Definition Time := nat.Parameter (Loc : Type) (L_eq : EqDec Loc).Definition Val := val.Definition Event := (Loc * Val * Time)%type.Definition View := Loc -> option Time.Definition Msg := (Event * View)%type.Parameters (ThreadId : Type) (T_eq : EqDec ThreadId).Definition State := (list Msg * (ThreadId -> option View) * View)%type.Inductive Op := Read_NA (l : Loc) (v : Val) | Read_A (l : Loc) (v : Val)
              | Write_NA (l : Loc) (v : Val) | Write_R (l : Loc) (v : Val).Inductive Op := Read_NA (l : Loc) (v : Val) | Read_A (l : Loc) (v : Val)
              | Write_NA (l : Loc) (v : Val) | Write_R (l : Loc) (v : Val).Inductive Op := Read_NA (l : Loc) (v : Val) | Read_A (l : Loc) (v : Val)
              | Write_NA (l : Loc) (v : Val) | Write_R (l : Loc) (v : Val).Inductive Op := Read_NA (l : Loc) (v : Val) | Read_A (l : Loc) (v : Val)
              | Write_NA (l : Loc) (v : Val) | Write_R (l : Loc) (v : Val).Inductive Op := Read_NA (l : Loc) (v : Val) | Read_A (l : Loc) (v : Val)
              | Write_NA (l : Loc) (v : Val) | Write_R (l : Loc) (v : Val).Definition upd {A B} {A_eq : EqDec A} (f : A -> option B) a b c := if eq_dec c a then Some b else f c.Definition join (V1 V2 : View) l := match V1 l, V2 l with
| Some a, Some b => Some (max a b)
| Some a, _ | _, Some a => Some a
| None, None => None end.Definition option_le t1 t2 := match t1, t2 with
| Some a, Some b => a <= b
| None, _ => True
| _, None => False end.Definition option_lt t1 t2 := match t1, t2 with
| Some a, Some b => a < b
| None, _ => True
| _, None => False end.Inductive step : State -> Op -> ThreadId -> State -> Prop :=
| sRead_A M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t)) :
    step (M, T, N) (Read_A l v) p (M, upd T p (join Vt V), N)
| sRead_NA M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t))
    (Hlast : forall v' t' V', In ((l, v', t'), V') M -> option_le (Some t') (Vt l)) :
    step (M, T, N) (Read_NA l v) p (M, upd T p (join Vt V), N)
| sWrite_R M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (Ht : option_lt (Vt l) (Some t)) (HV' : V' = upd Vt l t) :
    step (M, T, N) (Write_R l v) p (((l, v, t), V') :: M, upd T p V', N)
| sWrite_NA M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (HV' : V' = upd Vt l t) (Ht : forall v' t' V, In ((l, v', t'), V) M -> t' < t) :
    step (M, T, N) (Write_NA l v) p (((l, v, t), V') :: M, upd T p V', N).Inductive step : State -> Op -> ThreadId -> State -> Prop :=
| sRead_A M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t)) :
    step (M, T, N) (Read_A l v) p (M, upd T p (join Vt V), N)
| sRead_NA M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t))
    (Hlast : forall v' t' V', In ((l, v', t'), V') M -> option_le (Some t') (Vt l)) :
    step (M, T, N) (Read_NA l v) p (M, upd T p (join Vt V), N)
| sWrite_R M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (Ht : option_lt (Vt l) (Some t)) (HV' : V' = upd Vt l t) :
    step (M, T, N) (Write_R l v) p (((l, v, t), V') :: M, upd T p V', N)
| sWrite_NA M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (HV' : V' = upd Vt l t) (Ht : forall v' t' V, In ((l, v', t'), V) M -> t' < t) :
    step (M, T, N) (Write_NA l v) p (((l, v, t), V') :: M, upd T p V', N).Inductive step : State -> Op -> ThreadId -> State -> Prop :=
| sRead_A M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t)) :
    step (M, T, N) (Read_A l v) p (M, upd T p (join Vt V), N)
| sRead_NA M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t))
    (Hlast : forall v' t' V', In ((l, v', t'), V') M -> option_le (Some t') (Vt l)) :
    step (M, T, N) (Read_NA l v) p (M, upd T p (join Vt V), N)
| sWrite_R M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (Ht : option_lt (Vt l) (Some t)) (HV' : V' = upd Vt l t) :
    step (M, T, N) (Write_R l v) p (((l, v, t), V') :: M, upd T p V', N)
| sWrite_NA M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (HV' : V' = upd Vt l t) (Ht : forall v' t' V, In ((l, v', t'), V) M -> t' < t) :
    step (M, T, N) (Write_NA l v) p (((l, v, t), V') :: M, upd T p V', N).Inductive step : State -> Op -> ThreadId -> State -> Prop :=
| sRead_A M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t)) :
    step (M, T, N) (Read_A l v) p (M, upd T p (join Vt V), N)
| sRead_NA M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t))
    (Hlast : forall v' t' V', In ((l, v', t'), V') M -> option_le (Some t') (Vt l)) :
    step (M, T, N) (Read_NA l v) p (M, upd T p (join Vt V), N)
| sWrite_R M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (Ht : option_lt (Vt l) (Some t)) (HV' : V' = upd Vt l t) :
    step (M, T, N) (Write_R l v) p (((l, v, t), V') :: M, upd T p V', N)
| sWrite_NA M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (HV' : V' = upd Vt l t) (Ht : forall v' t' V, In ((l, v', t'), V) M -> t' < t) :
    step (M, T, N) (Write_NA l v) p (((l, v, t), V') :: M, upd T p V', N).Inductive step : State -> Op -> ThreadId -> State -> Prop :=
| sRead_A M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t)) :
    step (M, T, N) (Read_A l v) p (M, upd T p (join Vt V), N)
| sRead_NA M T N l v t p V Vt (HM : In ((l, v, t), V) M) (Hp : T p = Some Vt) (Ht : option_le (Vt l) (Some t))
    (Hlast : forall v' t' V', In ((l, v', t'), V') M -> option_le (Some t') (Vt l)) :
    step (M, T, N) (Read_NA l v) p (M, upd T p (join Vt V), N)
| sWrite_R M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (Ht : option_lt (Vt l) (Some t)) (HV' : V' = upd Vt l t) :
    step (M, T, N) (Write_R l v) p (((l, v, t), V') :: M, upd T p V', N)
| sWrite_NA M T N l v t p Vt V' (HM : ~exists v' V, In ((l, v', t), V) M) (Hp : T p = Some Vt)
    (HN : option_le (N l) (Vt l))
    (HV' : V' = upd Vt l t) (Ht : forall v' t' V, In ((l, v', t'), V) M -> t' < t) :
    step (M, T, N) (Write_NA l v) p (((l, v, t), V') :: M, upd T p V', N).

Lemma remove_old_NA_write : forall M1 M2 T N l v t V v' t' V' op p M1' M2' T' N' (Hop : match op with Read_NA _ _ | Write_NA _ _ => True | _ => False end) (Hin : In ((l, v', t'), V') (M1 ++ M2)) (Hnew : t < t'), step (M1 ++ ((l, v, t), V) :: M2, T, N) op p (M1' ++ ((l, v, t), V) :: M2', T', N') <-> step (M1 ++ M2, T, N) op p (M1' ++ M2', T', N').