(* $Id: DecLists.v,v 1.2 1999/10/05 10:35:34 boulme Exp $ *)
(* Properties and definitions on lists with a decidable relation *)

Set Implicit Arguments.
Unset Strict Implicit.
Require Export List.

Section DecLists.

Variable A : Set.
Variable R : A -> A -> Prop.
Hypothesis R_dec : forall x y : A, {R x y} + {~ R x y}.


Section DecAll.

Variable P : A -> list A -> Prop.
Hypothesis P_dec : forall (x : A) (l : list A), {P x l} + {~ P x l}.

Fixpoint AllD (l : list A) : Prop :=
  match l with
  | nil => True
  | a :: m => if P_dec a m then AllD m else False
  end.

Fixpoint ExD (l : list A) : Prop :=
  match l with
  | nil => False
  | a :: m => if P_dec a m then True else ExD m
  end.

Definition AllD_nil : AllD nil := I.

Definition AllD_cons :
  forall (a : A) (l : list A), P a l -> AllD l -> AllD (a :: l).
  intros a l H1 H2; simpl in |- *; case (P_dec a l); unfold not in |- *;
   simpl in |- *; auto.
Defined.


Definition ExD_hd : forall (a : A) (l : list A), P a l -> ExD (a :: l).
  intros a l H; simpl in |- *; case (P_dec a l); unfold not in |- *;
   simpl in |- *; auto.
  intros H'; elim (H' H).
Defined.

Definition ExD_tl : forall (a : A) (l : list A), ExD l -> ExD (a :: l).
  intros a l H; simpl in |- *; case (P_dec a l); simpl in |- *; auto.
Defined.

Hint Resolve AllD_cons ExD_hd ExD_tl: declists.  

Lemma AllD_dec : forall l : list A, {AllD l} + {~ AllD l}.
  intros l; elim l; simpl in |- *; auto.
  intros a l' H; case (P_dec a l'); simpl in |- *; auto.
Defined.

Lemma ExD_dec : forall l : list A, {ExD l} + {~ ExD l}.
  intros l; elim l; simpl in |- *; auto.
  intros a l' H; case (P_dec a l'); simpl in |- *; auto.
Defined.

Lemma AllD_cons_inv :
 forall (a : A) (l : list A), AllD (a :: l) -> P a l /\ AllD l.
Proof.
  simpl in |- *; intros a l; case (P_dec a l); simpl in |- *; auto;
   contradiction.
Qed.

Lemma ExD_cons_inv :
 forall (a : A) (l : list A), ExD (a :: l) -> P a l \/ ExD l.
Proof.
  simpl in |- *; intros a l; case (P_dec a l); simpl in |- *; auto.
Qed.

Hypothesis P_app_l : forall (x : A) (l m : list A), P x (l ++ m) -> P x l.

Lemma AllD_app_and : forall l m : list A, AllD (l ++ m) -> AllD l /\ AllD m.
Proof.
  intros l m; elim l.
  simpl in |- *; auto.
  intros a l' H H'; case (AllD_cons_inv H'); intros H1 H2; case (H H2);
   generalize (P_app_l H1); auto with declists.
Qed.

Lemma ExD_app_or : forall l m : list A, ExD (l ++ m) -> ExD l \/ ExD m.
Proof.
  intros l m; elim l.
  simpl in |- *; auto.
  intros a l' H H'; case (ExD_cons_inv H').
  intro H1; generalize (P_app_l H1); auto with declists.
  intros H1; case (H H1); auto with declists.
Qed.

Hypothesis P_l_app : forall (x : A) (l m : list A), P x l -> P x (l ++ m).

Lemma AllD_and_app : forall l m : list A, AllD l -> AllD m -> AllD (l ++ m).
Proof.
  intros l m; elim l.
  simpl in |- *; auto.
  intros a l' H H'; case (AllD_cons_inv H'); intros;
   change (AllD (a :: l' ++ m)) in |- *; auto with declists.
Qed.

Lemma ExD_or_app : forall l m : list A, ExD l \/ ExD m -> ExD (l ++ m).
Proof.
  intros l m; elim l.
  simpl in |- *; intro H; case H. contradiction. auto.
  intros a l' H H'; case H'; intros H''; change (ExD (a :: l' ++ m)) in |- *;
   auto with declists.
  case (ExD_cons_inv H''); auto with declists.
Qed.

End DecAll.

Hint Resolve AllD_nil AllD_cons AllD_app_and AllD_and_app ExD_hd ExD_tl:
  declists.  

Section DecAll2.

Variable P Q : A -> list A -> Prop.
Hypothesis P_dec : forall (x : A) (l : list A), {P x l} + {~ P x l}.
Hypothesis Q_dec : forall (x : A) (l : list A), {Q x l} + {~ Q x l}.

Lemma AllD_stable :
 (forall (x : A) (l : list A), P x l -> Q x l) ->
 forall l : list A, AllD P_dec l -> AllD Q_dec l.
Proof.
  intros H1 l; elim l; auto.
  intros a l' H H'; case (AllD_cons_inv H'); auto with declists.
Qed.

End DecAll2.


Section DecExD.

Variable P Q : A -> list A -> Prop.
Hypothesis P_dec : forall (x : A) (l : list A), {P x l} + {~ P x l}.

Definition notP (x : A) (l : list A) := ~ P x l.
Definition notP_dec : forall (x : A) (l : list A), {notP x l} + {~ notP x l}.
  intros x l; unfold notP in |- *; case (P_dec x l); auto.
Defined.

Definition nExD := AllD notP_dec.
 
Lemma not_nExD_ExD : forall l : list A, nExD l -> ExD P_dec l -> False.
Proof.
  intros l; elim l; simpl in |- *; auto.
  intros a l'; unfold notP_dec in |- *; case (P_dec a l'); simpl in |- *;
   auto.
Qed.

End DecExD.


Section InD.

Variable a : A.

Definition R_a (b : A) (l : list A) := R a b.

Definition R_a_dec : forall (x : A) (l : list A), {R_a x l} + {~ R_a x l}.
  intros x l; unfold R_a in |- *; case (R_dec a x); auto.
Defined.

Definition inD := ExD R_a_dec.

Definition inD_hd : forall (b : A) (l : list A), R a b -> inD (b :: l) :=
  ExD_hd R_a_dec.
Definition inD_tl : forall (b : A) (l : list A), inD l -> inD (b :: l) :=
  ExD_tl (P_dec:=R_a_dec).

Lemma inD_cons_inv :
 forall (b : A) (l : list A), inD (b :: l) -> R a b \/ inD l.
Proof ExD_cons_inv (P_dec:=R_a_dec). 

Definition inD_dec : forall l : list A, {inD l} + {~ inD l} :=
  ExD_dec R_a_dec.

Definition ninD := nExD R_a_dec.

Definition ninD_nil : ninD nil := AllD_nil (P:=notP R_a) (notP_dec R_a_dec).
Definition ninD_cons (b : A) (l : list A) (H1 : ~ R a b) 
  (H2 : ninD l) : ninD (b :: l) :=
  AllD_cons (P:=notP R_a) (P_dec:=notP_dec R_a_dec) H1 H2.

Lemma ninD_cons_inv :
 forall (b : A) (l : list A), ninD (b :: l) -> ~ R a b /\ ninD l.
Proof AllD_cons_inv (P:=notP R_a) (P_dec:=notP_dec R_a_dec). 

Lemma ninD_app_and : forall l m : list A, ninD (l ++ m) -> ninD l /\ ninD m.
  unfold ninD, nExD in |- *; auto with declists. 
Qed.

Lemma ninD_and_app : forall l m : list A, ninD l -> ninD m -> ninD (l ++ m).
  unfold ninD, nExD in |- *; auto with declists. 
Qed.

Definition ninD_dec : forall l : list A, {ninD l} + {~ ninD l} :=
  AllD_dec (P:=notP R_a) (notP_dec R_a_dec).

Lemma not_ninD_inD : forall l : list A, ninD l -> inD l -> False.
Proof not_nExD_ExD (P_dec:=R_a_dec).

End InD.
Hint Resolve inD_hd inD_tl ninD_nil ninD_cons ninD_app_and ninD_and_app:
  declists. 


Hypothesis R_refl : forall x : A, R x x.

Section AllD_InD_Props.

Variable P : A -> list A -> Prop.
Hypothesis P_dec : forall (x : A) (l : list A), {P x l} + {~ P x l}.
Hypothesis P_l_indep : forall (x : A) (l m : list A), P x l -> P x m.

Lemma inD_AllD :
 forall l : list A, (forall a : A, inD a l -> P a l) -> AllD P_dec l. 
Proof.
  intros l; elim l; eauto 15 with declists.
Qed.  

Hypothesis
  P_R_stable : forall (x y : A) (l : list A), P x l -> R y x -> P y l.

Lemma AllD_inD :
 forall l : list A, AllD P_dec l -> forall a : A, inD a l -> P a l. 
Proof.
  intros l; elim l.
  simpl in |- *; contradiction.
  intros a l' H1 H2 a' H4; case (AllD_cons_inv H2); case (inD_cons_inv H4);
   intros; apply P_l_indep with (l := l'); auto.
  apply P_R_stable with (x := a); auto.
Qed.  

End AllD_InD_Props.


Hypothesis R_trans : forall x y z : A, R x y -> R y z -> R x z.


Section Contains_Props.

Variable l : list A.

Lemma inD_R_stable : forall x y : A, inD x l -> R y x -> inD y l.
Proof.
  intros x y; elim l; auto with declists; intros a m H H0;
   case (inD_cons_inv H0); eauto with declists.  
Qed.

Let inD_l (a : A) (k : list A) := inD a l.

Let inD_l_dec : forall (a : A) (k : list A), {inD_l a k} + {~ inD_l a k}.
  unfold inD_l in |- *; intros a k; case (inD_dec a l); auto.
Defined.

Definition cont := AllD inD_l_dec.

Lemma cont_nil : cont nil.
Proof AllD_nil _.

Lemma cont_cons :
 forall (a : A) (m : list A), inD a l -> cont m -> cont (a :: m).
Proof AllD_cons (P_dec:=inD_l_dec).

Lemma incl_cont :
 forall m : list A, (forall a : A, inD a m -> inD a l) -> cont m.
Proof.
  intros m H; unfold cont in |- *; apply inD_AllD; auto.
Qed.

Lemma cont_incl :
 forall m : list A, cont m -> forall a : A, inD a m -> inD a l.
Proof.
  intros m H1 a H2; change (inD_l a m) in |- *;
   apply AllD_inD with (P_dec := inD_l_dec); auto.
  intro x; unfold inD_l in |- *; intros; apply inD_R_stable with (x := x);
   auto. 
Qed.

Lemma cont_refl : cont l.
Proof.
  apply incl_cont; auto.
Qed.
 
Lemma cont_cons_r_inD : forall (a : A) (m : list A), cont (a :: m) -> inD a l.
Proof.
  intros a m H; case (AllD_cons_inv H); auto.
Qed.

Lemma cont_tl_r : forall m : list A, cont m -> cont (tail m).
Proof.
  intros m; case m; simpl in |- *; auto.
  intros b m0 H; case (AllD_cons_inv H); auto.
Qed.

Lemma cont_incl2 :
 forall m : list A, cont m -> forall a : A, ninD a l -> ninD a m.
  intros m H a H'; unfold ninD, nExD in |- *;
   apply AllD_stable with (P_dec := inD_l_dec); auto.
  unfold inD_l, notP, R_a in |- *; intros x l' H0;
   change (notP (R_a a) x l) in |- *;
   apply AllD_inD with (P_dec := notP_dec (R_a_dec a)); 
   auto.
  unfold notP, R_a, not in |- *; intros x0 y l0 H1 H2 H3; apply H1;
   exact (R_trans H3 H2).
Qed.

End Contains_Props.

Lemma cont_tl_l : forall l m : list A, cont (tail l) m -> cont l m.
  intros l m H; apply incl_cont; intros a H1; generalize (cont_incl H H1);
   case l; auto with declists.
Qed.

Lemma cont_trans : forall l m n : list A, cont l m -> cont m n -> cont l n.
  intros l m n H1 H2; apply incl_cont; intros a H;
   generalize (cont_incl H1 (a:=a)) (cont_incl H2 (a:=a)); 
   auto.
Qed.


Section Disjoints_Props.

Variable l : list A.

Lemma ninD_R_stable : forall a b : A, ninD a l -> R a b -> ninD b l.
  unfold ninD, nExD in |- *; intros a b H H0;
   apply AllD_stable with (P_dec := notP_dec (R_a_dec a)); 
   auto.
  unfold notP, R_a, not in |- *; intros x l0 H1 H2; apply H1;
   apply R_trans with (y := b); auto.
Qed.

Let ninD_l (a : A) (k : list A) := ninD a l.

Let ninD_l_dec : forall (a : A) (k : list A), {ninD_l a k} + {~ ninD_l a k}.
  unfold ninD_l in |- *; intros a k; case (ninD_dec a l); auto.
Defined.

Definition disj := AllD ninD_l_dec.

Lemma disj_nil : disj nil.
Proof AllD_nil _.

Lemma disj_cons :
 forall (a : A) (m : list A), ninD a l -> disj m -> disj (a :: m).
Proof AllD_cons (P_dec:=ninD_l_dec).

Lemma disj_unzip :
 forall m : list A, (forall a : A, inD a m -> ninD a l) -> disj m.
Proof.
  intros m H; unfold disj in |- *; apply inD_AllD; auto.
Qed.

Lemma disj_cons_r_ninD :
 forall (a : A) (m : list A), disj (a :: m) -> ninD a l.
Proof.
  intros a m H; case (AllD_cons_inv H); auto.
Qed.

Lemma disj_tl_r : forall m : list A, disj m -> disj (tail m).
Proof.
  intros m; case m; simpl in |- *; auto.
  intros b m0 H; case (AllD_cons_inv H); auto.
Qed.

Lemma disj_app_and : forall m r : list A, disj (m ++ r) -> disj m /\ disj r.
  unfold disj, ninD_l in |- *; auto with declists.
Qed.

Lemma disj_and_app : forall m r : list A, disj m -> disj r -> disj (m ++ r).
  unfold disj, ninD_l in |- *; auto with declists.
Qed.

End Disjoints_Props.

Hint Resolve disj_nil disj_cons: declists.


Definition df := AllD ninD_dec.

Lemma df_nil : df nil.
Proof AllD_nil _.

Lemma df_cons : forall (a : A) (l : list A), ninD a l -> df l -> df (a :: l).
Proof AllD_cons (P_dec:=ninD_dec).

Hint Resolve df_nil df_cons: declists.

Lemma df_cons_inv :
 forall (a : A) (l : list A), df (a :: l) -> ninD a l /\ df l.
Proof AllD_cons_inv (P_dec:=ninD_dec).

Lemma df_app_disj : forall l m : list A, df (l ++ m) -> disj m l.
  intros l m; elim l.
    simpl in |- *; auto.
    intros a l' HR H; case (df_cons_inv H); intros H1 H0;
     case (ninD_app_and H1); auto with declists.
Qed.

Lemma df_disj_app :
 forall l m : list A, df l -> df m -> disj m l -> df (l ++ m).
Proof.
  intros l m; elim l; auto.
  intros a l0 HR H1 H2 H3; case (df_cons_inv H1);
   generalize (disj_cons_r_ninD H3); generalize (disj_tl_r H3); 
   simpl in |- *; intros; change (df (a :: l0 ++ m)) in |- *;
   auto with declists.
Qed.


Hypothesis R_sym : forall x y : A, R x y -> R y x.

Lemma disj_sym : forall l m : list A, disj l m -> disj m l.
Proof.
  intros l m H; apply disj_unzip; generalize H; elim m.
  simpl in |- *; auto.
  clear H m; intros a m H1 H2; generalize (disj_cons_r_ninD H2);
   generalize (disj_tl_r H2); intros H3 H4 b H5; apply ninD_cons; 
   auto.
  unfold not in |- *; intros; lapply (not_ninD_inD (a:=b) (l:=l)); auto;
   apply ninD_R_stable with (a := a); auto. 
Qed.

End DecLists.

Hint Resolve inD_hd inD_tl ninD_nil ninD_cons: declists. 
Hint Resolve cont_nil cont_cons cont_tl_l: declists.
Hint Resolve df_nil df_cons: declists.









