Module Utils

Require Import Coqlib.
Require Integers Pointers Errors.
Require Import BinPos List Utf8.
Require Import Values Maps.

Set Implicit Arguments.

Tactic Notation "inv" ident(X) := inversion X; try (subst; clear X).

Ltac discr :=
  match goal with
    | H : forall _, _ <> _ |- _ => eelim H; reflexivity
  end || idtac.

Lemma true_neq_false : true <> false.
Proof.
discriminate. Qed.

Ltac tnf := match goal with
              | H : true = false |- _ => elim (true_neq_false H)
              | H : false = true |- _ => elim (true_neq_false (eq_sym H))
            end.

Notation "'do' X <- A ; B" := (optbind (fun X => B) A)
 (at level 200, X ident, A at level 100, B at level 200).

Definition bind2 (A B C: Type) (f: option (A*B)) (g: A -> B -> option C) : option C :=
  match f with Some (a,b) => g a b | None => None end.

Notation "'do' ( X , Y ) <- A ; B" := (bind2 A (fun X Y => B))
 (at level 200, X ident, Y ident, A at level 100, B at level 200).

Lemma opt_bind_inversion {A B g f} {b:B} :
  optbind g f = Some b ->
  exists a : A, f = Some a.
Proof.
  destruct f as [a|].
  intros; exists a; reflexivity.
  simpl; intros H; inv H.
Qed.

Lemma opt_bind_inversion' {A B g f} :
  optbind g f <> @None B ->
  exists a : A, f = Some a.
Proof.
  destruct f as [a|].
  intros; exists a; reflexivity.
  simpl; intros H. congruence .
Qed.

Ltac opt_bind_inv t :=
  match goal with
    | H : @None _ <> optbind _ _ |- _ => symmetry in H; opt_bind_inv t
    | H : Some _ = optbind _ _ |- _ => symmetry in H; opt_bind_inv t
    | H : optbind _ _ = Some _ |- _ =>
      let H' := fresh "Hbind" in
      destruct (opt_bind_inversion H) as [t H']; rewrite H' in H; simpl in H
    | H : optbind _ _ <> @None _ |- _ =>
      let H' := fresh "Hbind" in
      destruct (opt_bind_inversion' H) as [t H']; rewrite H' in H; simpl in H
  end.

  Ltac bi :=
    match goal with
      | [H: Errors.bind _ _ = Errors.OK _ |- _] =>
          let u := fresh "Hbi" in
          destruct (Errors.bind_inversion _ _ H) as (? & u & ?); clear H;
          (match goal with
             | [K: unit |- _] => destruct K
           end || idtac)
    end.

  Ltac bif2 :=
    match goal with
      | [H: context [if ?c then _ else _] |- _] =>
          let Q := fresh "Htrue" in
          case_eq c; intros Q; rewrite Q in H; clarify
    end.

  Ltac autorw :=
    match goal with
      | [H: _ = _ |- _] => rewrite H in *
    end.

  Ltac autorw' := repeat (progress (autorw; clarify)).

Tactic Notation "app_inv" :=
  match goal with
    | H : _ ++ _ :: nil = _ ++ _ :: nil |- _ =>
      destruct (app_inj_tail _ _ _ _ H) as [?Hsnoc0 ?Hsnoc]; subst; clear H
    | H : nil = _ ++ _ :: _ |- _ => elim (app_cons_not_nil _ _ _ H)
    | H : _ ++ _ :: _ = nil |- _ => eelim app_cons_not_nil; symmetry; eassumption
    | H : _ ++ _ :: _ = _ :: nil |- _ => rewrite <- app_nil_l in H;
      destruct (app_inj_tail _ _ _ _ H) as [?Hsnoc0 ?Hsnoc]; subst; clear H
  end.

Lemma canap : forall {A l} {e:A} {x f}, l ++ e :: nil = x::f ->
                                        (l = nil /\ f = nil /\ x = e)
                                \/ (exists m, l = x::m /\ f = m++e::nil).
Proof.
  induction l; simpl.
  intros. inv H. left; intuition.
  intros e x f H. inv H.
  right. intuition eauto.
Qed.

Inductive lift_exists_list {X Y : Type} (R: X -> Y -> Prop) : list X -> Y -> Prop :=
| lel_hd x tl y (HR: R x y) : lift_exists_list R (x::tl) y
| lel_tl hd tl y (HR: lift_exists_list R tl y) : lift_exists_list R (hd::tl) y
.

Lemma in_lift_exists_list {X Y} (R: X -> Y -> Prop) :
  forall y l x,
    R x y -> In x l -> lift_exists_list R l y.
Proof.
  induction l. vauto.
  intros x H Q; inv Q.
    vauto.
  right. eauto.
Qed.

Lemma lift_exists_list_in {X Y} (R: X -> Y -> Prop) :
  forall y l,
    lift_exists_list R l y ->
    exists x, R x y /\ In x l.
Proof.
  induction l; intros K; inv K.
  eexists; intuition eauto. intuition.
  destruct (IHl HR) as [x Hx].
  exists x. intuition.
Qed.

Inductive list_forall {X : Type} (P: X -> Prop) : list X -> Prop :=
| lf_nil : list_forall P nil
| lf_cons x l : P x -> list_forall P l -> list_forall P (x::l)
.

Inductive lift_forall_list {X Y : Type} (R: X -> Y -> Prop) : list X -> list Y -> Prop :=
| lfl_nil : lift_forall_list R nil nil
| lfl_cons x y xl yl (HEAD: R x y) (TAIL: lift_forall_list R xl yl)
  : lift_forall_list R (x::xl) (y::yl).

Lemma in_lift_list {X Y} R : ∀ l l',
  lift_forall_list R l l' ->
  ∀ x : X, In x l -> ∃ y : Y, (In y l' ∧ R x y).
Proof.
  induction 1 as [|x y xl yl HEAD H HI].
    intros ? K; inv K.
  intros a [K|K].
    subst. exists y. intuition.
  destruct (HI _ K) as [b Hb].
  exists b. intuition.
Qed.

Lemma lfl_snoc {X Y} (R:XYProp) : ∀ xl yl x y,
  lift_forall_list R (xl ++ x :: nil) (yl ++ y :: nil) <->
                   (lift_forall_list R xl ylR x y).
Proof.
  induction xl.
    intros yl x y. simpl.
    split. intros H; inv H; inv TAIL. destruct yl; inv H3. intuition. constructor.
    app_inv.
    intros [H K]; inv H. simpl. repeat constructor. assumption.
  intros yl x y.
  split.
     destruct yl; simpl; intros H; inv H. inv TAIL. try app_inv.
     destruct (IHxl yl x y) as [U _].
     destruct (U TAIL); intuition. repeat constructor; trivial.
   intros [H K]; inv H.
   simpl.
   constructor. trivial.
   destruct (IHxl yl0 x y) as [_ V].
   apply V. intuition.
Qed.

Lemma lfl2 A B R :
  forall x y, @list_forall2 A B R x y <-> @lift_forall_list A B R x y.
Proof.
  induction x as [|a x HI]; intros y; split; intros H; inv H; constructor; auto; apply HI; auto.
Qed.

Lemma lessdef_list_length {l l'} :
  Val.lessdef_list l l' →
  length l = length l'.
Proof.
  induction 1; simpl; intuition.
Qed.

Inductive lift_opt {X Y} (R: X -> Y -> Prop) : option X -> option Y -> Prop :=
| lo_none : lift_opt R None None
| lo_some x y (HR: R x y) : lift_opt R (Some x) (Some y)
.
Hint Constructors lift_opt.

Definition list_max := fold_left Pmax.

Notation "M '{{' key '}}'" :=
  (match PTree.get key M with Some l => l | None => @nil _ end)(at level 0, no associativity).

Definition of_pair_list {A} (elt: list (positive * A)) : PTree.t A :=
  fold_left
    (fun m kv =>
       m ! (fst kv) <- (snd kv)
    )
    elt
    (PTree.empty A).

Fixpoint of_list' {A} (elt: list A) id : PTree.t A :=
  match elt with
    | nil => PTree.empty _
    | e::elt' =>
        let m := of_list' elt' (Psucc id) in
          m ! id <- e
  end.

Definition of_list {A} (elt: list A) : PTree.t A := of_list' elt xH.

Section FIND_P.
Context {A : Type}.
Variable P : A -> Prop.
Hypothesis P_dec : forall a : A, { P a } + { ~ P a }.

Variable t : PTree.t A.

Definition find_p' : option positive :=
  PTree.fold (fun res i a =>
                match P_dec a with
                  | left _ => Some i
                  | right _ => res
                end
             ) t None.

Lemma find_p_correct :
  match find_p' with
    | Some i => match t ! i with Some a => P a | None => False end
    | None => forall i a, t ! i = Some a -> ~ P a
  end.
Proof.
  unfold find_p'.
  apply PTree_Properties.fold_rec.
  intros m m' [b|] Hm Hm'. rewrite <- Hm. assumption.
    intros i a H. apply (Hm' i). rewrite Hm. exact H.
  intros i; rewrite PTree.gempty. discriminate.
  intros m b k v Hk Hv.
  case (P_dec v); intros Ha.
    rewrite PTree.gss. congruence.
  destruct b as [i|].
    case (peq i k); intros Hb.
      subst. intros contra. rewrite Hk in contra. intuition.
    rewrite PTree.gso; auto.
  intros H i a.
  case (peq i k); intros Hi.
    subst. rewrite PTree.gss. congruence.
  rewrite PTree.gso; auto.
  apply H.
Qed.

Definition find_p : { i : positive | match t ! i with Some a => P a | None => False end }
                      + { forall i a, t ! i = Some a -> ~ P a }.
Proof.
refine (match find_p' as res return _ = res -> _ with
          | Some i => fun H => inleft _ (exist _ i _)
          | None => fun H => inright _ _
        end (eq_refl _));
generalize find_p_correct; rewrite H; trivial.
Defined.

End FIND_P.

Section REV_FIND.

Context {A : Type}.
Hypothesis A_eq : forall a a' : A, { a = a' } + { a <> a' }.
Variable t : PTree.t A.

Definition rev_find a : option positive :=
  find_p' _ (A_eq a) t.

Lemma rev_find_correct a :
  match rev_find a with
    | Some i => t ! i = Some a
    | None => forall i, t ! i <> Some a
  end.
Proof.
  unfold rev_find.
  generalize (find_p_correct _ (A_eq a) t).
  destruct (find_p' (eq a) (A_eq a) t) as [i|].
    destruct (t!i). congruence. intuition.
  intros H i contra.
  apply (H i a contra).
  reflexivity.
Qed.

End REV_FIND.

Section FORALL.

Context {A : Type}.
Variable P : positive -> A -> Prop.
Hypothesis P_dec : forall k (a : A), { P k a } + { ~ P k a }.

Variable t : PTree.t A.

Definition forall_spec (F : bool) : Prop :=
  if F
  then forall k v, t ! k = Some v -> P k v
  else exists k, exists v, t ! k = Some v /\ ~ P k v.

Definition tree_forall : bool :=
  PTree.fold
       (fun (b:bool) k v => if b then if P_dec k v then true else false else false)
       t
       true.

Lemma tree_forall_correct : forall_spec tree_forall.
Proof.
  unfold forall_spec, tree_forall.
  apply PTree_Properties.fold_rec.
  intros m m' a Heq.
  destruct a. intros H k v U. rewrite <- Heq in U. intuition.
  intros (k & v & H & U). exists k; exists v. rewrite <- Heq. intuition.
  intros k v. rewrite PTree.gempty. congruence.
  intros m a k v Hm Ht.
  destruct a.
    intros H.
    destruct (P_dec k v).
      intros x y. rewrite PTree.gsspec.
      destruct (peq x k). subst. congruence.
      apply H.
    exists k. exists v. rewrite PTree.gss. intuition.
  intros (x & y & U & V).
  exists x. exists y.
  rewrite PTree.gsspec.
  destruct (peq x k). congruence.
  intuition.
Qed.

End FORALL.

Section FORALLB.

Context {A: Type}.
Variable P : positive -> A -> bool.

Variable t : PTree.t A.

Let P' : positive -> A -> Prop := fun k a => P k a.
Lemma P'_dec : forall k a, { P' k a } + { ~ P' k a }.
Proof.
subst P'. simpl. intros. destruct (P k a); intuition. Defined.

Definition tree_forallb : bool :=
  tree_forall P' P'_dec t.

Corollary tree_forallb_correct :
  if tree_forallb
  then forall k v, t ! k = Some v -> P k v
  else exists k, exists v, t ! k = Some v /\ ~ P k v.
Proof.
apply tree_forall_correct. Qed.

End FORALLB.

Section SUBTREE.

Context {A : Type}.
Variable t : PTree.t A.

Program Fixpoint subtree' acc id (lst: list positive) :
  option (PTree.t { i : positive | t ! i <> None }) :=
  match lst with
    | i :: lst' =>
        do m <- acc ;
        match t ! i as H return t ! i = H -> _ with
          | Some _ => fun K => subtree' (Some (m ! id <- (exist _ i _))) (Psucc id) lst'
          | None => fun _ => None
        end (eq_refl _)
    | nil => acc
  end.
Next Obligation.
intros Q; rewrite Q in K; inversion K. Defined.

Definition subtree lst := subtree' (Some (PTree.empty _)) xH lst.

Context {B:Type}.
Variable f : A -> B.
Lemma map_subtree_prop i : t ! i <> None -> (PTree.map (fun _ => f) t) ! i <> None.
Proof.
intros H. rewrite PTree.gmap. destruct (t!i). discriminate. congruence. Qed.

Definition map_subtree (s : PTree.t { i : positive | t ! i <> None }) :
  PTree.t { i : positive | (PTree.map (fun _ => f) t) ! i <> None } :=
  PTree.map (fun _ (iH : { i : positive | t ! i <> None } ) =>
               match iH with exist i H =>
                               exist (fun j => (PTree.map (fun _ => f) t) ! j <> None)
                                     i (map_subtree_prop i H)
               end) s.

End SUBTREE.


Ltac tid_case tid :=
  intros ?t;
  case (peq t tid); intros ?Ht;
  [subst; repeat rewrite PTree.gss| repeat (rewrite PTree.gso;[|exact Ht])].

Tactic Notation "solve_by_inversion_step" tactic(t) :=
  match goal with
  | H : _ |- _ => solve [ inversion H; subst; t ]
  end
  || fail "because the goal is not solvable by inversion.".

Tactic Notation "solve" "by" "inversion" "1" :=
  solve_by_inversion_step idtac.
Tactic Notation "solve" "by" "inversion" "2" :=
  solve_by_inversion_step (solve by inversion 1).
Tactic Notation "solve" "by" "inversion" "3" :=
  solve_by_inversion_step (solve by inversion 2).
Tactic Notation "solve" "by" "inversion" :=
  solve by inversion 1.

Lemma last_eq {X:Type} : ∀l x d,
  last (l++x::@nil X) d = x.
Proof.
  induction l.
  reflexivity.
  intros x d.
  simpl. rewrite IHl.
  destruct l; reflexivity.
Qed.

Lemma last_cons {X:Type} : forall b (a c:X), last (a::b) c = last b a.
Proof.
  induction b. reflexivity.
  intros x y.
  rewrite IHb.
  rewrite <- IHb with a y.
  reflexivity.
Qed.

David's stuff

Tactic Notation ">" tactic(t) := t.
Tactic Notation "by" tactic(t) := t; fail "this goal should be proved at this point".

Ltac invh f :=
    match goal with
      [ id: f |- _ ] => inv id
    | [ id: f _ |- _ ] => inv id
    | [ id: f _ _ |- _ ] => inv id
    | [ id: f _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ _ _ _ _ _ _ |- _ ] => inv id
    | [ id: f _ _ _ _ _ _ _ _ _ _ _ _ _ _ |- _ ] => inv id
    end.

End David's stuff

Require Import Coqlib.

Section MAPS.
Local Open Scope positive_scope.
Context {A:Type}.
Variable q : PTree.t A.

Lemma list_max_correct : ∀l x z, (In x lPle x z) → Ple x (list_max l z).
Proof.
induction l as [|p l HI].
intros x z [H|H]. inv H. simpl. exact H.
intros x z. simpl.
intros [ [H|H]|H].
  subst. apply HI. right. unfold Ple. rewrite Zpos_max. apply Zmax_bound_r. intuition.
 apply HI. left. assumption.
apply HI; clear HI. right. unfold Ple in *. rewrite Zpos_max.
apply Zmax_bound_l. exact H.
Qed.

Lemma list_max_bound : ∀l x z, Plt (list_max l z) x → (~ In x l) ∧ Plt z x.
Proof.
intros l x z H.
split. intros K. assert (G:=list_max_correct l (z:=z) (or_introl _ K)).
unfold Plt in H. unfold Ple in G. intuition.
assert (G:=list_max_correct l (z:=z) (or_intror _ (Ple_refl _))).
unfold Plt, Ple in *. intuition.
Qed.

Definition max_key : positive :=
  PTree.fold (fun acc k _ => Pmax acc k) q xH.

Lemma max_key_correct : ∀k,
  Plt max_key kPTree.get k q = None.
Proof.
unfold max_key.
rewrite PTree.fold_spec.
rewrite <- fold_left_map.
intros k H.
case_eq (PTree.get k q). 2: trivial.
intros a Ha. assert (K:=PTree.elements_correct q k Ha).
assert (K':= in_map (@fst _ _) _ _ K). simpl in K'.
destruct (list_max_bound _ _ H) as [V W].
elim V. exact K'.
Qed.

End MAPS.

Section TREE_MAP_PARTIAL.

Context {A B: Type}.
Variable f : positive -> A -> Errors.res B.

Definition ptree_map_partial (t: PTree.t A) : Errors.res (PTree.t B) :=
  PTree.fold
       (fun q k a =>
          Errors.bind q
                (fun x =>
                   Errors.bind (f k a)
                         (fun y => Errors.OK (x ! k <- y))))
       t
       (Errors.OK (PTree.empty B)).

Lemma ptree_map_partial_spec t :
  match ptree_map_partial t with
    | Errors.OK t' =>
        (forall k a,
          t ! k = Some a -> exists b, f k a = Errors.OK b /\ t' ! k = Some b) /\
        (forall k, t ! k = None -> t' ! k = None)
    | Errors.Error msg =>
        exists k, exists a,
          t ! k = Some a /\ f k a = Errors.Error msg
  end.
Proof.
  unfold ptree_map_partial.
  apply PTree_Properties.fold_rec.
  intros m m' [a|msg] Heq H.
    destruct H as [H H'].
    split.
      intros k u Hu.
      rewrite <- (Heq k) in Hu.
      destruct (H k u Hu) as (b & Hb & Ht').
      now intuition eauto.
    intros k Hk. rewrite <- Heq in Hk. now intuition.
  destruct H as (k & a & U & V).
    exists k. exists a. intuition congruence.
  split; intros; rewrite PTree.gempty in *; now intuition.
 intros m [t'|msg] k v Hmk Htk IH; simpl.
   destruct IH as [IH IH'].
   case_eq (f k v);
     intros b Hb; simpl.
     split.
       intros k' a'.
       rewrite PTree.gsspec.
       case (peq k' k).
         intros; clarify.
         exists b. intuition. rewrite PTree.gss. reflexivity.
       intros Hkk Hk'.
       destruct (IH k' _ Hk') as (b' & Hb' & K).
       exists b'. intuition. rewrite PTree.gso; now trivial.
     intros k'. repeat rewrite PTree.gsspec.
     case (peq k' k); clarify. intuition.
   exists k. exists v. intuition. rewrite PTree.gss. reflexivity.
 destruct IH as (u & w & H & K).
 exists u. exists w. intuition.
 rewrite PTree.gso. trivial.
 intros contra; subst.
 congruence.
Qed.

Corollary ptree_map_partial_ok {t t'} :
  ptree_map_partial t = Errors.OK t' ->
        (forall k a,
          t ! k = Some a -> exists b, f k a = Errors.OK b /\ t' ! k = Some b) /\
        (forall k, t ! k = None -> t' ! k = None).
Proof.
generalize (ptree_map_partial_spec t). destruct (ptree_map_partial t); clarify. intros H Q; clarify. Qed.

Corollary ptree_map_partial_ko {t msg} :
  ptree_map_partial t = Errors.Error msg ->
        exists k, exists a,
          t ! k = Some a /\ f k a = Errors.Error msg.
Proof.
generalize (ptree_map_partial_spec t). destruct (ptree_map_partial t); clarify. intros H Q; clarify. Qed.

Corollary ptree_map_partial_inv {t t'} :
  ptree_map_partial t = Errors.OK t' ->
  forall k b,
    t' ! k = Some b ->
    exists a,
      t ! k = Some a /\ f k a = Errors.OK b.
Proof.
  generalize (ptree_map_partial_spec t). destruct (ptree_map_partial t); clarify.
  intros (H & Q) ?; clarify.
  intros k b Hb.
  case_eq (t ! k). intros a Ha; eexists; intuition.
    destruct (H k a Ha) as (b' & Hab & Hb'); rewrite Hb' in Hb; clarify.
  intros H'. pose proof (Q k H'). rewrite Hb in *. clarify.
Qed.

End TREE_MAP_PARTIAL.

Section TREE_OPT_MAP.

Context {A B : Type}.
Variable f : A -> option B.
Variable t : PTree.t A.

Definition ptree_opt_map : PTree.t B :=
  PTree.fold (fun res k a => match f a with Some b => res ! k <- b | None => res end) t (PTree.empty B).

Lemma ptree_opt_map_spec :
  forall k,
    match t ! k, ptree_opt_map ! k with
      | None, None => True
      | None, _ => False
      | Some a, b => f a = b
    end.
Proof.
  intros.
  unfold ptree_opt_map.
  apply PTree_Properties.fold_rec.
  intros m m' a H H0. rewrite <- H. trivial.
  repeat rewrite PTree.gempty. trivial.
  intros m a k0 v H H0 H1.
  rewrite PTree.gsspec.
  destruct (peq k k0).
    subst. rewrite H in H1.
    case_eq (f v). intros. rewrite PTree.gss. trivial.
    destruct (a ! k0); intuition.
  destruct (m ! k); destruct (f v); trivial.
    rewrite PTree.gso; trivial.
  rewrite PTree.gso; trivial.
Qed.

End TREE_OPT_MAP.

Module Rset.
  Definition t := PTree.t unit.
  Local Notation elt := positive.
  Definition empty : t := PTree.empty _.
  Definition add (x:elt) (s:t) : t := PTree.set x tt s.
  Definition singleton (x:elt) : t := add x empty.
  Definition remove (x:elt) (s:t) : t := PTree.remove x s.
  Definition add_list (l:list elt) (s:t) : t := List.fold_right add s l.
  Definition remove_list (l:list elt) (s:t) : t := List.fold_right remove s l.
  Definition mem (x:elt) (s:t) : bool :=
    match PTree.get x s with
      | None => false
      | Some _ => true
    end.
  Definition union (s1 s2:t) : t :=
    PTree.combine (fun o1 o2 =>
      match o1, o2 with
        | None, None => None
        | _, _ => Some tt
      end) s1 s2.
  Definition inter (s1 s2:t) : t :=
    PTree.combine (fun o1 o2 =>
      match o1, o2 with
        | Some _, Some _ => Some tt
        | _, _ => None
      end) s1 s2.
  Definition forallb (f:elt->bool) (s:t) : bool :=
    PTree.fold (fun b x _ => b && f x) s true.

  Definition subset (r s:t) : bool :=
    forallb (fun x => mem x s) r.

  Section PROP.
      Lemma add_mem {s v} : mem v (add v s).
Proof.
unfold mem, add. rewrite PTree.gss. trivial. Qed.
      Lemma add_mem_o {s v v'} : v <> v' -> mem v (add v' s) = mem v s.
Proof.
unfold mem, add. intros K. rewrite PTree.gsspec. destruct (peq v v'); clarify. Qed.
      Lemma mem_add {s v v'} : mem v s -> mem v (add v' s).
Proof.
unfold mem, add. intros K. rewrite PTree.gsspec. destruct peq; clarify. Qed.
      Lemma add_comm {s v v'} : add v (add v' s) = add v' (add v s).
Proof.
apply PTree.ext. intros x. unfold add. repeat rewrite PTree.gsspec.
        destruct (peq x v); destruct (peq x v'); reflexivity.
      Qed.
      Lemma add_not_empty {s v} : add v s <> empty.
Proof.
        unfold add, empty. intros K.
        assert (Some tt <> None) as Q by discriminate.
        elim Q. replace (Some tt) with ((s ! v <- tt) ! v). rewrite K. apply PTree.gempty.
        apply PTree.gss.
      Qed.
      Lemma mem_add_nop {s v} : mem v s -> add v s = s.
Proof.
unfold mem, add. intros K.
        apply PTree.ext. intros x. rewrite PTree.gsspec.
        destruct (peq x v). subst. destruct (s ! v) as [[]|]; clarify. trivial.
      Qed.

      Lemma remove_comm {s v v'} : remove v (remove v' s) = remove v' (remove v s).
Proof.
        unfold remove. apply PTree.ext.
        intros x; repeat rewrite PTree.grspec.
        destruct (PTree.elt_eq x v); destruct (PTree.elt_eq x v'); trivial.
      Qed.
      Lemma remove_add {s v} : ~ mem v s -> remove v (add v s) = s.
Proof.
unfold mem, remove, add. intros K.
        apply PTree.ext. intros. rewrite PTree.grspec.
        destruct (PTree.elt_eq x v).
          subst. destruct (s ! v); clarify.
        exploit PTree.gso; eauto.
      Qed.
      Lemma remove_add_remove {s v} : remove v (add v s) = remove v s.
Proof.
unfold mem, remove, add.
        apply PTree.ext. intros. rewrite PTree.grspec.
        destruct (PTree.elt_eq x v).
          subst. rewrite PTree.grs; auto.
          rewrite PTree.gro; auto.
        exploit PTree.gso; eauto.
      Qed.
      Lemma add_remove {s v} : add v (remove v s) = add v s.
Proof.
unfold remove, add.
        apply PTree.ext. intros. repeat rewrite PTree.gsspec.
        destruct (peq x v). trivial.
        rewrite PTree.grspec.
        destruct (PTree.elt_eq x v); clarify.
      Qed.
      Lemma not_mem_remove_nop {s v} : ~ mem v s -> remove v s = s.
Proof.
unfold mem, remove. intros K.
        apply PTree.ext. intros x. rewrite PTree.grspec.
        destruct (PTree.elt_eq x v). subst. destruct (s ! v) as [[]|]; clarify. trivial.
      Qed.
      Lemma remove_not_mem {v s} : ¬ mem v (remove v s).
Proof.
unfold mem, remove. rewrite PTree.grs. clarify. Qed.
      Lemma mem_rmo {s v v'} : v <> v' -> mem v (remove v' s) = mem v s.
Proof.
unfold mem, remove. intros K.
        rewrite PTree.grspec.
        destruct (PTree.elt_eq v v'); clarify.
      Qed.
      Lemma empty_not_mem {v} : ~ mem v empty.
Proof.
unfold mem, empty. rewrite PTree.gempty. intuition. Qed.

    Context { f : elt -> bool }.
    Lemma forallb_spec r :
      match forallb f r with
        | true => forall x, mem x r -> f x
        | false => exists x, mem x r /\ ~ f x
      end.
Proof.
      unfold forallb, mem.
      apply PTree_Properties.fold_rec.
      > intros m m' [] H H0. intros x K. rewrite <- H in K. intuition.
        destruct H0 as (x & Hx). exists x. rewrite <- H. assumption.
      > intros x. rewrite PTree.gempty. congruence.
      > intros m [] k v H H0 H1.
        > simpl.
          case_eq (f k); intros Hfk.
          > intros x.
            rewrite PTree.gsspec.
            destruct (peq x k). subst. intuition.
            intuition.
          > exists k. rewrite PTree.gss. intuition. congruence.
        > simpl.
          destruct H1 as (x & Hx).
          exists x.
          rewrite PTree.gso.
          assumption.
          intros contra; subst.
          rewrite H in Hx. intuition.
    Qed.
    Corollary forallb_forall {x r} :
      forallb f r -> mem x r -> f x.
Proof.
intros H. generalize (forallb_spec r). rewrite H. intuition. Qed.
    Corollary forall_forallb {r} :
      (∀ x, mem x rf x) → forallb f r.
Proof.
intros H. generalize (forallb_spec r). destruct (forallb f r). easy.
           intros (x & K & Q). specialize H with x. intuition.
    Qed.

  End PROP.

    Lemma subset_spec {r s} : subset r s <-> ∀ x, mem x rmem x s.
Proof.
split. intros H x q. exact (forallb_forall H q).
           apply forall_forallb.
    Qed.

    Remark empty_subset {r} : subset empty r.
Proof.
auto. Qed.

    Lemma subset_refl {r} : subset r r.
Proof.
apply forall_forallb. intuition. Qed.

    Lemma subset_trans : transitive _ subset.
Proof.
intros x y z X Y. apply forall_forallb.
           intros q Q. eapply (forallb_forall Y). apply (forallb_forall X Q).
    Qed.

    Lemma subset_antisym : antisymmetric _ subset.
Proof.
intros x y X Y. apply PTree.ext. intros q.
           case_eq (x ! q). intros () Qx.
           assert (mem q y). eapply (forallb_forall X). unfold mem. autorw'. unfold mem in *.
           destruct (y ! q) as [()|]; clarify.
           intros Qx.
           case_eq (y ! q). intros () Qy.
           assert (mem q x). eapply (forallb_forall Y). unfold mem. autorw'. unfold mem in *. autorw'.
           easy.
    Qed.

    Remark subset_empty {r} : subset r emptyr = empty.
Proof.
intros H. apply subset_antisym; auto. Qed.

    Lemma mem_singleton {x y} : mem x (singleton y) → x = y.
Proof.
unfold singleton. case (peq x y). easy. intros K H. rewrite add_mem_o in H.
           eelim empty_not_mem; eassumption. easy.
    Qed.

    Lemma subset_singleton : ∀ r x, subset r (singleton x) → r = emptyr = singleton x.
Proof.
intros r x H. case_eq (mem x r); intros K;[right|left].
           apply subset_antisym. easy. apply forall_forallb. intros y Y.
           now rewrite (mem_singleton Y) in *.
           apply subset_empty.
           apply subset_spec. intros y Y.
           rewrite subset_spec in H.
           rewrite (mem_singleton (H y Y)) in Y. autorw'.
    Qed.

    Lemma remove_subset {x r} : subset (remove x r) r.
Proof.
      apply subset_spec. intros q Q.
      case (peq q x). intros ->. elim (remove_not_mem Q).
      intros H. now rewrite mem_rmo in Q.
    Qed.

    Lemma subset_add {v s} : subset s (add v s).
Proof.
apply subset_spec. intros x X. case (peq x v).
           intros ->. apply add_mem.
           intros H. now rewrite add_mem_o.
    Qed.

    Lemma add_singleton {v v' s} : add v s = singleton v' →
                                   v = v' ∧ subset s (singleton v).
Proof.
      intros H.
      assert (mem v (singleton v')) as K. rewrite <- H. apply add_mem.
      rewrite (mem_singleton K) in *. intuition. rewrite <- H. apply subset_add.
    Qed.

    Lemma remove_last {v s} : remove v s = emptysubset s (singleton v).
Proof.
      intros H. apply subset_spec. intros x X.
      case (peq x v). intros ->. apply add_mem.
      intros K. apply False_ind.
      rewrite <- (@mem_rmo s _ _ K) in X.
      rewrite H in X.
      apply (empty_not_mem X).
    Qed.

    Lemma add_remove_comm {v v' s} :
      vv' →
      remove v' (add v s) = add v (remove v' s).
Proof.
      intros NE.
      apply subset_antisym; apply subset_spec; intros x Hx.
      case (peq x v). intros ->. apply add_mem.
      intros EN. rewrite add_mem_o; auto.
      assert (xv'). intros ->. elim (remove_not_mem Hx).
      rewrite mem_rmo; auto.
      rewrite mem_rmo in Hx; auto.
      rewrite add_mem_o in Hx; auto.
      assert (xv'). intros ->. rewrite add_mem_o in Hx; auto.
        elim (remove_not_mem Hx).
      rewrite mem_rmo; auto.
      case (peq x v). intros ->. apply add_mem.
      intros EN. rewrite add_mem_o; auto.
      rewrite add_mem_o in Hx; auto.
      rewrite mem_rmo in Hx; auto.
    Qed.
End Rset.

Section list.

Context {A:Type}.

Lemma In_eq_app: forall (x:A) l, In x l -> exists l1, exists l2, l = l1++x::l2.
Proof.
  induction l; intros; inv H.
  exists nil; simpl; econstructor; reflexivity.
  destruct IHl as (l1 & l2 & Hl); auto.
  exists (a::l1); exists l2; subst; auto.
Qed.



Lemma eq_app_app: forall (a b:A) l1 l2 l3 l4, l1 ++ a :: l2 = l3 ++ b :: l4 -> a<>b ->
  (exists l, l1 = l3 ++ b :: l /\ l4 = l ++ a :: l2)
  \/
  (exists l, l3 = l1 ++ a :: l /\ l2 = l ++ b :: l4).
Proof.
  induction l1; destruct l3; simpl; intros.
  inv H; intuition.
  inv H; right; exists l3; auto.
  inv H; left; exists l1; auto.
  inv H.
  exploit IHl1; eauto; intros [(l & L1 & L2) | (l & L1 & L2)]; subst; clear IHl1.
  left; econstructor; split; eauto.
  right; econstructor; split; eauto.
Qed.


End list.

Reserved Notation "m ¡ l" (no associativity, at level 60).
Fixpoint get_list {X:Type} (m: PTree.t X) (l: list positive)
: option (list X) :=
  match l with
    | nil => Some nil
    | p::l' =>
      do x <- m ! p ;
      do r <- m ¡ l';
      Some (x :: r)
  end
where "m ¡ l" := (get_list m l).

Fixpoint fold_left2 {A B C: Type} (f: ABCA) (z: A) (u: list B) (v: list C) : A :=
  match u, v with
    | b::u', c::v' => fold_left2 f (f z b c) u' v'
    | _, _ => z
  end.

Fixpoint fold_right2 {A B C: Type} (f: ABCA) (z: A) (u: list B) (v: list C) : A :=
  match u, v with
    | b::u', c::v' => f (fold_right2 f z u' v') b c
    | _, _ => z
  end.

Class EqDec {X: Type} :=
{ eq_dec: ∀ x y: X, { x = y } + { xy }
}.

Definition upd `{X: Type} `{EqDec X} {Y} (f: XY) p (v:Y) := fun q => if eq_dec p q then v else f q.

Lemma upd_s `{X: Type} `{EqDec X} {Y} (f: XY) p v:
  (upd f p v) p = v.
Proof.
unfold upd. case (eq_dec p p); tauto. Qed.

Lemma upd_o `{X: Type} `{EqDec X} {Y} (f: XY) p v p' :
  pp' → (upd f p v) p' = f p'.
Proof.
unfold upd. case (eq_dec p p'); tauto. Qed.

Ltac eq_case :=
  match goal with |- appcontext[ @eq_dec _ _ ?x ?y ] => case (eq_dec x y) end.

Instance ZEqDec : @EqDec Z := Build_EqDec Z_eq_dec.
Instance PosEqDec : @EqDec positive := Build_EqDec peq.
Instance IntEqDec : @EqDec Integers.int := Build_EqDec _.
Proof.
  intros x y; generalize (Integers.Int.eq_spec x y).
  now destruct (Integers.Int.eq x y); auto.
Defined.
Instance PtrEqDec : @EqDec Pointers.pointer := Build_EqDec _.
Proof.
  intros [u i] [v j].
  case (eq_dec u v).
    intros <-. case (eq_dec i j). now intros <-; left.
    intros K; right; intros L. clarify.
  right; intros ?; clarify.
Defined.

Section OPT_MAP.

  Context {A B: Type}.
  Variable (f: Aoption B).

  Definition opt_map' (l: list A) : option (list B) → option (list B) :=
    fold_left (fun l a => do b <- f a; do l' <- l; Some (b::l')) l.

  Definition opt_map (l: list A) : option (list B) := opt_map' l (Some nil).

  Lemma opt_map'_none l: opt_map' l None = None.
Proof.
induction l as [| x l IH]. reflexivity.
         simpl. case (f x); easy.
  Qed.

  Lemma opt_map_none (l: list A) :
    opt_map l = None → ∃a, In a lf a = None.
Proof.
    unfold opt_map.
    generalize ((@nil B)).
    induction l as [| a l IH]. inversion 1.
    simpl.
    case_eq (f a); simpl.
      intros b Hb.
      intros m Hm. destruct (IH _ Hm) as [x (H & K)].
      exists x. tauto.
    intros H m Hb.
    exists a. tauto.
  Qed.

  Lemma opt_map_some (l: list A) :
    opt_map lNone → ∀a, In a lf aNone.
Proof.
    unfold opt_map.
    generalize (@nil B).
    induction l as [| a l IH]. tauto.
    simpl.
    case_eq (f a); simpl.
      intros b Hb.
      intros m Hm u [->|Hu]. congruence.
      now eapply IH; eauto.
    rewrite opt_map'_none. congruence.
  Qed.

End OPT_MAP.

Ltac andb' a b :=
  match goal with
    | [H: is_true (_ && _) |- _ ] => unfold is_true in H; andb' a b
    | [H: _ && _ = true |- _ ] => apply andb_true_iff in H; destruct H as [a b]
  end.

Tactic Notation "andb" "as" ident(a) ident(b) := andb' a b.
Tactic Notation "andb" := let a := fresh "L" in let b := fresh "R" in andb' a b.