Section Linearizability.
Variable K : Type.
Variable K_eq_dec : forall x y : K, {x = y} + {x <> y}.
Inductive op : Type :=
| I : K -> op
| O : K -> op.
Definition op_eq_dec :
forall x y : op, {x = y} + {x <> y}.
Proof using K_eq_dec.
decide equality.
Qed.
Inductive IR : Type :=
| IRI : K -> IR
| IRO : K -> IR
| IRU : K -> IR.
Definition IR_eq_dec :
forall x y : IR, {x = y} + {x <> y}.
Proof using K_eq_dec.
decide equality.
Qed.
(* Hypothesis trace_NoDup : NoDup trace. *)
(* also maybe: no Us *)
(* alse maybe: every O has corresponding I before it *)
Definition acknowledged_op (k : K) (trace : list op) :=
In (O k) trace.
Definition acknowledged_op_dec (k : K) (tr : list op) : {acknowledged_op k tr} + {~acknowledged_op k tr} :=
in_dec op_eq_dec (O k) tr.
Inductive acknowledge_all_ops : list op ->  list IR -> Prop :=
| AAO_nil : acknowledge_all_ops [] []
| AAO_IU : forall k tr out,
~ acknowledged_op k tr ->
acknowledge_all_ops tr out ->
acknowledge_all_ops (I k :: tr) (IRI k :: IRU k :: out)
| AAO_I_dorp : forall k tr out,
~ acknowledged_op k tr ->
acknowledge_all_ops tr out ->
acknowledge_all_ops (I k :: tr) out
| AAO_IO : forall k tr out,
acknowledged_op k tr ->
acknowledge_all_ops tr out ->
acknowledge_all_ops (I k :: tr) (IRI k :: out)
| AAO_O : forall k tr out,
acknowledge_all_ops tr out ->
acknowledge_all_ops (O k :: tr) (IRO k :: out).
Proof using.
induction 1; intros; simpl in *; intuition (auto; congruence).
Qed.
Fixpoint acknowledge_all_ops_func (l : list op) (target : list IR) : list IR :=
match l with
| [] => []
| x :: xs => match x with
| I k => if acknowledged_op_dec k xs
then IRI k :: acknowledge_all_ops_func xs target
else if in_dec IR_eq_dec (IRU k) target
then IRI k :: IRU k :: acknowledge_all_ops_func xs target
else acknowledge_all_ops_func xs target
| O k => IRO k :: acknowledge_all_ops_func xs target
end
end.
Hint Constructors acknowledge_all_ops : core.
Proof using.
intros.
unfold acknowledge_all_ops_func. repeat break_match; auto.
Qed.
Proof using.
induction l; intros; simpl; repeat break_match; subst; eauto.
Qed.
Proof using.
induction l; simpl in *; repeat break_match; subst; intuition eauto using f_equal.
repeat break_match; eauto using f_equal; solve [exfalso; eauto].
Qed.
Definition good_move (x y : IR) : Prop :=
(forall k k', ~ (x = IRO k /\ y = IRI k')) /\
(forall k, ~ (x = IRI k /\ y = IRO k)) /\
(forall k, ~ (x = IRI k /\ y = IRU k)).
Inductive IR_equivalent : list IR -> list IR -> Prop :=
| IR_equiv_nil : IR_equivalent [] []
| IR_equiv_cons : forall x xs ys,
IR_equivalent xs ys ->
IR_equivalent (x :: xs) (x :: ys)
| IR_equiv_move : forall x y xs ys,
IR_equivalent xs ys ->
good_move x y ->
IR_equivalent (x :: y :: xs) (y :: x :: ys)
| IR_equiv_trans : forall l1 l2 l3,
IR_equivalent l1 l2 ->
IR_equivalent l2 l3 ->
IR_equivalent l1 l3.
Hint Constructors IR_equivalent : core.
Proof using.
induction l; eauto.
Qed.
Proof using.
induction 1; intros; simpl in *; intuition.
Qed.
Proof using.
induction 1; intros; simpl in *; intuition.
Qed.
Hint Constructors Permutation : core.
Proof using.
induction 1; eauto.
Qed.

Lemma IR_equiv_app_head :
forall l xs ys,
IR_equivalent xs ys ->
IR_equivalent (l ++ xs) (l ++ ys).