Require Import Base.
Implicit Types A N : list nat.
Inductive sorted : list nat -> Prop :=
| sortedN : sorted nil
| sortedC x A : (forall z, z el A -> x < z) -> sorted A -> sorted (x::A).
Definition sep (A B : list nat) : Prop :=
exists x, x el A /\ x nel B \/ x nel A /\ x el B.
Lemma sorted_sep A B :
sorted A -> sorted B -> A <> B -> sep A B.
Proof.
intros H. revert B.
induction H as [ |x A H1 _ IH]; intros B H2 H3.
- destruct B as [|x B]. congruence. exists x. auto.
- destruct H2 as [ |y B H5 H6].
+ exists x. auto.
+ assert (x<y \/ y<x \/ x=y) as [H7|[H7|<-]] by omega.
* exists x. left. split. now auto. intros [<-|H8%H5]; omega.
* exists y. right. split; [|now auto]. intros [->|H8%H1]; omega.
* destruct (IH B H6) as [y [[H7 H8]|[H7 H8]]].
-- congruence.
-- exists y. left. split. now auto.
apply H1 in H7. contradict H8.
destruct H8 as [<-|H8]. omega. exact H8.
-- exists y. right. split; [|now auto].
apply H5 in H8. contradict H7.
destruct H7 as [->|H7]. omega. exact H7.
Qed.
Fact sorted_unique A B :
sorted A -> sorted B -> A === B <-> A = B.
Proof.
intros H1 H2. split.
- intros H3. contra_dec H4.
destruct (sorted_sep H1 H2 H4) as [x [[H5 H6]|[H5 H6]]].
+ apply H3 in H5. auto.
+ apply H3 in H6. auto.
- intros <-. reflexivity.
Qed.
Fixpoint insert x A : list nat :=
match A with
| nil => [x]
| y::A' => if Dec (x<y) then x::y::A'
else if Dec (x=y) then y::A' else y::insert x A'
end.
Fixpoint sort A : list nat :=
match A with
| nil => nil
| x::A' => insert x (sort A')
end.
Lemma insert_equiv x A :
insert x A === x :: A.
Proof.
induction A as [|y A IH]; cbn.
- reflexivity.
- decide (x < y) as [D|D]. reflexivity.
decide (x = y) as [<-|E]. now auto.
rewrite IH. apply equi_swap.
Qed.
Lemma sort_equiv A :
sort A === A.
Proof.
induction A as [|x A IH]; cbn.
- reflexivity.
- now rewrite insert_equiv, IH.
Qed.
Lemma sorted_cons x y A :
x < y -> sorted (y::A) -> sorted (x::y::A).
Proof.
intros H1 H2. constructor.
- intros z [->|H3]. exact H1.
enough (y<z) by omega.
inv H2; auto.
- constructor; inv H2; auto.
Qed.
Lemma insert_sorted x A :
sorted A -> sorted (insert x A).
Proof.
induction 1 as [ |y A H1 H IH]; cbn.
- auto using sorted.
- decide (x < y) as [H2|H2].
+ apply sorted_cons; auto using sorted.
+ decide (x = y) as [<-|H3]. now auto using sorted.
constructor; [|exact IH].
intros z [->|H4] % insert_equiv. omega. auto.
Qed.
Lemma sort_sorted A :
sorted (sort A).
Proof.
induction A as [|x A IH]; cbn.
- constructor.
- apply insert_sorted, IH.
Qed.
Theorem sort_normalizer A B :
A === B <-> sort A = sort B.
Proof.
rewrite <-sorted_unique.
- now rewrite !sort_equiv.
- apply sort_sorted.
- apply sort_sorted.
Qed.
Fact equiv_sep A B :
A === B <-> ~ sep A B.
Proof.
split.
- intros H1 [x [[H2 H3]|[H2 H3]]]; firstorder.
- intros H1. split; intros x H2; contra_dec H3; apply H1; exists x; auto.
Qed.
Fact sorted_sort_fp A :
sorted A <-> sort A = A.
Proof.
split; intros H.
- apply sorted_unique.
+ apply sort_sorted.
+ exact H.
+ apply sort_equiv.
- rewrite <-H. apply sort_sorted.
Qed.
Fact sorted_dec A :
dec (sorted A).
Proof.
apply dec_transfer with (P:= sort A = A).
- symmetry. apply sorted_sort_fp.
- auto.
Qed.
Fact sort_idempotent A :
sort (sort A) = sort A.
Proof.
apply sorted_sort_fp.
apply sort_sorted.
Qed.