Require Arith.
Require Omega.
Require machine.

Section lemmas.


Lemma apart_extend_right : 
  (e1,sz1,e2,sz2:nat)(sz2':nat)
  (apart e1 sz1 e2 sz2) ->
  (le sz2' sz2) ->
  (apart e1 sz1 e2 sz2').
Proof.
Unfold apart.
Intros.
Omega.
Qed.


Lemma apart_shift_right : 
  (e1,sz1,e2,sz2:nat)(x,sz2':nat)
  (apart e1 sz1 e2 sz2) ->
  (le (plus x sz2') sz2) ->
  (lt (0) sz2') ->
  (apart e1 sz1 (plus e2 x) sz2').
Proof.
Unfold apart.
Intros.
Omega.
Qed.


Lemma apart_move_both : 
  (e1,sz1,e2,sz2:nat)(a:nat)
  (apart e1 sz1 e2 sz2) ->
  (apart (plus a e1) sz1 (plus a e2) sz2).
Proof.
Unfold apart.
Intros.
Omega.
Qed.



Lemma apart_sym : (e1:exp; n1:nat; e2:exp; n2:nat)
  (apart e1 n1 e2 n2) ->
  (apart e2 n2 e1 n1).
Proof.
Unfold apart.
Intros.
Omega.
Qed.

Lemma allocate_addr_apart : (s:state)
  (n:nat)
  (e1:exp; SZ1:nat)  
  (lt (0) n) ->
  (lt (0) SZ1) ->
  (addr SZ1 (mem_of s) e1) ->
  (apart e1 SZ1 (rega_of (allocate n s)) n). 
Proof.
Intros.
Unfold apart.
LetTac a := (rega_of (allocate n s)).
Decompose Sum (lt_eq_lt_dec e1 a).
  Left.
  Split; Auto.  
  LetTac o := (minus a e1).
  Assert (not (le (plus o (1)) SZ1)).
    Intro.    
    Apply allocate_new with n1:=(1) o:=(0) n2:=n
        s:=s; Auto with arith.
      Replace (plus (0) (rega_of (allocate n s)))
          with (plus o e1).
        EApply addr_closed; EAuto.

        Unfold o a.
        Unfold a in a1.
        Omega.

      Unfold o a in H2; Unfold a in a1; Unfold a.
      Omega.

  ElimType False; Apply allocate_new with s:=s 
      n1:=(1) o:=(0) n2:=n;
      EAuto.
    EApply addr_closed.
      Rewrite b in H1; EApply H1.    
  
      Omega.

  Right.
  Split; Auto.  
  LetTac o := (minus e1 a).
  Assert (not (le (plus o (1)) n)).
    Intro.    
    Apply allocate_new with n1:=(1) o:=o n2:=n
        s:=s; Auto with arith.
       Omega.
   
      Replace (plus o (rega_of (allocate n s)))
          with (plus (0) e1).
        EApply addr_closed; EAuto.

        Unfold o a.
        Unfold a in b.
        Omega.

      Unfold o a in H2; Unfold a in b; Unfold a.
      Omega.
Qed.

Lemma allocate_addr_apart_extend : (s:state)
  (n:nat)
  (e1:exp; SZ1:nat; SZ2:nat)  
  (lt (0) n) ->
  (lt (0) SZ1) ->
  (le SZ2 n) ->
  (addr SZ1 (mem_of s) e1) ->
  (apart e1 SZ1 (rega_of (allocate n s)) SZ2). 
Proof.
Intros.
EApply apart_extend_right; EAuto.
EApply allocate_addr_apart; EAuto.
Qed.

End lemmas.

Tactic Definition Discriminate_something :=
  Match Context With [ H: ? = ? |- ? ]
    -> Discriminate H.
Tactic Definition Discriminate_some3 :=
  Match Context With [ H: (? = ?)\/(? = ?)\/(? = ?) |- ? ]
    -> Decompose [or] H; Discriminate_something.

