(* Copyright (C) 2005-2008 Sebastien Briais *)
(* http://lamp.epfl.ch/~sbriais/ *)
(* This library is free software; you can redistribute it and/or modify *)
(* it under the terms of the GNU Lesser General Public License as *)
(* published by the Free Software Foundation; either version 2.1 of the *)
(* License, or (at your option) any later version. *)
(* This library is distributed in the hope that it will be useful, but *)
(* WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *)
(* Lesser General Public License for more details. *)
(* You should have received a copy of the GNU Lesser General Public *)
(* License along with this library; if not, write to the Free Software *)
(* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *)
(* 02110-1301 USA *)
Require Export List Permutation.
(** we define some notions on lists such as being a permutation of *)
(** insertion x l l' iff l' is l where x has been inserted somewhere *)
Inductive insertion (A:Set) : A -> list A -> list A -> Prop :=
head_insertion : forall (x:A)(l:list A),(insertion A x l (x::l))
|tail_insertion : forall (x y:A)(l l':list A),(insertion A x l l')->(insertion A x (y::l) (y::l')).
induction xs.
simpl.
apply head_insertion.
simpl.
apply tail_insertion.
auto.
Qed.
intros.
induction H;simpl;tauto.
Qed.
induction l;simpl;try tauto;intros.
inversion H;simpl;try tauto.
case H0;try tauto.
right;auto.
Qed.
induction l;simpl;try tauto;intros.
case H;intro.
rewrite H0;exists l;apply head_insertion.
elim (IHl H0);intro l';intro.
exists (a::l');apply tail_insertion;trivial.
Qed.
intros.
induction H;simpl in H0.
case H0;intro H1;try (symmetry in H1);tauto.
case H0;simpl;intro;tauto.
Qed.
(** a list is a set iff all the elements are pairwise distinct *)
Inductive is_set (A:Set) : list A->Prop :=
nil_is_set : (is_set A nil)
|cons_is_set : forall (x:A)(l:list A),(is_set A l)->~(In x l)->(is_set A (x::l)).
induction 1;intros.
inversion H;trivial.
inversion H0.
apply cons_is_set.
apply IHinsertion;trivial.
intro;apply H4;apply (insertion_inclusion A x l l');trivial.
Qed.
induction l;simpl;try tauto;intros.
inversion H;rewrite <- H3 in H0;inversion H0.
simpl in H7;trivial.
intro.
case H10;intro.
apply H9;rewrite H11;eapply insertion_in;apply H5.
elim (IHl l'0 x H5 H8 H11).
Qed.
induction 1.
intros.
inversion H0.
apply cons_is_set.
apply nil_is_set.
auto.
intros.
inversion H2.
subst x1.
subst l0.
subst l'.
apply cons_is_set.
eapply IHis_set.
apply H0.
apply head_insertion.
auto.
subst x1;subst y;subst l0.
apply cons_is_set.
eapply IHis_set with x0;auto.
red;intro.
apply H1.
simpl.
right;auto.
red;intro.
case (in_insertion_inv _ _ _ _ _ H7 H3);intro.
apply H1.
simpl.
left;auto.
apply H0.
auto.
Qed.
(** l' is a permutation of l *)
Inductive is_permutation (A:Set) : list A->list A->Prop :=
nil_is_permutation : (is_permutation A nil nil)
|cons_is_permutation : forall (l l':list A),(is_permutation A l l')->forall (x:A)(l'':(list A)),(insertion A x l' l'')->(is_permutation A (x::l) l'').
induction l;intros;simpl in H.
destruct l'.
apply nil_is_permutation.
elim (H a);intros.
elim H3;simpl;tauto.
inversion H0.
symmetry in H2;rewrite H2 in H;elim (H a);intros.
rewrite H2 in H6;rewrite H2.
assert (In x l');auto.
elim (in_insertion A x l' H8).
intro l'';intro.
apply cons_is_permutation with l'';trivial.
apply IHl;trivial.
split;intro.
elim (H x0);intros.
elim (in_insertion_inv A x0 x l'' l');auto.
intro;rewrite H13 in H10;rewrite H2 in H5;tauto.
elim (H x0);intros.
case H12;try tauto.
apply (insertion_inclusion A x l'' l');trivial.
intro;rewrite <- H13 in H10.
elim (is_set_insertion_in A l'' l' x);trivial.
eapply is_set_insertion;eauto.
Qed.
induction l.
apply nil_is_permutation.
eapply cons_is_permutation;[apply IHl | apply head_insertion].
Qed.
induction 1.
apply cons_is_permutation with l;[apply is_permutation_refl | apply head_insertion].
apply cons_is_permutation with (y::l);[apply is_permutation_refl | apply tail_insertion;trivial].
Qed.
induction 1;intros.
inversion H.
exists (y::l);split;[apply head_insertion | apply tail_insertion;apply head_insertion].
exists l';split;[trivial | apply head_insertion].
inversion H0.
exists (y0::y::l);split;[apply head_insertion | apply tail_insertion;apply tail_insertion;trivial].
elim (IHinsertion l'0 y0 H5);intro l3;intro.
elim H6;intros.
exists (y::l3);split;[apply tail_insertion | apply tail_insertion];trivial.
Qed.
induction 1;intros.
inversion H;inversion H0;apply is_permutation_refl.
inversion H1.
apply cons_is_permutation with l'';trivial.
apply cons_is_permutation with l';trivial.
elim (insertion_trans A l' l'' x H0 l3 x0 H2).
intro l4;intro.
elim H8;intros.
apply cons_is_permutation with l4;trivial.
eapply IHis_permutation;eauto.
Qed.
induction 1;[apply nil_is_permutation | eapply permutation_insertion;eauto;apply head_insertion].
Qed.
induction l;simpl;intros.
inversion H;simpl;tauto.
inversion H;simpl.
split;intro.
case H5;intro.
eapply insertion_in;rewrite H6 in H4;apply H4.
elim (IHl l'0 H2 x);intros.
eapply insertion_inclusion;eauto.
case (in_insertion_inv A x a l'0 l' H4 H5);intro.
rewrite H6;tauto.
elim (IHl l'0 H2 x);intros.
right;auto.
Qed.
intros.
eapply permutation_insertion;eauto.
apply is_permutation_refl.
Qed.
intros.
apply (well_founded_ind (well_founded_ltof (list A) (fun l:list A => length l)));unfold ltof;auto.
Qed.
induction 1;simpl;trivial.
rewrite IHinsertion;trivial.
Qed.
induction 1;simpl;trivial.
generalize (insertion_length A l' l'' x H0);intro;congruence.
Qed.
induction l;intros;inversion H.
inversion H0.
apply is_permutation_refl.
rewrite <- H4;destruct l.
inversion H8.
generalize (head_insertion A a0 l);intro.
assert (In x (a0::l)).
eapply insertion_in;apply H8.
case (in_insertion_inv A x a0 l (a0::l) H10 H11);intro.
rewrite H12;rewrite <- H12 in H10;rewrite <- H12 in H8;rewrite <- H12 in IHl.
assert (is_permutation A l l1).
eapply IHl;eauto.
eapply cons_is_permutation;eauto;apply head_insertion.
elim (in_insertion A x l H12);intro l2;intro.
generalize (tail_insertion A x a0 l2 l H13);intro.
assert (is_permutation A (a0::l2) l1).
eapply IHl;eauto.
apply is_permutation_sym;auto.
eapply cons_is_permutation;eauto.
rewrite H1 in H3.
inversion H0.
rewrite <- H9;apply insertion_is_permutation;trivial.
assert (is_permutation A l0 l1).
eapply IHl;eauto.
eapply cons_is_permutation;eauto;apply head_insertion.
Qed.

Lemma permutation_insertion_comm : forall (A:Set)(l1 l2:list A)(x:A),(insertion A x l1 l2)->forall (l4:list A),(is_permutation A l2 l4)->(exists l3:list A,(is_permutation A l1 l3) /\ (insertion A x l3 l4)).