intros key update init t0.
elim t0; clear t0.
(* t0=Avl_Nil *)
intros avl_t0.
apply
Avl_Ins_Spec_Intro
with (t := Avl_Node key (update init) Avl_Nil Avl_Nil Balanced).
apply Not_Lookup.
unfold not in |- *; intros d lookup0.
apply (inv_lookup_nil key d lookup0).
apply leave_is_avl.
apply Lin_Ins_New with (nil (A:=Int * B)) (nil (A:=Int * B)); trivial.
apply equiv_ins_nil.
right; 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).
intro equal.
clear ih_l0 ih_r0.
apply Avl_Ins_Spec_Intro with (t := Avl_Node k0 (update d0) l0 r0 b0).
apply Lookup with d0.
rewrite (equal_eq key k0 equal).
apply Lookup_Equal.
apply (avl_ins_eq k0 d0 l0 r0 b0); assumption.
rewrite (equal_eq key k0 equal).
apply Lin_Ins_Update with d0 (lin_avl l0) (lin_avl r0); trivial.
apply equiv_ins_eq; assumption.
left.
elim b0; simpl in |- *; trivial.
intro notequal.
elim (less_dec 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_dec_spec0 avl_l lin_ins_l equiv_ins_l bal_or_shift.
elim (balance_left k0 d0 l r0 b0).
intros t avl_t lin_t equiv_t growth_dec.
apply Avl_Ins_Spec_Intro with t.
elim lookup_dec_spec0; clear lookup_dec_spec0.
intros d lookup_d.
apply Lookup with d.
apply Lookup_Left; assumption.
intros not_lookup_d0.
apply Not_Lookup.
unfold not in |- *; intros d lookup_d0.
apply (not_lookup_d0 d).
apply (lookup_avl_inv_less key k0 d0 l0 r0 b0); assumption.
assumption.
elim lin_ins_l; clear lin_ins_l.
intros l1 l2 lin_l0 lin_l.
apply Lin_Ins_New with l1 (l2 ++ (k0, d0) :: lin_avl r0); simpl in |- *.
rewrite lin_l0.
rewrite (app_ass l1 l2 ((k0, d0) :: lin_avl r0)); trivial.
rewrite lin_t; simpl in |- *.
rewrite lin_l.
rewrite (app_ass l1 ((key, update init) :: l2) ((k0, d0) :: lin_avl r0)).
trivial.
intros d' l1 l2 lin_l0 lin_l.
apply Lin_Ins_Update with d' 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 ((key, update d') :: l2) ((k0, d0) :: lin_avl r0)).
trivial.
apply equiv_ins_equiv_equiv_ins with (Avl_Node k0 d0 l r0 b0).
apply (equiv_ins_left key update init k0 d0 l0 r0 b0 l b0); assumption.
apply equiv_sym; assumption.
elim growth_dec; clear growth_dec.
intro has_not_grown.
left.
inversion_clear avl_t0.
generalize H1; clear H1.
clear equiv_t equiv_ins_l H3 H2 H0 H.
inversion_clear has_not_grown.
(* (is_balanced_avl l r0 b0) *)
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.
intro Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
trivial.
(* (is_balanced_avl_left_shift l r0 Left_Balanced) *)
rewrite H0; clear H0.
simpl in |- *.
inversion_clear H.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
(* (is_balanced_avl_left_shift l r0 Right_Balanced) *)
rewrite H0; clear H0.
simpl in |- *.
inversion_clear H.
rewrite H0; clear H0.
trivial.
intro has_grown.
right.
clear equiv_t equiv_ins_l.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear has_grown.
(*  (is_balanced_avl_left_shift l r0 Left_Balanced) *)
rewrite H0; clear H0.
simpl in |- *.
inversion_clear H.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
(* (is_balanced_avl_left_shift l r0 Balanced) *)
rewrite H0; clear H0.
simpl in |- *.
inversion_clear H.
rewrite H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
(* side premisses of Elim (balance...) *)
assumption.
apply below_below_avl.
apply equiv_ins_below with key update init l0.
assumption.
assumption.
inversion_clear avl_t0.
apply is_below_avl_is_below; assumption.
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
elim bal_or_shift; clear bal_or_shift; intro height_l.
left.
apply hasnot_grown_left__preserves_is_balanced_avl with l0.
inversion_clear avl_t0; assumption.
assumption.
right.
apply is_left_balanced_is_left_balanced_left_shift with l0.
inversion_clear avl_t0; assumption.
assumption.
(**********    greater   **********************************)
intro notless.
generalize (notequal_notless_greater key k0 notequal notless).
intro greater; clear notless.
elim (ih_r0 (inv_is_avl_right k0 d0 l0 r0 b0 avl_t0)); clear ih_l0 ih_r0.
intros r lookup_dec_spec0 avl_r lin_ins_r equiv_ins_r bal_or_shift.
elim (balance_right k0 d0 l0 r b0).
intros t avl_t lin_t equiv_t growth_dec.
apply Avl_Ins_Spec_Intro with t.
elim lookup_dec_spec0; clear lookup_dec_spec0.
intros d lookup_d.
apply Lookup with d.
apply Lookup_Right; assumption.
intros not_lookup_d0.
apply Not_Lookup.
unfold not in |- *; intros d lookup_d.
apply (not_lookup_d0 d).
apply (lookup_avl_inv_greater key k0 d0 l0 r0 b0); assumption.
assumption.
elim lin_ins_r; clear lin_ins_r.
intros l1 l2 lin_r0 lin_r.
apply Lin_Ins_New with (lin_avl l0 ++ (k0, d0) :: l1) l2; simpl in |- *.
rewrite lin_r0.
rewrite (app_ass (lin_avl l0) ((k0, d0) :: l1) l2); trivial.
rewrite lin_t; simpl in |- *.
rewrite lin_r.
rewrite (app_ass (lin_avl l0) ((k0, d0) :: l1) ((key, update init) :: l2)).
trivial.
intros d' l1 l2 lin_r0 lin_r.
apply Lin_Ins_Update with d' (lin_avl l0 ++ (k0, d0) :: l1) l2; simpl in |- *.
rewrite lin_r0.
rewrite (app_ass (lin_avl l0) ((k0, d0) :: l1) ((key, d') :: l2)); trivial.
rewrite lin_t; simpl in |- *.
rewrite lin_r.
rewrite (app_ass (lin_avl l0) ((k0, d0) :: l1) ((key, update d') :: l2)).
trivial.
apply equiv_ins_equiv_equiv_ins with (Avl_Node k0 d0 l0 r b0).
apply (equiv_ins_right key update init k0 d0 l0 r0 b0 r b0); assumption.
apply equiv_sym; assumption.
clear equiv_t avl_t bal_or_shift equiv_ins_r.
elim growth_dec; clear growth_dec.
intro has_not_grown.
left.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear has_not_grown.
(* (is_balanced_avl l0 r b0) *)
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.
(* (is_balanced_avl_right_shift l0 r Left_Balanced) *)
rewrite H0; clear H0; simpl in |- *.
inversion_clear H.
rewrite H0; trivial.
(* (is_balanced_avl_left_shift l0 r Right_Balanced) *)
rewrite H0; clear H0; simpl in |- *.
inversion_clear H.
rewrite <- H0; clear H0.
intro Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
intro has_grown.
right.
inversion_clear avl_t0.
generalize H1; clear H H0 H1 H2 H3.
inversion_clear has_grown; simpl in |- *.
(*  (is_balanced_avl_right_shift l0 r Balanced) *)
rewrite H0; clear H0.
inversion_clear H.
rewrite H0; trivial.
(* (is_balanced_avl_right_shift l0 r Right_Balanced) *)
rewrite H0; clear H0.
inversion_clear H.
rewrite <- H0; clear H0.
intros Balanced_l0; inversion_clear Balanced_l0.
rewrite H; trivial.
(* side premisses of Elim (balance...) *)
inversion_clear avl_t0; assumption.
inversion_clear avl_t0; assumption.
assumption.
apply above_above_avl.
apply equiv_ins_above with key update init r0.
assumption.
assumption.
inversion_clear avl_t0.
apply is_above_avl_is_above; assumption.
elim bal_or_shift; clear bal_or_shift; intro height_r.
left.
apply hasnot_grown_right__preserves_is_balanced_avl with r0.
inversion_clear avl_t0; assumption.
assumption.
right.
apply is_balanced_avl_is_balanced_avl_right_shift with r0.
inversion_clear avl_t0; assumption.
assumption.
Qed.
(***********************************************************************)
Inductive equiv_del (key : Int) (t0 t : avl_tree) : Prop :=
equiv_del_intro :
(forall k : Int, Equal k key -> forall d : B, lookup k t d -> False) ->
(forall (k : Int) (data : B),
~ Equal k key -> lookup k t0 data -> lookup k t data) ->
(forall (k : Int) (data : B),
~ Equal k key -> lookup k t data -> lookup k t0 data) ->
equiv_del key t0 t.

Lemma inv_equiv_del_equal :
forall (key : Int) (t0 t : avl_tree) (k : Int) (d : B),
equiv_del key t0 t -> Equal k key -> lookup k t d -> False.