Section Frequency.
Variable A : Type.
Variable eqA_dec : forall a b : A, {a = b} + {a <> b}.
(* Create a list of a given length with a given element  *)
Fixpoint id_list (a : A) (n : nat) {struct n} : list A :=
match n with
| O => nil
| S n1 => a :: id_list a n1
end.
(* An element in a frequency list *)
Fixpoint add_frequency_list (a : A) (l : list (A * nat)) {struct l} :
list (A * nat) :=
match l with
| nil => (a, 1) :: nil
| (b, n) :: l1 =>
match eqA_dec a b with
| left _ => (a, S n) :: l1
| right _ => (b, n) :: add_frequency_list a l1
end
end.
Proof using.
intros a l; generalize a; elim l; simpl in |- *; clear a l; auto.
intros (a, n) l H b.
case (eqA_dec b a); auto.
intros e; simpl in |- *; rewrite e; auto.
simpl in |- *.
intros e;
apply
permutation_trans
with
(id_list a n ++
(b :: nil) ++ flat_map (fun p => id_list (fst p) (snd p)) l);
[ idtac | simpl in |- *; auto ].
change
(permutation
((b :: nil) ++
id_list a n ++ flat_map (fun p => id_list (fst p) (snd p)) l)
(id_list a n ++
(b :: nil) ++ flat_map (fun p => id_list (fst p) (snd p)) l))
in |- *.
repeat rewrite <- app_ass; auto.
Qed.
Proof using.
intros a1 a2 b1 l; elim l; simpl in |- *; auto.
intros [H1| H1]; auto; injection H1; auto.
intros (a3, b3) l1 Rec; simpl in |- *; auto.
case (eqA_dec a2 a3); simpl in |- *; auto.
intros e H; cut (In (a1, b1) ((a2, S b3) :: l1)); auto.
simpl in |- *; intros [H1| H1]; auto.
injection H1; auto.
intuition.
Qed.
Proof using.
intros a l; elim l; simpl in |- *; auto.
intros (a1, n1) l1 Rec H; case (eqA_dec a a1).
intros e; apply unique_key_perm with (l1 := (a, S n1) :: l1); auto.
apply unique_key_cons; auto.
intros b; red in |- *; intros H0; case (unique_key_in _ _ _ _ b _ H); auto.
rewrite <- e; auto.
apply unique_key_inv with (1 := H); auto.
intros n; apply unique_key_cons; auto.
intros b; red in |- *; intros H0;
case add_frequency_list_in_inv with (1 := H0); auto.
intros H2; case (unique_key_in _ _ _ _ b _ H); auto.
apply Rec; apply unique_key_inv with (1 := H); auto.
Qed.
Proof using.
intros a l; generalize a; elim l; clear a l; simpl in |- *; auto.
intros (a1, l1) l0 H a H0.
case (eqA_dec a a1); auto.
intros H1; case (H0 l1); left;
apply f_equal2 with (f := pair (A:=A) (B:=nat)); auto.
intros n; apply in_cons; auto; apply H; auto.
intros ca; red in |- *; intros H1; case (H0 ca); auto.
Qed.
Proof using.
intros m; elim m; clear m; simpl in |- *; auto.
intros (a1, l1) l Rec a n H H1; case (eqA_dec a a1); simpl in |- *; auto.
intros H2; case H1; auto.
intros H3; left; apply f_equal2 with (f := pair (A:=A) (B:=nat));
injection H3; auto.
rewrite H2; intros H3; case unique_key_in with (1 := H) (b2 := n); auto.
intros n0; right; apply Rec.
apply unique_key_inv with (1 := H); auto.
case H1; auto.
intros H0; case n0; injection H0; auto.
Qed.
Proof using.
intros m; elim m; clear m; simpl in |- *; auto.
intros (a1, l1) l H a0 b n H0 [H1| H1]; case (eqA_dec b a1); simpl in |- *;
auto.
intros H2; case H0; injection H1; auto.
intros; apply trans_equal with (2 := sym_equal H2); auto.
Qed.
(* Create a frequency list from a message *)
Fixpoint frequency_list (l : list A) : list (A * nat) :=
match l with
| nil => nil
| a :: l1 => add_frequency_list a (frequency_list l1)
end.
Proof using.
intros a n m; generalize n; elim m; clear m n; simpl in |- *; auto.
intros a0 l H n H0; case add_frequency_list_in_inv with (1 := H0); auto.
intros H1; right; apply (H n); auto.
Qed.

(* Developing the frequency list gives a permutation of the initial message *)
Theorem frequency_list_perm :
forall l : list A,
permutation l
(flat_map (fun p => id_list (fst p) (snd p)) (frequency_list l)).