Section OneStep.
Variable A : Type.
Variable f : A -> nat.
(* A step is valid if the two smallest elements of the initial list have been merged *)
Definition one_step (l1 l2 : list (btree A)) : Prop :=
exists l3 : list (btree A),
(exists t1 : btree A,
(exists t2 : btree A,
ordered (sum_order f) (t1 :: t2 :: l3) /\
permutation l1 (t1 :: t2 :: l3) /\
permutation l2 (node t1 t2 :: l3))).
Proof using.
intros l1 l2 l3 (l4, (t1, (t2, (H1, (H2, H3)))))
(l5, (t3, (t4, (H4, (H5, H6))))).
rewrite weight_tree_list_permutation with (1 := H3).
rewrite weight_tree_list_permutation with (1 := H6).
repeat rewrite weight_tree_list_node.
apply f_equal2 with (f := plus).
cut
(map (sum_leaves f) (t1 :: t2 :: l4) = map (sum_leaves f) (t3 :: t4 :: l5)).
simpl in |- *; intros H7; injection H7.
intros H8 H9 H10; repeat apply f_equal2 with (f := plus); auto.
apply ordered_sum_leaves_eq; auto.
apply permutation_trans with (2 := H5); auto.
apply permutation_sym; auto.
rewrite <- weight_tree_list_permutation with (1 := H2).
apply weight_tree_list_permutation; auto.
Qed.
intros l1 l2 l3 (l4, (t1, (t2, (H1, (H2, H3)))))
(l5, (t3, (t4, (H4, (H5, H6))))).
Proof using.
red in |- *.
exists (node t1 t2 :: l4); exists (node t3 t4 :: l5); auto; simpl in |- *;
auto.
split; auto; split; auto.
cut
(map (sum_leaves f) (t1 :: t2 :: l4) = map (sum_leaves f) (t3 :: t4 :: l5)).
simpl in |- *; intros H7; injection H7; intros H8 H9 H10;
apply f_equal2 with (f := cons (A:=nat)); auto.
apply ordered_sum_leaves_eq; auto.
apply permutation_trans with (2 := H5); auto.
apply permutation_sym; auto.
Qed.

(* Choosing one step or another does not change weight and sum leaves *)
Theorem one_step_comp :
forall l1 l2 l3 l4 : list (btree A),
weight_tree_list f l1 = weight_tree_list f l2 ->
same_sum_leaves f l1 l2 ->
one_step l1 l3 ->
one_step l2 l4 ->
weight_tree_list f l3 = weight_tree_list f l4 /\ same_sum_leaves f l3 l4.