intros key t0; elim t0; clear t0.
(* t0=nil *)
intros avl_t0.
apply Delete_Spec_Intro with (t := Avl_Nil).
right.
unfold not in |- *; intros d lookup_t0.
inversion_clear lookup_t0.
assumption.
intros d lookup_t0.
elimtype False.
inversion_clear lookup_t0.
apply equiv_del_nil.
left; simpl in |- *; trivial.
(* t0=(Avl_Node k0 d0 l0 r0 b0) *)
intros k0 d0 l0 ih_l0 r0 ih_r0 b0 avl_t0.
elim (equal_dec key k0).
(* (Equal key=k0)  *)
intros equal.
clear ih_l0 ih_r0.
generalize avl_t0; clear avl_t0.
case l0; clear l0.
(* l0=nil *)
intro avl_t0.
apply Delete_Spec_Intro with (t := r0).
left with d0.
rewrite (equal_eq key k0 equal).
simpl in |- *.
apply Lookup_Equal.
inversion_clear avl_t0; assumption.
intros d lookup0.
apply Lin_Del_Spec_Intro with (nil (A:=Int * B)) (lin_avl r0).
rewrite (equal_eq key k0 equal); trivial.
rewrite (lookup_avl_equal key k0 (Avl_Node k0 d0 Avl_Nil r0 b0) d d0);
try assumption.
trivial.
apply Lookup_Equal.
simpl in |- *; trivial.
rewrite (equal_eq key k0 equal).
apply equiv_del_right_semi_leave; assumption.
right.
inversion_clear avl_t0.
inversion_clear H1; simpl in |- *.
discriminate H4.
rewrite <- H4.
simpl in |- *; trivial.
trivial.
(* l0=(node kl0 dl0 ll0 rl0 bl0) *)
intros kl0 dl0 ll0 rl0 bl0 avl_t0.
elim (delete_max kl0 dl0 ll0 rl0 bl0).
intros k d l lookup_l0 avl_l below_l lin_l0 equiv_del_l0 bal_or_shift.
elim (balance_shrunk_right k d l r0 b0); try assumption.
intros t avl_t lin_t0 equiv_t0 shrunk_dec.
apply Delete_Spec_Intro with (t := t).
left with d0.
rewrite (equal_eq key k0 equal).
simpl in |- *; apply Lookup_Equal.
assumption.
intros d1 lookup0.
apply
Lin_Del_Spec_Intro
with (lin_avl ll0 ++ (kl0, dl0) :: lin_avl rl0) (lin_avl r0).
rewrite (equal_eq key k0 equal).
rewrite
(lookup_avl_equal key k0
(Avl_Node k0 d0 (Avl_Node kl0 dl0 ll0 rl0 bl0) r0 b0) d1 d0)
; try assumption.
simpl in |- *; trivial.
apply Lookup_Equal.
generalize lin_l0; clear lin_l0; simpl in |- *; intro lin_l0.
rewrite lin_l0.
rewrite (app_ass (lin_avl l) ((k, d) :: nil) (lin_avl r0)).
trivial.
apply equiv_del_equiv_equiv_del with (t1 := Avl_Node k d l r0 b0).
apply equiv_del_equal; try assumption.
apply is_below_avl_is_below.
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
apply is_above_avl_is_above.
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
apply equiv_sym; assumption.
clear lin_t0 equiv_t0 avl_t bal_or_shift equiv_del_l0 below_l avl_l lookup_l0.
elim shrunk_dec; clear shrunk_dec.
intros hasnot_shrunk.
left.
inversion_clear avl_t0.
generalize H1; clear H1 H3 H2 H0 H.
inversion_clear hasnot_shrunk.
rewrite H0; clear H0.
inversion_clear H; simpl in |- *.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite <- H.
simpl in |- *; trivial.
rewrite H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite <- H.
simpl in |- *; trivial.
trivial.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite <- H0.
simpl in |- *; trivial.
rewrite H0; clear H0.
simpl in |- *; trivial.
intros has_shrunk.
right.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear has_shrunk.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite <- H0.
simpl in |- *; trivial.
rewrite H0; clear H0.
simpl in |- *; trivial.
(* side premisses (Elim balance_shrunk_right ...) *)
inversion_clear avl_t0; assumption.
apply above_avl_trans with k0.
inversion_clear avl_t0; assumption.
apply lookup_below_less with (Avl_Node kl0 dl0 ll0 rl0 bl0) d.
assumption.
apply is_below_avl_is_below.
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
elim bal_or_shift; clear bal_or_shift; intros height_l0.
left.
apply
hasnot_grown_left__preserves_is_balanced_avl
with (Avl_Node kl0 dl0 ll0 rl0 bl0).
inversion_clear avl_t0; assumption.
symmetry  in |- *; assumption.
right.
apply
is_balanced_avl_is_balanced_avl_right_shift_left
with (Avl_Node kl0 dl0 ll0 rl0 bl0).
inversion_clear avl_t0; assumption.
symmetry  in |- *; assumption.
inversion_clear avl_t0; assumption.
(* ~(Equal key k0) *)
intro notequal.
elim (less_dec key k0).
(* (Less key k0) *)
intro less.
elim (ih_l0 (inv_is_avl_left k0 d0 l0 r0 b0 avl_t0)); clear ih_l0 ih_r0.
intros l lookup_l0 avl_l lin_l0 equiv_del_l0 bal_or_shift.
elim (balance_shrunk_right k0 d0 l r0 b0); try assumption.
intros t avl_t lin_t equiv_t shrunk_dec.
apply Delete_Spec_Intro with t; try assumption.
elim lookup_l0; clear lookup_l0.
intros d lookup_d.
left with d.
apply Lookup_Left; assumption.
intro not_lookup_l0.
right.
unfold not in |- *; intros d lookup_t.
apply (not_lookup_l0 d).
apply (lookup_avl_inv_less key k0 d0 l0 r0 b0 d); assumption.
clear shrunk_dec equiv_t avl_t bal_or_shift equiv_del_l0 lookup_l0.
intros d lookup0.
elim lin_l0 with d; clear lin_l0.
intros l1 l2 lin_l0 lin_l.
apply Lin_Del_Spec_Intro with l1 (l2 ++ (k0, d0) :: lin_avl r0).
simpl in |- *.
rewrite lin_l0.
rewrite (app_ass l1 ((key, d) :: l2) ((k0, d0) :: lin_avl r0)).
trivial.
rewrite lin_t.
simpl in |- *.
rewrite lin_l.
rewrite (app_ass l1 l2 ((k0, d0) :: lin_avl r0)); trivial.
apply (lookup_avl_inv_less key k0 d0 l0 r0 b0 d); assumption.
clear shrunk_dec lin_t bal_or_shift lin_l0.
apply equiv_del_equiv_equiv_del with (t1 := Avl_Node k0 d0 l r0 b0);
try assumption.
apply equiv_del_trans_left; try assumption.
inversion_clear avl_t0.
apply is_above_avl_is_above; assumption.
apply equiv_sym; assumption.
clear lin_t equiv_t avl_t bal_or_shift equiv_del_l0 lookup_l0.
elim shrunk_dec; clear shrunk_dec.
intro hasnot_shrunk.
left.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear hasnot_shrunk.
rewrite H0; clear H0.
inversion_clear H; simpl in |- *.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
trivial.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0; simpl in |- *.
rewrite H0; trivial.
rewrite H0; clear H0.
simpl in |- *; trivial.
intros has_shrunk.
right.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear has_shrunk.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
simpl in |- *.
rewrite H0; trivial.
rewrite H0; clear H0.
simpl in |- *; trivial.
(* side premisses (Elim (balance_shrunk_right ...) ) *)
inversion_clear avl_t0.
apply below_below_avl.
apply below_equiv_del_below with l0 key.
apply is_below_avl_is_below; assumption.
assumption.
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
elim bal_or_shift; clear bal_or_shift; intros height_l0.
left.
apply hasnot_grown_left__preserves_is_balanced_avl with l0.
inversion_clear avl_t0; assumption.
symmetry  in |- *; assumption.
right.
apply is_balanced_is_balanced_right_shift with l0.
inversion_clear avl_t0; assumption.
assumption.
(* (Less k0 key) *)
intro notless.
generalize (notequal_notless_greater key k0 notequal notless); intro greater.
elim ih_r0; clear ih_r0 ih_l0 notless.
intros r lookup_r0 avl_r lin_r0 equiv_r0 bal_or_shift.
elim (balance_shrunk_left k0 d0 l0 r b0); try assumption.
intros t avl_t lin_t equiv_t shrunk_dec.
apply Delete_Spec_Intro with t; try assumption.
elim lookup_r0; clear lookup_r0.
intros d lookup_d.
left with d.
apply Lookup_Right; assumption.
intro not_lookup_r0.
right.
unfold not in |- *; intros d lookup_t.
apply (not_lookup_r0 d).
apply (lookup_avl_inv_greater key k0 d0 l0 r0 b0 d); assumption.
intros d lookup0.
elim lin_r0 with d; clear lin_r0.
intros l1 l2 lin_r0 lin_r.
apply Lin_Del_Spec_Intro with (lin_avl l0 ++ (k0, d0) :: l1) l2;
simpl in |- *.
rewrite (app_ass (lin_avl l0) ((k0, d0) :: l1) ((key, d) :: l2)).
rewrite lin_r0; trivial.
rewrite lin_t.
simpl in |- *.
rewrite (app_ass (lin_avl l0) ((k0, d0) :: l1) l2).
rewrite lin_r; trivial.
apply (lookup_avl_inv_greater key k0 d0 l0 r0 b0 d); assumption.
apply equiv_del_equiv_equiv_del with (t1 := Avl_Node k0 d0 l0 r b0);
try assumption.
apply equiv_del_trans_right; try assumption.
inversion_clear avl_t0.
apply is_below_avl_is_below; assumption.
apply equiv_sym; assumption.
clear lin_t equiv_t avl_t bal_or_shift equiv_r0 lookup_r0.
elim shrunk_dec; clear shrunk_dec.
intro hasnot_shrunk.
left.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear hasnot_shrunk.
rewrite H0; clear H0.
inversion_clear H; simpl in |- *.
trivial.
trivial.
rewrite <- H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
rewrite H0; clear H0.
simpl in |- *.
trivial.
rewrite H0; clear H0.
simpl in |- *.
trivial.
intros has_shrunk.
right.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear has_shrunk.
rewrite H0; clear H0.
simpl in |- *; trivial.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
simpl in |- *.
rewrite H0; trivial.
(* side premisses (Elim (balance_shrunk_right ...) ) *)
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
inversion_clear avl_t0.
apply above_above_avl.
apply above_equiv_del_above with r0 key.
apply is_above_avl_is_above; assumption.
assumption.
elim bal_or_shift; clear bal_or_shift; intros height_l0.
left.
apply hasnot_grown_right__preserves_is_balanced_avl with r0.
inversion_clear avl_t0; assumption.
symmetry  in |- *; assumption.
right.
apply Balanced_shrunk_left_balanced_shift with r0.
inversion_clear avl_t0; assumption.
assumption.
inversion_clear avl_t0; assumption.
Qed.
(************************************************************************)
(************************************************************************)
(************************************************************************)
Inductive AVL : Set :=
AVL_intro : forall t : avl_tree, is_avl t -> AVL.
Definition AVL_NIL := AVL_intro Avl_Nil Nil_Is_Avl.
Definition LOOKUP (key : Int) (T : AVL) (data : B) :=
match T with
| AVL_intro t _ => lookup key t data
end.
Definition LOOKUP_Dec_Spec (key : Int) (T : AVL) :=
match T with
| AVL_intro t _ => lookup_dec_spec key t
end.

(* Specifications: *)
Theorem LOOKUP_DEC : forall (key : Int) (T : AVL), LOOKUP_Dec_Spec key T.
intros key T.