Library example_reverse_list

Load seplog_header.

Definition data := 0%Z.
Definition next := 1%Z.

Ltac Unfolds_fields := unfold data; unfold next.

Definition reverse_list (i j k:var.v) :=
  j <- nat_e 0;
  while (var_e i =/= nat_e 0) (

       k <-* (i -.> next);
       (i -.> next) *<- var_e j;
       j <- var_e i;
       i <- var_e k

    ).

Inductive list_assert : list Z -> nat -> nat -> store.s -> heap.h -> Prop :=
     list_end : forall i j l s h,
                      sep.emp s h ->
                      i = j ->
                      l = nil ->
                      list_assert l i j s h
    | list_suiv: forall l l' d i j k s h h1 h2,
                      h1 # h2 ->
                      h = (h1 +++ h2) ->
                      i <> k ->
                      i <> j ->
                      l = d::l' ->
                      (nat_e i |--> int_e d::nat_e j::nil) s h1 ->
                      (list_assert l' j k) s h2 ->
                      list_assert l i k s h.

Definition list_empty : list Z := nil.

Fixpoint list_reverse_coq (l:list Z) : list Z :=
   match l with
     nil => nil
     | a :: l' => list_reverse_coq l' ++ a::nil
   end.

Eval compute in (list_reverse_coq (3::6::8::1::8::9::13::nil)%Z).

Lemma list_reverse_coq_lemma1: forall l a,
  list_reverse_coq (l ++ a::nil) = a::list_reverse_coq l.

Lemma list_reverse_coq_lemma2: forall l,
  list_reverse_coq (list_reverse_coq l) = l.

Lemma list_assert_inde_store: forall l i j s1 s2 h,
  list_assert l i j s1 h -> list_assert l i j s2 h.

Definition reverse_precondition (l: list Z) (hd: var.v) : assert :=
  fun s h => exists v, eval (var_e hd) s = Z_of_nat v /\ (list_assert l v 0) s h.

Definition reverse_postcondition (l: list Z) (hd: var.v) : assert :=
  fun s h => exists v, eval (var_e hd) s = Z_of_nat v /\ (list_assert (list_reverse_coq l) v 0) s h.

Definition reverse_list_specif: Prop := forall l i j k,
  var.set (i::j::k::nil) ->
    {{reverse_precondition l i}}
    reverse_list i j k
    {{reverse_postcondition l j}}.

Lemma list_assert_hd_uneq: forall l1 l2 hd1 hd2 s h,
   (list_assert l1 hd1 0 ** list_assert l2 hd2 0) s h -> hd1 <> 0 ->
   hd1 <> hd2.

Ltac Decompose_inverse_list_hyp := red; intros; Decompose_hyp.

Ltac Resolve_inverse_list_goal :=
  match goal with
    | |- ?P1 /\ ?P2 => split; [Resolve_inverse_list_goal | Resolve_inverse_list_goal]
    | id: list_assert ?l ?st ?ed ?s1 ?h1 |- list_assert ?l ?st ?ed ?s2 ?h2 => assert (A1: h2 = h1); [Heap_emp_clean; Equal_heap | rewrite A1; clear A1; eapply (list_assert_inde_store); apply id]
    | id: list_assert ?l ?st ?ed ?s1 ?h |- list_assert ?l ?st ?ed ?s2 ?h => eapply (list_assert_inde_store); apply id
    | |- update_store2 ?x ?v ?P => red; Resolve_inverse_list_goal
    | |- _ => (Store_update || auto)
    | _ => idtac
  end.

Ltac Resolve_inverse_list:= Decompose_inverse_list_hyp; Resolve_inverse_list_goal.

Lemma reverse_list_verif: reverse_list_specif.