Library quicksort
Require Import List.
Require Import Recdef.
Require Import Omega.
Chapter QuickSort.
Variable A : Type.
Variable A_eq_dec : forall a b : A, {a = b}+{~a = b}.
Variable Order : A -> A -> Prop.
Hypothesis order_antisym : forall a b : A, Order a b -> Order b a -> a = b.
Hypothesis order_trans : forall a b c : A, Order a b -> Order b c -> Order a c.
Hypothesis order_dec : forall x y : A, {Order x y}+{~Order x y}.
Hypothesis order_total : forall a b : A, {Order a b}+{Order b a}.
Lemma order_refl :
forall (a : A), Order a a.
Proof.
intro;assert ({Order a a}+{Order a a}).
apply order_total.
destruct H;assumption.
Qed.
Lemma not_order_order :
forall a b : A, ~Order a b -> Order b a.
Proof.
intros;destruct (order_total a b);[absurd(Order a b) | ];assumption.
Qed.
Fixpoint partition (p : A) (l : list A) {struct l}: (list A)*(list A) :=
match l with
| nil => (nil,nil)
| h :: t => let (less,more) := partition p t in
match order_dec h p with
| left _ => (h :: less, more)
| right _ => (less, h :: more)
end
end.
Functional Scheme partition_ind := Induction for partition Sort Prop.
Lemma partition_le :
forall (l : list A) (p : A) (x : A), In x (fst(partition p l)) -> (Order x p).
Proof.
intros l p.
functional induction partition p l;simpl;intros.
intuition.
decompose [or] H; [rewrite <- H0 | apply IHp0; rewrite e0];
assumption.
apply IHp0; rewrite e0; assumption.
Qed.
Lemma partition_gt :
forall (l : list A) (p : A) (x : A), In x (snd(partition p l)) -> (~Order x p).
Proof.
intros l p.
functional induction partition p l;simpl;intros.
intuition.
apply IHp0;rewrite e0;assumption.
decompose [or] H;[rewrite <- H0 | apply IHp0; rewrite e0];
assumption.
Qed.
Lemma partition_length_l :
forall (l : list A) (p : A), length (fst(partition p l)) <= length l.
Proof.
intros;functional induction partition p l;
auto; try auto; simpl; rewrite e0 in IHp0;
[ apply le_n_S | apply lt_le_weak; apply le_lt_n_Sm ];
assumption.
Qed.
Lemma partition_length_r :
forall (l : list A) (p : A), length (snd(partition p l)) <= length l.
Proof.
intros;functional induction partition p l;
try auto; simpl; rewrite e0 in IHp0;
[ apply lt_le_weak; apply le_lt_n_Sm | apply le_n_S ];
assumption.
Qed.
Lemma permutation_partition:
forall (l : list A) (p : A), Permutation l (fst(partition p l)++snd(partition p l)).
Proof.
intros;functional induction partition p l;
simpl; try rewrite e0 in IHp0;
first [constructor | apply Permutation_cons_app];
assumption.
Qed.
Inductive is_sorted : list A -> Prop :=
| is_sorted_nil : is_sorted nil
| is_sorted_singleton : forall x : A, is_sorted (x :: nil)
| is_sorted_cons: forall (l : list A) (x y : A),
(Order x y) -> is_sorted (y :: l) -> is_sorted (x :: y :: l).
Lemma is_sorted_add_hd : forall (l : list A) (a : A),
is_sorted l ->
(forall b : A,
In b l -> (Order a b))
-> is_sorted (a :: l).
Proof.
induction l;intros.
constructor.
apply is_sorted_cons;[apply H0|];intuition.
Qed.
Lemma is_sorted_tail :
forall (l : list A) (a : A), is_sorted (a :: l) -> is_sorted l.
Proof.
induction l; intros;
[constructor | inversion H; assumption ].
Qed.
Lemma is_sorted_head_min :
forall (l : list A) (a : A), is_sorted(a :: l)
-> (forall b : A, In b l -> (Order a b)).
Proof.
induction l;intros.
inversion H0.
simpl in H0;decompose [or] H0;inversion H.
subst;assumption.
eapply order_trans;[eassumption|apply IHl;intuition].
Qed.
Lemma is_sorted_cat :
forall (l l':list A), is_sorted l -> is_sorted l' ->
(forall (x y: A), In x l -> In y l' ->
(Order x y)) -> is_sorted (l ++ l').
Proof.
induction l;intros.
assumption.
simpl; apply is_sorted_add_hd.
apply IHl.
eapply is_sorted_tail; eassumption.
assumption.
intros;apply H1;intuition.
intros;assert (In b l \/ In b l').
apply in_app_or; assumption.
decompose [or] H3.
apply (is_sorted_head_min l); assumption.
apply H1; [ simpl; left; reflexivity | assumption ].
Qed.
Lemma is_sorted_rmsnd :
forall (l : list A) (x y : A),
is_sorted (x :: y :: l)
-> is_sorted (x :: l).
Proof.
intros;inversion H;inversion H4;
subst;constructor.
eapply order_trans;eassumption.
assumption.
Qed.
Lemma NoDup_rmsnd :
forall (l : list A) (x y : A),
NoDup (x :: y :: l)
-> NoDup (x :: l).
Proof.
intros;constructor;inversion H;inversion H3;intuition.
Qed.
Function quicksort (l : list A) {measure length l}: list A :=
match l with
| nil => nil
| h::t => let (less,more) := partition h t in
quicksort(less) ++ h::quicksort(more)
end.
Proof.
intros; replace (more) with (snd(partition h t));
[ simpl; apply le_lt_n_Sm; apply partition_length_r
| rewrite teq0 ; reflexivity ].
intros; replace less with (fst(partition h t));
[ simpl; apply le_lt_n_Sm; apply partition_length_l
| rewrite teq0; reflexivity ].
Qed.
Theorem permutation_quicksort:
forall l:list A,
Permutation l (quicksort l).
Proof.
intro;functional induction (quicksort l).
constructor.
apply Permutation_cons_app.
eapply Permutation_trans.
apply permutation_partition.
instantiate (1:=h).
rewrite e0; simpl.
apply Permutation_app; assumption.
Qed.
Lemma quicksort_in :
forall (l : list A) (a : A), In a (quicksort l) -> In a l.
Proof.
intros;eapply Permutation_in;
[ apply Permutation_sym; apply permutation_quicksort
| assumption ].
Qed.
Theorem is_sorted_quicksort: forall l:list A, is_sorted(quicksort l).
Proof.
intro;functional induction quicksort l.
constructor.
apply is_sorted_cat.
assumption.
apply is_sorted_add_hd.
assumption.
intros;apply not_order_order.
apply partition_gt with (l:=t).
rewrite e0;apply quicksort_in;assumption.
intros;cut (Order x h /\ Order h y).
intro.
decompose [and] H1.
eapply order_trans; eassumption.
split.
apply (partition_le t);rewrite e0;
apply quicksort_in;assumption.
simpl in H0;decompose [or] H0.
rewrite H1;apply order_refl.
assert (In y more).
apply quicksort_in;assumption.
apply not_order_order.
apply partition_gt with (l:=t).
rewrite e0;assumption.
Qed.
Fixpoint elim_dup (l : list A) {struct l}: list A :=
match l with
nil => nil
| x :: l' => match l' with
| nil => l
| y :: l'' => match (A_eq_dec x y) with
|left _ => elim_dup l'
|right _ => x :: elim_dup l'
end
end
end.
Lemma in_elim_dup_aux :
forall (l : list A) (a x : A),
In x (elim_dup (a :: l))
-> a <> x
-> In x (elim_dup l).
Proof.
intros.
simpl in H;decompose[or] H;intuition.
destruct l;[|destruct (A_eq_dec a a0);[assumption|]];
simpl in H;decompose[or] H;intuition.
Qed.
Lemma in_elim_dup : forall (l : list A) (x : A),
In x (elim_dup l)
-> In x l.
Proof.
induction l;intros;simpl.
inversion H.
destruct (A_eq_dec a x).
left;assumption.
right;apply IHl;eapply in_elim_dup_aux;eassumption.
Qed.
Lemma in_dup_aux :
forall (l : list A) (x : A),
In x (elim_dup (x :: l)).
Proof.
induction l;intros;simpl.
intuition.
destruct (A_eq_dec x a).
rewrite e;apply IHl.
intuition.
Qed.
Lemma in_dup :
forall (l : list A) (x : A),
In x l
-> In x (elim_dup l).
Proof.
induction l;intros.
assumption.
simpl in H;decompose [or] H.
subst;apply in_dup_aux.
simpl;destruct l.
inversion H0.
destruct (A_eq_dec a a0).
apply IHl;assumption.
simpl;right;apply IHl;assumption.
Qed.
Lemma NoDup_elim_dup : forall (l : list A),
is_sorted l
-> NoDup (elim_dup l).
Proof.
induction l;intros.
simpl;constructor.
simpl;destruct l.
constructor;[intuition | constructor].
destruct (A_eq_dec a a0).
apply IHl.
eapply is_sorted_tail;eassumption.
constructor.
unfold not;intro.
assert (In a (a0 :: l)).
apply in_elim_dup;assumption.
simpl in H1;decompose[or]H1.
subst;intuition.
inversion H;subst.
assert (a = a0).
apply order_antisym.
assumption.
eapply is_sorted_head_min;eassumption.
subst;intuition.
apply IHl;inversion H;assumption.
Qed.
Lemma sort_elim_dup :
forall (l : list A),
is_sorted l
-> is_sorted (elim_dup l).
Proof.
induction l;intros.
assumption.
simpl;destruct l.
assumption.
destruct (A_eq_dec a a0).
apply IHl;eapply is_sorted_tail;eassumption.
apply is_sorted_add_hd.
apply IHl;eapply is_sorted_tail;eassumption.
intros;eapply is_sorted_head_min.
eassumption.
apply in_elim_dup;assumption.
Qed.
End QuickSort.