Definition recompose (tt : (canonTree*canonTree)): canonTree :=
let (t1, t2) := tt in
let (x1, c1) := t1 in
let (x2, c2) := t2 in
match x1 as s return (canonicalTree s -> canonTree) with
| Leaf b1 =>
fun c3 : canonicalTree (Leaf b1) =>
match x2 as s return (canonicalTree s -> canonTree) with
| Leaf b2 =>
fun c4 : canonicalTree (Leaf b2) =>
match bool_dec b1 b2 with
| left e =>
let H :=
eq_rec b1
(fun b3 : bool => canonicalTree (Leaf b3) -> canonTree)
(fun _ : canonicalTree (Leaf b1) =>
exist (fun t : ShareTree => canonicalTree t) (Leaf b1) c3)
b2 e in
H c4
| right n =>
exist (fun t : ShareTree => canonicalTree t)
(Node (Leaf b1) (Leaf b2)) (compose_canon1 b1 b2 n c3 c4)
end
| Node x21 x22 =>
fun c4 : canonicalTree (Node x21 x22) =>
exist (fun t : ShareTree => canonicalTree t)
(Node (Leaf b1) (Node x21 x22)) (compose_canon2 b1 x21 x22 c3 c4)
end c2
| Node x11 x12 =>
fun c3 : canonicalTree (Node x11 x12) =>
match x2 as s return (canonicalTree s -> canonTree) with
| Leaf b2 =>
fun c4 : canonicalTree (Leaf b2) =>
exist (fun t : ShareTree => canonicalTree t)
(Node (Node x11 x12) (Leaf b2)) (compose_canon3 x11 x12 b2 c3 c4)
| Node x21 x22 =>
fun c4 : canonicalTree (Node x21 x22) =>
exist (fun t : ShareTree => canonicalTree t)
(Node (Node x11 x12) (Node x21 x22))
(compose_canon4 x11 x12 x21 x22 c3 c4)
end c2
end c1.
(*End Definition*)

(* Specifications: *)
Lemma tree_height_diff : forall t1 t2, height t1 <> height t2 -> t1 <> t2.
Lemma fullTreeP_subL : forall n t1 t2, fullTreeP (Node t1 t2) (S n) -> fullTreeP t1 n.
Lemma fullTreeP_subR : forall n t1 t2, fullTreeP (Node t1 t2) (S n) -> fullTreeP t2 n.
Lemma fullTreeP_height : forall n t, fullTreeP t n -> tree_heightP t = n.
Lemma fullTreeP_combine : forall t1 t2 n, fullTreeP t1 n -> fullTreeP t2 n ->
fullTreeP (Node t1 t2) (S n).
Lemma fullTree_double : forall t, fullTree t -> fullTree (Node t t).
Lemma fullTree_sub : forall t1 t2, fullTree (Node t1 t2) <->
(fullTree t1 /\ fullTree t2 /\ tree_heightP t1 = tree_heightP t2).
Lemma mkFull_height : forall n t t', mkFull n t = Some t' -> tree_heightP t' = n.
Lemma mkFull_correct : forall n t t', mkFull n t = Some t' -> fullTree t'.
Lemma mkFull_mkCanon : forall n t t', mkFull n t = Some t' ->
mkCanon t = mkCanon t'.
Lemma mkFull_split : forall n t1 t2 t1' t2',
mkFull (S n) (Node t1 t2) = Some (Node t1' t2') <->
(mkFull n t1 = Some t1' /\ mkFull n t2 = Some t2').
Lemma mkFull_mkCanon_simpl : forall n t1 t2, mkFull (S n) (mkCanon (Node t1 t2)) =
mkFull (S n) (Node (mkCanon t1) (mkCanon t2)).
Lemma mkFull_None : forall n t, n < tree_heightP t -> mkFull n t = None.
Lemma mkFull_Some : forall n t, n >= tree_heightP t -> exists t', mkFull n t = Some t'.
Lemma mkCanon_eq_split : forall t1 t2 t1' t2', mkCanon (Node t1 t2) = mkCanon (Node t1' t2')
-> mkCanon t1 = mkCanon t1' /\ mkCanon t2 = mkCanon t2'.
Lemma mkCanon_simpl : forall t1 t2, mkCanon (Node (mkCanon t1) (mkCanon t2)) = mkCanon (Node t1 t2).
Lemma mkCanon_height : forall t t', mkCanon t = t' ->  tree_heightP t' <= tree_heightP t.
Lemma mkCanon_rewrite : forall t, exists t1, exists t2, mkCanon t = mkCanon (Node t1 t2).
Lemma canonTree_rewrite1 : forall (t' : canonTree), exists t1, exists t2,
t' = (exist (fun t => canonicalTree t)
(mkCanon (Node t1 t2))
(mkCanon_correct _)).
Lemma canonTree_rewrite2: forall (t : canonTree), t =
exist (fun t => canonicalTree t) (mkCanon (proj1_sig t)) (mkCanon_correct _).
Lemma mkCanon_height_split : forall n t11 t12 t21 t22,
max (tree_heightP (mkCanon (Node t11 t12)))
(tree_heightP (mkCanon (Node t21 t22))) < S (S n) ->
max (tree_heightP (mkCanon t11))
(tree_heightP (mkCanon t21)) < S n /\
max (tree_heightP (mkCanon t12))
(tree_heightP (mkCanon t22)) < S n.
Lemma mkCanon_diff : forall t11 t12 t21 t22,
mkCanon (Node t11 t12) <> mkCanon (Node t21 t22) ->
mkCanon t11 <> mkCanon t21 \/
mkCanon t12 <> mkCanon t22.
Lemma canonTree_proof_irr: forall t1 t2 c1 c2, t1 = t2 -> exist (fun t => canonicalTree t) t1 c1 =
exist (fun t => canonicalTree t) t2 c2.
Lemma canonTree_combine : forall t1 t2, canonicalTree t1 ->
canonicalTree t2 ->
max (tree_heightP t1) (tree_heightP t2) > 0 ->
canonicalTree (Node t1 t2).
Lemma mkCanon_intersect : forall t1 t2, mkCanon (intersect_tree (mkCanon t1) (mkCanon t2)) =
mkCanon (intersect_tree t1 t2).
Lemma mkCanon_join_split : forall t11 t12 t21 t22 t31 t32,
join (exist (fun t => canonicalTree t)(mkCanon (Node t11 t12)) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon (Node t21 t22)) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon (Node t31 t32)) (mkCanon_correct _))->
join (exist (fun t => canonicalTree t)(mkCanon t11) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t21) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t31) (mkCanon_correct _))/\
join (exist (fun t => canonicalTree t)(mkCanon t12) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t22) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t32) (mkCanon_correct _)).
Lemma mkCanon_join_combine : forall t11 t12 t21 t22 t31 t32,
join (exist (fun t => canonicalTree t)(mkCanon t11) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t21) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t31) (mkCanon_correct _))->
join (exist (fun t => canonicalTree t)(mkCanon t12) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t22) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon t32) (mkCanon_correct _))->
join (exist (fun t => canonicalTree t)(mkCanon (Node t11 t12)) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon (Node t21 t22)) (mkCanon_correct _))
(exist (fun t => canonicalTree t)(mkCanon (Node t31 t32)) (mkCanon_correct _)).
Lemma mkCanon_mkFull_split : forall n t1 t2 t1' t2', mkFull (S n) (mkCanon (Node t1 t2)) =
Some (Node t1' t2') <->
mkFull n (mkCanon t1) = Some t1' /\
mkFull n (mkCanon t2) = Some t2'.
(*L20*)
Lemma tree_round_left_zero : forall t, roundL 0 t = None.
Lemma tree_round_left_combine: forall n t1 t2 t1' t2',
roundL n (exist (fun t => canonicalTree t)(mkCanon t1) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t1') (mkCanon_correct _)) ->
roundL n (exist (fun t => canonicalTree t)(mkCanon t2) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t2') (mkCanon_correct _))->
roundL (S n) (exist (fun t => canonicalTree t)(mkCanon (Node t1 t2)) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon (Node t1' t2')) (mkCanon_correct _)).
Lemma tree_round_left_split : forall n t1 t2 t1' t2',
roundL (S (S n)) (exist (fun t => canonicalTree t)(mkCanon (Node t1 t2)) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon (Node t1' t2')) (mkCanon_correct _)) ->
roundL (S n) (exist (fun t => canonicalTree t)(mkCanon t1) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t1') (mkCanon_correct _)) /\
roundL (S n) (exist (fun t => canonicalTree t)(mkCanon t2) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t2') (mkCanon_correct _)).
Lemma tree_round_left_Leaf : forall b n,
roundL (S n) (exist (fun t => canonicalTree t)(Leaf b) (canonTree_Leaf _))
= Some (exist (fun t => canonicalTree t)(Leaf b) (canonTree_Leaf _)).
(*L15*)
Lemma tree_round_left_identity : forall n t, height t < n ->
roundL n t = Some t.
Lemma tree_round_left_one : forall t1 t2 t c,
roundL 1 (exist (fun t => canonicalTree t)(Node t1 t2) c) = Some t ->
exists b1,exists b2, t1 = Leaf b1 /\ t2 = Leaf b2 /\
t = (exist (fun t => canonicalTree t)(Leaf b1) (canonTree_Leaf _)).
(*L14*)
Lemma tree_round_left_join : forall n t1 t2 t3 t1' t2' t3',
join t1 t2 t3 ->
roundL n t1 = Some t1' ->
roundL n t2 = Some t2' ->
roundL n t3 = Some t3' ->
join t1' t2' t3'.
(*L16*)
Lemma tree_round_left_None : forall n t,
n < height t ->
roundL n t = None.
(*L17*)
Lemma tree_round_left_decrease : forall n t,
S n = height t ->
exists t', roundL (S n) t = Some t' /\ height t' <= n.
(*L18*)
Lemma tree_round_left_Some : forall n t,
height t <= S n ->
exists t', roundL (S n) t = Some t'.
(*L19*)
Lemma tree_round_left_height_compare : forall t t' n,
roundL n t = Some t' ->
height t' < n.
Lemma tree_round_right_combine : forall n t1 t2 t1' t2',
roundR n (exist (fun t => canonicalTree t)(mkCanon t1) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t1') (mkCanon_correct _)) ->
roundR n (exist (fun t => canonicalTree t)(mkCanon t2) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t2') (mkCanon_correct _))->
roundR (S n) (exist (fun t => canonicalTree t)(mkCanon (Node t1 t2)) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon (Node t1' t2')) (mkCanon_correct _)).
Lemma tree_round_right_split : forall n t1 t2 t1' t2',
roundR (S (S n)) (exist (fun t => canonicalTree t)(mkCanon (Node t1 t2)) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon (Node t1' t2')) (mkCanon_correct _)) ->
roundR (S n) (exist (fun t => canonicalTree t)(mkCanon t1) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t1') (mkCanon_correct _)) /\
roundR (S n) (exist (fun t => canonicalTree t)(mkCanon t2) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t)(mkCanon t2') (mkCanon_correct _)).
Lemma tree_round_right_Leaf : forall b n,
roundR (S n) (exist (fun t => canonicalTree t)(Leaf b) (canonTree_Leaf _))
= Some (exist (fun t => canonicalTree t)(Leaf b) (canonTree_Leaf _)).
(*L22*)
Lemma tree_round_right_identity : forall n t,
height t < n ->
roundR n t = Some t.
Lemma tree_round_right_one : forall t1 t2 t c,
roundR 1 (exist (fun t => canonicalTree t)(Node t1 t2) c) = Some t ->
exists b1,exists b2, t1 = Leaf b1 /\ t2 = Leaf b2 /\
t = (exist (fun t => canonicalTree t)(Leaf b2) (canonTree_Leaf _)).
(*L21*)
Lemma tree_round_right_join : forall n t1 t2 t3 t1' t2' t3',
join t1 t2 t3 ->
roundR n t1 = Some t1' ->
roundR n t2 = Some t2' ->
roundR n t3 = Some t3' ->
join t1' t2' t3'.
(*L23*)
Lemma tree_round_right_None : forall n t,
n < height t ->
roundR n t = None.
(*L24*)
Lemma tree_round_right_decrease : forall n t,
S n = height t ->
exists t', roundR (S n) t = Some t' /\ height t' <= n.
(*L25*)
Lemma tree_round_right_Some : forall n t,
height t <= S n ->
exists t', roundR (S n) t = Some t'.
(*L26*)
Lemma tree_round_right_height_compare : forall t t' n,
roundR n t = Some t' ->
height t' < n.
(*L27*)
Lemma tree_round_right_zero : forall t, roundR 0 t = None.
Lemma tree_avg_Leaf : forall n b c,
avg (S n) (exist (fun t => canonicalTree t)(Leaf b) c)
(exist (fun t => canonicalTree t)(Leaf b) c)
= Some (exist (fun t => canonicalTree t)(Leaf b) c).
(*L29*)
Lemma tree_avg_identity : forall n t,
height t < n ->
avg n t t = Some t.
(*L30*)
Lemma tree_avg_None : forall n t1 t2,
n <= max (height t1) (height t2) ->
avg n t1 t2 = None.
Lemma tree_avg_split : forall n t11 t12 t21 t22 t31 t32,
avg (S (S n)) (exist (fun t => canonicalTree t) (mkCanon (Node t11 t12)) (mkCanon_correct _))
(exist (fun t => canonicalTree t) (mkCanon (Node t21 t22)) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t) (mkCanon (Node t31 t32)) (mkCanon_correct _))->
avg (S n )    (exist (fun t => canonicalTree t) (mkCanon t11) (mkCanon_correct _))
(exist (fun t => canonicalTree t) (mkCanon t21) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t) (mkCanon t31) (mkCanon_correct _)) /\
avg (S n )    (exist (fun t => canonicalTree t) (mkCanon t12) (mkCanon_correct _))
(exist (fun t => canonicalTree t) (mkCanon t22) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t) (mkCanon t32) (mkCanon_correct _)).
Lemma tree_avg_combine : forall n t11 t12 t21 t22 t31 t32,
avg n (exist (fun t => canonicalTree t) (mkCanon t11) (mkCanon_correct _))
(exist (fun t => canonicalTree t) (mkCanon t21) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t) (mkCanon t31) (mkCanon_correct _)) ->
avg n (exist (fun t => canonicalTree t) (mkCanon t12) (mkCanon_correct _))
(exist (fun t => canonicalTree t) (mkCanon t22) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t) (mkCanon t32) (mkCanon_correct _)) ->
avg (S n) (exist (fun t => canonicalTree t) (mkCanon (Node t11 t12)) (mkCanon_correct _))
(exist (fun t => canonicalTree t) (mkCanon (Node t21 t22)) (mkCanon_correct _))
= Some (exist (fun t => canonicalTree t) (mkCanon (Node t31 t32)) (mkCanon_correct _)).
(*L31*)
Lemma tree_avg_round2avg : forall n t1 t2 t3,
roundL n t3 = Some t1 ->
roundR n t3 = Some t2 ->
avg n t1 t2 = Some t3.
(*L32*)
Lemma tree_avg_avg2round : forall n t1 t2 t3,
avg n t1 t2 = Some t3 ->
roundL n t3 = Some t1 /\
roundR n t3 = Some t2.
(*L33*)
Lemma tree_avg_join : forall n t11 t12 t13 t21 t22 t23 t31 t32 t33,
avg n t11 t12 =  Some t13 ->
avg n t21 t22 = Some t23 ->
avg n t31 t32 = Some t33 ->
join t11 t21 t31 ->
join t12 t22 t32 ->
join t13 t23 t33.
Lemma tree_avg_increase : forall n t1 t2,
t1 <> t2 -> max (height t1) (height t2) < n ->
exists t3, avg n t1 t2 = Some t3 /\ height t3 = n.
(*L34*)
Lemma tree_avg_ex: forall n t1 t2,
height t1 < n ->
height t2 < n ->
exists t3, avg n t1 t2 = Some t3.
(*L35*)
Lemma avg_share_correct: forall n s,
(height s <= S n)%nat ->
exists s', exists s'',
roundL (S n) s = Some s' /\
roundR (S n) s = Some s'' /\
avg (S n) s' s'' = Some s.
(*L5*)
Lemma decompose_recompose: forall t,
decompose (recompose t) = t.
(*L6*)
Lemma recompose_decompose: forall t,
recompose(decompose t) = t.
Lemma decompose_rewrite : forall t t1 t2, decompose t = (t1 ,t2)
<-> t = exist (fun t => canonicalTree t)
(mkCanon (Node (proj1_sig t1) (proj1_sig t2))) (mkCanon_correct _).
(*L4*)
Lemma decompose_height : forall n t1 t2 t3,
height t1 = S n ->
decompose t1 = (t2, t3) ->
height t2 <= n /\ height t3 <= n.
(*L7*)
Lemma decompose_join : forall t1 t11 t12 t2 t21 t22 t3 t31 t32,
decompose t1 = (t11, t12) ->
decompose t2 = (t21, t22) ->
decompose t3 = (t31, t32) ->
(join t1 t2 t3 <->
(join t11 t21 t31 /\ join t12 t22 t32)).
Lemma is_height_zero : forall t, {height t = 0} + {height t <> 0}.
(*12*)
Lemma decompose_le: forall s1 s2 s11 s12 s21 s22,
(s1 <= s2)%ba ->
decompose s1 = (s11,s12) ->
decompose s2 = (s21,s22) ->
(s11 <= s21)%ba /\ (s12 <= s22)%ba.
(*L13*)
Lemma decompose_diff: forall s1 s2 s11 s12 s21 s22,
s1 <> s2 ->
decompose s1 = (s11,s12) ->
decompose s2 = (s21,s22) ->
s11 <> s21 \/ s12 <> s22.
(*L36*)
Lemma countBLeafCT_decompose : forall n s s1 s2,
decompose s = (s1,s2) ->
countBLeafCT (S n) s = countBLeafCT n s1 + countBLeafCT n s2.
(*L37*)
Lemma countBLeafCT_le : forall n s1 s2,
(s1 <= s2)%ba -> countBLeafCT n s1 <= countBLeafCT n s2.
(*L38*)
Lemma countBLeafCT_lt : forall n s1 s2,
(s1 <= s2)%ba ->
s1 <> s2 ->
height s2 <= n ->
countBLeafCT n s1 < countBLeafCT n s2.