frap/SharedMemory.v

1617 lines
39 KiB
Coq
Raw Normal View History

(** Formal Reasoning About Programs <http://adam.chlipala.net/frap/>
* Chapter 13: Operational Semantics for Shared-Memory Concurrency
* Author: Adam Chlipala
* License: https://creativecommons.org/licenses/by-nc-nd/4.0/ *)
Require Import Frap.
Set Implicit Arguments.
Set Asymmetric Patterns.
(** * Shared notations and definitions; main material starts afterward. *)
Notation "m $! k" := (match m $? k with Some n => n | None => O end) (at level 30).
Definition heap := fmap nat nat.
Definition assertion := heap -> Prop.
Hint Extern 1 (_ <= _) => linear_arithmetic.
Hint Extern 1 (@eq nat _ _) => linear_arithmetic.
Ltac simp := repeat (simplify; subst; propositional;
try match goal with
| [ H : ex _ |- _ ] => invert H
end); try linear_arithmetic.
(** * An object language with shared-memory concurrency *)
(* Let's simplify the encoding by only working with commands that generate
* [nat]. *)
Inductive loop_outcome :=
| Done (a : nat)
| Again (a : nat).
Inductive cmd :=
| Return (r : nat)
| Bind (c1 : cmd) (c2 : nat -> cmd)
| Read (a : nat)
| Write (a v : nat)
| Fail
(* Now here's the new part: parallel composition of commands. *)
| Par (c1 c2 : cmd)
(* Let's also add locking commands, where locks are named by [nat]s. *)
| Lock (a : nat)
| Unlock (a : nat).
Notation "x <- c1 ; c2" := (Bind c1 (fun x => c2)) (right associativity, at level 80).
Infix "||" := Par.
Definition locks := set nat.
Inductive step : heap * locks * cmd -> heap * locks * cmd -> Prop :=
| StepBindRecur : forall c1 c1' c2 h h' l l',
step (h, l, c1) (h', l', c1')
-> step (h, l, Bind c1 c2) (h', l', Bind c1' c2)
| StepBindProceed : forall v c2 h l,
step (h, l, Bind (Return v) c2) (h, l, c2 v)
| StepRead : forall h l a,
step (h, l, Read a) (h, l, Return (h $! a))
| StepWrite : forall h l a v,
step (h, l, Write a v) (h $+ (a, v), l, Return 0)
| StepParRecur1 : forall h l c1 c2 h' l' c1',
step (h, l, c1) (h', l', c1')
-> step (h, l, Par c1 c2) (h', l', Par c1' c2)
| StepParRecur2 : forall h l c1 c2 h' l' c2',
step (h, l, c2) (h', l', c2')
-> step (h, l, Par c1 c2) (h', l', Par c1 c2')
| StepLock : forall h l a,
~a \in l
-> step (h, l, Lock a) (h, l \cup {a}, Return 0)
| StepUnlock : forall h l a,
a \in l
-> step (h, l, Unlock a) (h, l \setminus {a}, Return 0).
Definition trsys_of (h : heap) (l : locks) (c : cmd) := {|
Initial := {(h, l, c)};
Step := step
|}.
Example two_increments_thread :=
_ <- Lock 0;
n <- Read 0;
if n <=? 1 then
_ <- Write 0 (n + 1);
Unlock 0
2016-04-21 23:12:02 +00:00
else
Fail.
Example two_increments := two_increments_thread || two_increments_thread.
2016-04-22 00:35:34 +00:00
Fixpoint notAboutToFail (c : cmd) : bool :=
2016-04-21 23:12:02 +00:00
match c with
2016-04-22 00:35:34 +00:00
| Fail => false
2016-04-21 23:12:02 +00:00
| Bind c1 _ => notAboutToFail c1
2016-04-22 00:35:34 +00:00
| Par c1 c2 => notAboutToFail c1 && notAboutToFail c2
| _ => true
2016-04-21 23:12:02 +00:00
end.
Theorem two_increments_ok :
invariantFor (trsys_of $0 {} two_increments)
2016-04-21 23:12:02 +00:00
(fun p => let '(_, _, c) := p in
2016-04-22 00:35:34 +00:00
notAboutToFail c = true).
Proof.
2016-04-22 22:25:07 +00:00
Admitted.
(* unfold two_increments, two_increments_thread.
simplify.
eapply invariant_weaken.
apply multiStepClosure_ok; simplify.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_done.
simplify.
2016-04-22 00:35:34 +00:00
propositional; subst; equality.
2016-04-22 22:25:07 +00:00
Qed.*)
2016-04-21 23:12:02 +00:00
(** * Optimization #1: always run all purely local actions first. *)
Fixpoint runLocal (c : cmd) : cmd :=
match c with
| Return _ => c
| Bind c1 c2 =>
match runLocal c1 with
| Return v => runLocal (c2 v)
| c1' => Bind c1' c2
end
| Read _ => c
| Write _ _ => c
| Fail => c
| Par c1 c2 => Par (runLocal c1) (runLocal c2)
2016-04-21 23:12:02 +00:00
| Lock _ => c
| Unlock _ => c
end.
Inductive stepL : heap * locks * cmd -> heap * locks * cmd -> Prop :=
| StepL : forall h l c h' l' c',
step (h, l, c) (h', l', c')
-> stepL (h, l, c) (h', l', runLocal c').
Definition trsys_ofL (h : heap) (l : locks) (c : cmd) := {|
Initial := {(h, l, runLocal c)};
Step := stepL
|}.
Hint Constructors step stepL.
Lemma run_Return : forall h l r h' l' c,
step^* (h, l, Return r) (h', l', c)
-> h' = h /\ l' = l /\ c = Return r.
Proof.
induct 1; eauto.
invert H.
Qed.
Lemma run_Bind : forall h l c1 c2 h' l' c',
step^* (h, l, Bind c1 c2) (h', l', c')
-> (exists c1', step^* (h, l, c1) (h', l', c1')
/\ c' = Bind c1' c2)
\/ (exists h'' l'' r, step^* (h, l, c1) (h'', l'', Return r)
/\ step^* (h'', l'', c2 r) (h', l', c')).
Proof.
induct 1; eauto.
invert H; eauto 10.
Ltac inst H :=
repeat match type of H with
| _ = _ -> _ => specialize (H eq_refl)
| forall x : ?T, _ =>
let y := fresh in evar (y : T); let y' := eval unfold y in y in
specialize (H y'); clear y
end.
inst IHtrc.
first_order; eauto 10.
Qed.
Lemma StepBindRecur_star : forall c1 c1' c2 h h' l l',
step^* (h, l, c1) (h', l', c1')
-> step^* (h, l, Bind c1 c2) (h', l', Bind c1' c2).
Proof.
induct 1; eauto.
cases y.
cases p.
eauto.
Qed.
Lemma StepParRecur1_star : forall h l c1 c2 h' l' c1',
step^* (h, l, c1) (h', l', c1')
-> step^* (h, l, Par c1 c2) (h', l', Par c1' c2).
Proof.
induct 1; eauto.
cases y.
cases p.
eauto.
Qed.
Lemma StepParRecur2_star : forall h l c1 c2 h' l' c2',
step^* (h, l, c2) (h', l', c2')
-> step^* (h, l, Par c1 c2) (h', l', Par c1 c2').
Proof.
induct 1; eauto.
cases y.
cases p.
eauto.
Qed.
Hint Resolve StepBindRecur_star StepParRecur1_star StepParRecur2_star.
Lemma runLocal_idem : forall c, runLocal (runLocal c) = runLocal c.
Proof.
induct c; simplify; eauto.
cases (runLocal c); simplify; eauto.
rewrite IHc; auto.
rewrite IHc; auto.
equality.
2016-04-22 00:35:34 +00:00
Qed.
2016-04-21 23:12:02 +00:00
Lemma step_runLocal : forall h l c h' l' c',
step (h, l, c) (h', l', c')
-> (runLocal c = runLocal c' /\ h = h' /\ l = l')
\/ exists c'', step (h, l, runLocal c) (h', l', c'')
/\ runLocal c'' = runLocal c'.
Proof.
induct 1; simplify; first_order; eauto.
rewrite H0; equality.
cases (runLocal c1).
invert H0.
rewrite <- H1; eauto.
rewrite <- H1; eauto.
rewrite <- H1; eauto.
rewrite <- H1; eauto.
rewrite <- H1; eauto.
rewrite <- H1; eauto.
rewrite <- H1; eauto.
rewrite H0; equality.
right; eexists; propositional.
2016-04-21 23:12:02 +00:00
eauto.
simplify.
rewrite runLocal_idem; equality.
2016-04-21 23:12:02 +00:00
equality.
right; eexists; propositional.
2016-04-21 23:12:02 +00:00
eauto.
simplify.
rewrite runLocal_idem; equality.
2016-04-21 23:12:02 +00:00
Qed.
Lemma step_stepL' : forall h l c h' l' c',
step^* (h, l, c) (h', l', c')
-> stepL^* (h, l, runLocal c) (h', l', runLocal c').
Proof.
induct 1; simplify; eauto.
cases y.
cases p.
inst IHtrc.
apply step_runLocal in H; first_order; subst.
rewrite H; eauto.
econstructor.
econstructor.
eauto.
equality.
Qed.
Theorem notAboutToFail_runLocal : forall c,
2016-04-22 00:35:34 +00:00
notAboutToFail (runLocal c) = true
-> notAboutToFail c = true.
2016-04-21 23:12:02 +00:00
Proof.
induct c; simplify; auto.
cases (runLocal c); simplify; auto.
2016-04-22 21:58:14 +00:00
cases (runLocal c1); simplify; auto; propositional;
repeat match goal with
| [ H : _ |- _ ] => apply andb_true_iff in H; propositional
| [ H : _ = _ |- _ ] => rewrite H
end; try equality.
2016-04-21 23:12:02 +00:00
Qed.
Theorem step_stepL : forall h l c ,
invariantFor (trsys_ofL h l c) (fun p => let '(_, _, c) := p in
2016-04-22 00:35:34 +00:00
notAboutToFail c = true)
2016-04-21 23:12:02 +00:00
-> invariantFor (trsys_of h l c) (fun p =>
let '(_, _, c) := p in
2016-04-22 00:35:34 +00:00
notAboutToFail c = true).
2016-04-21 23:12:02 +00:00
Proof.
unfold invariantFor; simplify.
propositional; subst.
cases s'.
cases p.
apply step_stepL' in H1.
apply H in H1; eauto using notAboutToFail_runLocal.
Qed.
Theorem two_increments_ok_again :
invariantFor (trsys_of $0 {} two_increments)
(fun p => let '(_, _, c) := p in
2016-04-22 00:35:34 +00:00
notAboutToFail c = true).
2016-04-21 23:12:02 +00:00
Proof.
2016-04-22 22:25:07 +00:00
Admitted.
(* apply step_stepL.
2016-04-21 23:12:02 +00:00
unfold two_increments, two_increments_thread.
simplify.
eapply invariant_weaken.
apply multiStepClosure_ok; simplify.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_done.
2016-04-22 22:25:07 +00:00
simplify.
propositional; subst; equality.
Qed.*)
(** * Optimization #2: partial-order reduction *)
Example independent_threads :=
2016-04-22 23:11:42 +00:00
(a <- Read 0;
_ <- Write 1 (a + 1);
a <- Read 1;
if a ==n 1 then
Return 0
else
Fail)
|| (b <- Read 2;
Write 2 (b + 1)).
2016-04-22 22:25:07 +00:00
Theorem independent_threads_ok :
invariantFor (trsys_of $0 {} independent_threads)
(fun p => let '(_, _, c) := p in
notAboutToFail c = true).
Proof.
2016-04-22 23:11:42 +00:00
Admitted.
(* apply step_stepL.
2016-04-22 22:25:07 +00:00
unfold independent_threads.
simplify.
eapply invariant_weaken.
apply multiStepClosure_ok; simplify.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_step.
model_check_done.
simplify.
2016-04-22 00:35:34 +00:00
propositional; subst; equality.
2016-04-22 23:11:42 +00:00
Qed.*)
Record summary := {
Reads : set nat;
Writes : set nat;
Locks : set nat
}.
Inductive summarize : cmd -> summary -> Prop :=
| SumReturn : forall r s,
summarize (Return r) s
| SumFail : forall s,
summarize Fail s
| SumBind : forall c1 c2 s,
summarize c1 s
-> (forall r, summarize (c2 r) s)
-> summarize (Bind c1 c2) s
| SumRead : forall a s,
a \in s.(Reads)
-> summarize (Read a) s
| SumWrite : forall a v s,
a \in s.(Writes)
-> summarize (Write a v) s
| SumLock : forall a s,
a \in s.(Locks)
-> summarize (Lock a) s
| SumUnlock : forall a s,
a \in s.(Locks)
-> summarize (Unlock a) s.
Inductive summarizeThreads : cmd -> list (cmd * summary) -> Prop :=
| StPar : forall c1 c2 ss1 ss2,
summarizeThreads c1 ss1
-> summarizeThreads c2 ss2
-> summarizeThreads (Par c1 c2) (ss1 ++ ss2)
| StAtomic : forall c s,
summarize c s
-> summarizeThreads c [(c, s)].
2016-04-22 23:11:42 +00:00
Inductive nextAction : cmd -> cmd -> Prop :=
| NaReturn : forall r,
nextAction (Return r) (Return r)
| NaFail :
nextAction Fail Fail
2016-04-22 23:11:42 +00:00
| NaRead : forall a,
nextAction (Read a) (Read a)
| NaWrite : forall a v,
nextAction (Write a v) (Write a v)
| NaLock : forall l,
nextAction (Lock l) (Lock l)
| NaUnlock : forall l,
nextAction (Unlock l) (Unlock l)
| NaBind : forall c1 c2 c,
nextAction c1 c
-> nextAction (Bind c1 c2) c.
Definition commutes (c : cmd) (s : summary) : Prop :=
match c with
| Return _ => True
| Fail => True
| Read a => ~a \in s.(Writes)
| Write a _ => ~a \in s.(Reads) \cup s.(Writes)
| Lock a => ~a \in s.(Locks)
| Unlock a => ~a \in s.(Locks)
| _ => False
end.
Inductive stepC : heap * locks * list (cmd * summary) -> heap * locks * list (cmd * summary) -> Prop :=
| StepFirst : forall h l c h' l' c' s cs,
step (h, l, c) (h', l', c')
-> stepC (h, l, (c, s) :: cs) (h', l', (c', s) :: cs)
| StepAny : forall h l c h' l' s cs1 c1 s1 cs2 c1',
(forall c0 h'' l'' c'', nextAction c c0
-> List.Forall (fun c_s => commutes c0 (snd c_s)) (cs1 ++ (c1, s1) :: cs2)
-> step (h, l, c) (h'', l'', c'')
-> False)
-> step (h, l, c1) (h', l', c1')
-> stepC (h, l, (c, s) :: cs1 ++ (c1, s1) :: cs2) (h', l', (c, s) :: cs1 ++ (c1', s1) :: cs2).
Definition trsys_ofC (h : heap) (l : locks) (cs : list (cmd * summary)) := {|
Initial := {(h, l, cs)};
Step := stepC
|}.
Lemma commutes_sound' : forall h l c2 h' l' c2',
2016-04-22 23:11:42 +00:00
step (h, l, c2) (h', l', c2')
-> forall s c1 h'' l'' c1', step (h', l', c1) (h'', l'', c1')
-> summarize c2 s
-> commutes c1 s
2016-04-22 23:11:42 +00:00
-> exists h1 l1, step (h, l, c1) (h1, l1, c1')
/\ step (h1, l1, c2) (h'', l'', c2').
Proof.
induct 1; simplify; eauto.
invert H1.
eapply IHstep in H0; eauto; first_order.
2016-04-22 23:11:42 +00:00
eauto.
invert H0; invert H; simplify; propositional; eauto.
2016-04-22 23:11:42 +00:00
do 2 eexists; propositional.
eauto.
assert (a <> a0) by sets.
replace (h' $! a) with (h' $+ (a0, v) $! a) by (simplify; equality).
2016-04-22 23:11:42 +00:00
eauto.
invert H0; invert H; simplify; propositional; eauto.
2016-04-22 23:11:42 +00:00
do 2 eexists; propositional.
eauto.
assert (a <> a0) by sets.
replace (h $+ (a, v) $+ (a0, v0)) with (h $+ (a0, v0) $+ (a, v)) by maps_equal.
2016-04-22 23:11:42 +00:00
eauto.
invert H1.
invert H1.
invert H1; invert H0; simplify; propositional; eauto.
2016-04-22 23:11:42 +00:00
do 2 eexists; propositional.
constructor.
sets.
replace ((l \cup {a}) \cup {a0}) with ((l \cup {a0}) \cup {a}) by sets.
2016-04-22 23:11:42 +00:00
constructor.
sets.
do 2 eexists; propositional.
constructor.
sets; propositional.
replace (l \cup {a} \setminus {a0}) with ((l \setminus {a0}) \cup {a}) by sets.
2016-04-22 23:11:42 +00:00
constructor.
sets.
invert H1; invert H0; simplify; propositional; eauto.
2016-04-22 23:11:42 +00:00
do 2 eexists; propositional.
constructor.
sets.
replace ((l \setminus {a}) \cup {a0}) with ((l \cup {a0}) \setminus {a}) by sets.
2016-04-22 23:11:42 +00:00
constructor.
sets.
do 2 eexists; propositional.
constructor.
sets; propositional.
replace ((l \setminus {a}) \setminus {a0}) with ((l \setminus {a0}) \setminus {a}) by sets.
2016-04-22 23:11:42 +00:00
constructor.
sets.
Qed.
Lemma step_nextAction_Return : forall r h l c h' l' c',
step (h, l, c) (h', l', c')
-> nextAction c (Return r)
-> h' = h /\ l' = l /\ (forall h'' l'', step (h'', l'', c) (h'', l'', c')).
Proof.
induct 1; invert 1; propositional; eauto.
Qed.
Lemma step_nextAction_other : forall c0 h l c h' l' c',
step (h, l, c) (h', l', c')
-> nextAction c c0
-> (forall r, c0 <> Return r)
-> exists f c0', step (h, l, c0) (h', l', c0')
/\ c = f c0
/\ c' = f c0'
/\ forall h1 l1 h2 l2 c0'', step (h1, l1, c0) (h2, l2, c0'')
-> step (h1, l1, f c0) (h2, l2, f c0'').
Proof.
induct 1; invert 1; first_order; subst; eauto.
exists (fun X => x <- x X; c2 x); eauto 10.
invert H3.
unfold not in *; exfalso; eauto.
exists (fun X => X); eauto.
exists (fun X => X); eauto.
exists (fun X => X); eauto 10.
exists (fun X => X); eauto 10.
Qed.
Lemma nextAction_couldBe : forall c c0,
nextAction c c0
-> match c0 with
| Return _ => True
| Fail => True
| Read _ => True
| Write _ _ => True
| Lock _ => True
| Unlock _ => True
| _ => False
end.
Proof.
induct 1; auto.
Qed.
Lemma commutes_sound : forall h l c2 h' l' c2',
step (h, l, c2) (h', l', c2')
-> forall s c1 c0 h'' l'' c1', step (h', l', c1) (h'', l'', c1')
-> summarize c2 s
-> nextAction c1 c0
-> commutes c0 s
-> exists h1 l1, step (h, l, c1) (h1, l1, c1')
/\ step (h1, l1, c2) (h'', l'', c2').
Proof.
simplify.
assert (Hc : commutes c0 s) by assumption.
specialize (nextAction_couldBe H2).
cases c0; propositional.
assert (Hs : step (h', l', c1) (h'', l'', c1')) by assumption.
eapply step_nextAction_Return in H0; eauto; propositional; subst.
eauto.
eapply step_nextAction_other in H0; eauto; first_order; subst; try equality.
eapply commutes_sound' with (c2 := c2) (c1 := Read a) in H3; eauto.
first_order; eauto.
eapply step_nextAction_other in H0; eauto; first_order; subst; try equality.
eapply commutes_sound' with (c2 := c2) (c1 := Write a v) in H3; eauto.
first_order; eauto.
eapply step_nextAction_other in H0; eauto; first_order; subst; try equality.
invert H0.
eapply step_nextAction_other in H0; eauto; first_order; subst; try equality.
eapply commutes_sound' with (c2 := c2) (c1 := Lock a) in H3; eauto.
first_order; eauto.
eapply step_nextAction_other in H0; eauto; first_order; subst; try equality.
eapply commutes_sound' with (c2 := c2) (c1 := Unlock a) in H3; eauto.
first_order; eauto.
Qed.
Hint Constructors summarize.
2016-04-22 23:11:42 +00:00
Lemma summarize_step : forall h l c h' l' c' s,
step (h, l, c) (h', l', c')
-> summarize c s
-> summarize c' s.
Proof.
induct 1; invert 1; simplify; eauto.
Qed.
Lemma summarize_steps : forall h l c h' l' c' s,
step^* (h, l, c) (h', l', c')
-> summarize c s
-> summarize c' s.
Proof.
induct 1; eauto.
cases y.
cases p.
eauto using summarize_step.
Qed.
Fixpoint pow2 (n : nat) : nat :=
match n with
| O => 1
| S n' => pow2 n' * 2
end.
Inductive boundRunningTime : cmd -> nat -> Prop :=
| BrtReturn : forall r n,
boundRunningTime (Return r) n
| BrtFail : forall n,
boundRunningTime Fail n
| BrtRead : forall a n,
boundRunningTime (Read a) (S n)
| BrtWrite : forall a v n,
boundRunningTime (Write a v) (S n)
| BrtLock : forall a n,
boundRunningTime (Lock a) (S n)
| BrtUnlock : forall a n,
boundRunningTime (Unlock a) (S n)
| BrtBind : forall c1 c2 n1 n2,
boundRunningTime c1 n1
-> (forall r, boundRunningTime (c2 r) n2)
-> boundRunningTime (Bind c1 c2) (S (n1 + n2))
| BrtPar : forall c1 c2 n1 n2,
boundRunningTime c1 n1
-> boundRunningTime c2 n2
-> boundRunningTime (Par c1 c2) (pow2 (n1 + n2)).
Theorem boundRunningTime_not_total : exists c, forall n, ~boundRunningTime c n.
Proof.
Fixpoint scribbly (n : nat) : cmd :=
match n with
| O => Return 0
| S n' => _ <- Write n' 0; scribbly n'
end.
Lemma scribbly_time : forall n m,
boundRunningTime (scribbly n) m
-> m >= n.
Proof.
induct n; invert 1; auto.
invert H2.
specialize (H4 n0).
apply IHn in H4.
linear_arithmetic.
Qed.
exists (n <- Read 0; scribbly n); propositional.
invert H.
specialize (H4 (S n2)).
apply scribbly_time in H4.
linear_arithmetic.
Qed.
Lemma pow2_pos : forall n,
pow2 n > 0.
Proof.
induct n; simplify; auto.
Qed.
Lemma pow2_mono : forall n m,
n < m
-> pow2 n < pow2 m.
Proof.
induct 1; simplify; auto.
specialize (pow2_pos n); linear_arithmetic.
Qed.
Hint Resolve pow2_mono.
Lemma pow2_incr : forall n,
n < pow2 n.
Proof.
induct n; simplify; auto.
Qed.
Hint Resolve pow2_incr.
Lemma pow2_inv : forall n m,
pow2 n <= m
-> n < m.
Proof.
simplify.
specialize (pow2_incr n).
linear_arithmetic.
Qed.
Lemma use_pow2 : forall n m k,
pow2 m <= S k
-> n <= m
-> n <= k.
Proof.
simplify.
apply pow2_inv in H.
linear_arithmetic.
Qed.
Lemma use_pow2' : forall n m k,
pow2 m <= S k
-> n < m
-> pow2 n <= k.
Proof.
simplify.
specialize (@pow2_mono n m).
linear_arithmetic.
Qed.
Hint Constructors boundRunningTime.
Lemma boundRunningTime_step : forall c n h l h' l',
boundRunningTime c n
-> forall c', step (h, l, c) (h', l', c')
-> exists n', boundRunningTime c' n' /\ n' < n.
2016-04-22 23:11:42 +00:00
Proof.
induct 1; invert 1; simplify; eauto.
apply IHboundRunningTime in H4; first_order; subst.
eexists; propositional.
eauto.
linear_arithmetic.
apply IHboundRunningTime1 in H3; first_order; subst.
eauto 6.
apply IHboundRunningTime2 in H3; first_order; subst.
eauto 6.
Qed.
Require Import Classical.
Theorem complete_trace : forall k c n,
boundRunningTime c n
-> n <= k
-> forall h l, exists h' l' c', step^* (h, l, c) (h', l', c')
/\ (forall h'' l'' c'',
step (h', l', c') (h'', l'', c'')
-> False).
Proof.
induct k; simplify.
invert H; try linear_arithmetic.
do 3 eexists; propositional.
eauto.
invert H.
do 3 eexists; propositional.
eauto.
invert H.
specialize (pow2_pos (n1 + n2)).
linear_arithmetic.
invert H.
do 3 eexists; propositional.
eauto.
invert H.
do 3 eexists; propositional.
eauto.
invert H.
do 3 eexists; propositional.
apply trc_one.
eauto.
invert H.
do 3 eexists; propositional.
apply trc_one.
eauto.
invert H.
destruct (classic (a \in l)).
do 3 eexists; propositional.
eauto.
invert H1.
sets.
do 3 eexists; propositional.
apply trc_one.
eauto.
invert H1.
destruct (classic (a \in l)).
do 3 eexists; propositional.
apply trc_one.
eauto.
invert H1.
do 3 eexists; propositional.
eauto.
invert H1.
sets.
eapply IHk in H1; eauto; first_order.
cases x1.
specialize (H2 r).
eapply IHk in H2; eauto; first_order.
do 3 eexists; propositional.
eapply trc_trans.
apply StepBindRecur_star.
eassumption.
eapply TrcFront.
eauto.
eassumption.
eauto.
do 3 eexists; propositional.
apply StepBindRecur_star.
eassumption.
invert H3.
eauto.
do 3 eexists; propositional.
apply StepBindRecur_star.
eassumption.
invert H3.
eauto.
do 3 eexists; propositional.
apply StepBindRecur_star.
eassumption.
invert H3.
eauto.
do 3 eexists; propositional.
apply StepBindRecur_star.
eassumption.
invert H3.
eauto.
do 3 eexists; propositional.
apply StepBindRecur_star.
eassumption.
invert H3.
eauto.
do 3 eexists; propositional.
apply StepBindRecur_star.
eassumption.
invert H3.
eauto.
do 3 eexists; propositional.
apply StepBindRecur_star.
eassumption.
invert H3.
eauto.
assert (Hb1 : boundRunningTime c1 n1) by assumption.
assert (Hb2 : boundRunningTime c2 n2) by assumption.
eapply IHk in H1; eauto using use_pow2; first_order.
invert H.
eapply IHk in H2; eauto using use_pow2; first_order.
invert H.
do 3 eexists; propositional.
eauto.
invert H; eauto.
cases y.
cases p.
specialize (boundRunningTime_step Hb2 H3); first_order.
assert (boundRunningTime (Par x1 c) (pow2 (n1 + x3))) by eauto.
eapply IHk in H6; eauto using use_pow2'; first_order.
do 3 eexists; propositional.
eapply TrcFront.
eauto.
eassumption.
eauto.
cases y.
cases p.
specialize (boundRunningTime_step Hb1 H3); first_order.
assert (boundRunningTime (Par c c2) (pow2 (x2 + n2))) by eauto.
eapply IHk in H6; eauto using use_pow2'; first_order.
do 3 eexists; propositional.
eapply TrcFront.
eauto.
eassumption.
eauto.
Qed.
Lemma notAboutToFail_step : forall h l c h' l' c',
step (h, l, c) (h', l', c')
-> notAboutToFail c = false
-> notAboutToFail c' = false.
Proof.
induct 1; simplify; eauto; try equality.
apply andb_false_iff in H0.
apply andb_false_iff.
propositional.
apply andb_false_iff in H0.
apply andb_false_iff.
propositional.
Qed.
Lemma notAboutToFail_steps : forall h l c h' l' c',
step^* (h, l, c) (h', l', c')
-> notAboutToFail c = false
-> notAboutToFail c' = false.
Proof.
induct 1; simplify; eauto.
cases y.
cases p.
eauto using notAboutToFail_step.
Qed.
Lemma boundRunningTime_steps : forall h l c h' l' c',
step^* (h, l, c) (h', l', c')
-> forall n, boundRunningTime c n
-> exists n', boundRunningTime c' n' /\ n' <= n.
Proof.
induct 1; simplify; eauto.
cases y.
cases p.
specialize (boundRunningTime_step H1 H); first_order.
eapply IHtrc in H2; eauto.
first_order.
eauto.
Qed.
Inductive stepsi : nat -> heap * locks * cmd -> heap * locks * cmd -> Prop :=
| StepsiO : forall st,
stepsi O st st
| StepsiS : forall st1 st2 st3 i,
step st1 st2
-> stepsi i st2 st3
-> stepsi (S i) st1 st3.
Hint Constructors stepsi.
Theorem steps_stepsi : forall st1 st2,
step^* st1 st2
-> exists i, stepsi i st1 st2.
Proof.
induct 1; first_order; eauto.
Qed.
Lemma Exists_app_fwd : forall A (P : A -> Prop) ls1 ls2,
Exists P (ls1 ++ ls2)
-> Exists P ls1 \/ Exists P ls2.
Proof.
induct ls1; invert 1; simplify; subst; eauto.
apply IHls1 in H1; propositional; eauto.
Qed.
Lemma Exists_app_bwd : forall A (P : A -> Prop) ls1 ls2,
Exists P ls1 \/ Exists P ls2
-> Exists P (ls1 ++ ls2).
Proof.
induct ls1; simplify; propositional; eauto.
invert H0.
invert H0; eauto.
Qed.
Lemma summarizeThreads_aboutToFail : forall c cs,
summarizeThreads c cs
-> notAboutToFail c = false
-> Exists (fun c_s => notAboutToFail (fst c_s) = false) cs.
Proof.
induct 1; simplify; eauto.
apply andb_false_iff in H1; propositional; eauto using Exists_app_bwd.
Qed.
Hint Resolve summarizeThreads_aboutToFail.
Lemma summarizeThreads_nonempty : forall c,
summarizeThreads c []
-> False.
Proof.
induct 1.
cases ss1; simplify; eauto.
equality.
Qed.
Hint Immediate summarizeThreads_nonempty.
Hint Constructors stepC summarizeThreads.
Lemma step_pick : forall h l c h' l' c',
step (h, l, c) (h', l', c')
-> forall cs, summarizeThreads c cs
-> exists cs1 c0 s cs2 c0', cs = cs1 ++ (c0, s) :: cs2
/\ step (h, l, c0) (h', l', c0')
/\ summarizeThreads c' (cs1 ++ (c0', s) :: cs2).
Proof.
induct 1; invert 1.
eexists [], _, _, [], _; simplify; propositional; eauto 10 using summarize_step.
eexists [], _, _, [], _; simplify; propositional; eauto 10 using summarize_step.
eexists [], _, _, [], _; simplify; propositional; eauto 10 using summarize_step.
eexists [], _, _, [], _; simplify; propositional; eauto 10 using summarize_step.
apply IHstep in H3; first_order; subst.
rewrite <- app_assoc.
simplify.
do 5 eexists; propositional.
eauto.
change (x ++ (x3, x1) :: x2 ++ ss2)
with (x ++ ((x3, x1) :: x2) ++ ss2).
rewrite app_assoc.
eauto.
invert H1.
apply IHstep in H5; first_order; subst.
rewrite app_assoc.
do 5 eexists; propositional.
eauto.
rewrite <- app_assoc.
eauto.
invert H1.
eexists [], _, _, [], _; simplify; propositional; eauto using summarize_step.
eexists [], _, _, [], _; simplify; propositional; eauto using summarize_step.
(* Here's a gnarly bit to make up for simplification in the proof above.
* Some existential variables weren't determined, but we can pick their values
* here. *)
Grab Existential Variables.
exact l'.
exact h'.
Qed.
Lemma translate_trace_matching : forall h l c h' l' c',
step (h, l, c) (h', l', c')
-> forall c0 s cs, summarizeThreads c ((c0, s) :: cs)
-> ~(exists c1 h'0 l'0 c'0,
nextAction c0 c1
/\ Forall (fun c_s => commutes c1 (snd c_s)) cs
/\ step (h, l, c0) (h'0, l'0, c'0))
-> exists cs', stepC (h, l, (c0, s) :: cs) (h', l', cs')
/\ summarizeThreads c' cs'.
Proof.
simplify.
eapply step_pick in H; eauto.
first_order; subst.
cases x; simplify.
invert H.
eauto.
invert H.
eauto 10.
Qed.
Lemma nextAction_det : forall c c0,
nextAction c c0
-> forall h l h' l' c', step (h, l, c) (h', l', c')
-> forall h'' l'' c'', step (h, l, c) (h'', l'', c'')
-> h' = h'' /\ l'' = l' /\ c'' = c'.
Proof.
induct 1; invert 1; invert 1; auto.
eapply IHnextAction in H2; eauto.
equality.
invert H2.
invert H2.
Qed.
Lemma split_center : forall A (x : A) l1 l2 r1 r2,
l1 ++ l2 = r1 ++ x :: r2
-> (exists r21, r2 = r21 ++ l2
/\ l1 = r1 ++ x :: r21)
\/ (exists r12, r1 = l1 ++ r12
/\ l2 = r12 ++ x :: r2).
Proof.
induct l1; simplify; subst; eauto.
cases r1; simplify.
invert H; eauto.
invert H.
apply IHl1 in H2; first_order; subst; eauto.
Qed.
Hint Rewrite app_length.
Lemma step_into_summarizeThreads : forall c0 cs1 c s cs2,
summarizeThreads c0 (cs1 ++ (c, s) :: cs2)
-> forall h l h' l' c', step (h, l, c) (h', l', c')
-> exists c0', step (h, l, c0) (h', l', c0')
/\ summarizeThreads c0' (cs1 ++ (c', s) :: cs2).
Proof.
induct 1; simplify.
apply split_center in x; first_order; subst.
eapply IHsummarizeThreads1 in H1; eauto.
first_order.
eexists; propositional.
eauto.
change (summarizeThreads (x0 || c2) (cs1 ++ ((c', s) :: x) ++ ss2)).
rewrite app_assoc.
eauto.
eapply IHsummarizeThreads2 in H1; eauto.
first_order.
rewrite <- app_assoc.
eauto.
cases cs1; simplify.
invert x.
eauto using summarize_step.
invert x.
apply (f_equal (@length _)) in H3; simplify.
linear_arithmetic.
Qed.
Lemma Forall_app_fwd1 : forall A (P : A -> Prop) ls1 ls2,
Forall P (ls1 ++ ls2)
-> Forall P ls1.
Proof.
induct ls1; invert 1; eauto.
Qed.
Lemma Forall_app_fwd2 : forall A (P : A -> Prop) ls1 ls2,
Forall P (ls1 ++ ls2)
-> Forall P ls2.
Proof.
induct ls1; invert 1; simplify; subst; eauto.
Qed.
Hint Immediate Forall_app_fwd1 Forall_app_fwd2.
Lemma commute_writes : forall c1 c a s h l1' h' l' v,
nextAction c1 c
-> a \in Writes s
-> commutes c s
-> forall c1', step (h, l1', c1) (h', l', c1')
-> step (h $+ (a, v), l1', c1) (h' $+ (a, v), l', c1').
Proof.
induct 1; simplify.
invert H1.
invert H1.
invert H1.
replace (h' $! a0) with (h' $+ (a, v) $! a0).
eauto.
assert (a <> a0) by sets.
simplify; equality.
invert H1.
replace (h $+ (a0, v0) $+ (a, v)) with (h $+ (a, v) $+ (a0, v0)).
eauto.
assert (a <> a0) by sets.
maps_equal.
invert H1.
eauto.
invert H1.
eauto.
invert H2; eauto.
Qed.
Lemma commute_locks : forall c1 c a s h l1' h' l',
nextAction c1 c
-> a \in Locks s
-> commutes c s
-> forall c1', step (h, l1', c1) (h', l', c1')
-> step (h, l1' \cup {a}, c1) (h', l' \cup {a}, c1').
Proof.
induct 1; simplify.
invert H1.
invert H1.
invert H1; eauto.
invert H1; eauto.
invert H1.
replace ((l1' \cup {l}) \cup {a}) with ((l1' \cup {a}) \cup {l}) by sets.
constructor.
sets.
invert H1.
replace ((l1' \setminus {l}) \cup {a}) with ((l1' \cup {a}) \setminus {l}) by sets.
constructor.
sets.
invert H2; eauto.
Qed.
Lemma commute_unlocks : forall c1 c a s h l1' h' l',
nextAction c1 c
-> a \in Locks s
-> commutes c s
-> forall c1', step (h, l1', c1) (h', l', c1')
-> step (h, l1' \setminus {a}, c1) (h', l' \setminus {a}, c1').
Proof.
induct 1; simplify.
invert H1.
invert H1.
invert H1; eauto.
invert H1; eauto.
invert H1.
replace (l1' \cup {l} \setminus {a}) with ((l1' \setminus {a}) \cup {l}) by sets.
constructor.
sets.
invert H1.
replace ((l1' \setminus {l}) \setminus {a}) with ((l1' \setminus {a}) \setminus {l}) by sets.
constructor.
sets.
invert H2; eauto.
Qed.
Lemma commutes_noblock : forall c c0,
nextAction c c0
-> forall h l h' l' c', step (h, l, c) (h', l', c')
-> forall c1 s, summarize c1 s
-> commutes c0 s
-> forall h1' l1' c1', step (h, l, c1) (h1', l1', c1')
-> exists h'' l'', step (h1', l1', c) (h'', l'', c').
Proof.
induct 1; invert 1.
induct 1; simplify; eauto.
invert H0.
invert H0.
invert H3; eauto.
invert H1; eauto.
invert H1; eauto.
assert (a0 <> a) by sets.
replace (h' $! a) with (h' $+ (a0, v) $! a) by (simplify; equality).
eauto.
invert H1; eauto.
invert H1; eauto.
induct 1; simplify; eauto.
induct 1; simplify; eauto.
invert H0.
invert H0.
invert H4; eauto.
invert H2; eauto.
invert H2; eauto.
invert H2; eauto.
do 2 eexists.
constructor.
sets.
invert H2; eauto.
do 2 eexists.
constructor.
sets.
induct 1; simplify; eauto.
invert H0.
invert H0.
invert H4; eauto.
invert H2; eauto.
invert H2; eauto.
invert H2; eauto.
do 2 eexists.
constructor.
sets.
invert H2; eauto.
do 2 eexists.
constructor.
sets.
induct 1; simplify; eauto.
invert H1.
invert H1.
invert H5; eauto.
invert H3; eauto.
invert H3.
do 2 eexists; eapply commute_writes in H2; eauto.
invert H3.
do 2 eexists; eapply commute_locks in H2; eauto.
invert H3.
do 2 eexists; eapply commute_unlocks in H2; eauto.
eauto.
Qed.
Lemma Forall_app_bwd : forall A (P : A -> Prop) ls1 ls2,
Forall P ls1
-> Forall P ls2
-> Forall P (ls1 ++ ls2).
Proof.
induct 1; simplify; eauto.
Qed.
Hint Resolve Forall_app_bwd.
Lemma split_app : forall A (l1 l2 r1 r2 : list A),
l1 ++ l2 = r1 ++ r2
-> (exists r12, r1 = l1 ++ r12
/\ l2 = r12 ++ r2)
\/ (exists r21, r2 = r21 ++ l2
/\ l1 = r1 ++ r21).
Proof.
induct l1; simplify; subst; eauto.
cases r1; simplify; subst.
right; eexists (_ :: _); simplify; eauto.
invert H.
apply IHl1 in H2; first_order; subst; eauto.
Qed.
Hint Rewrite app_length.
Lemma step_out_of_summarizeThreads : forall c cs1 c0 s cs2,
summarizeThreads c (cs1 ++ (c0, s) :: cs2)
-> forall h l c0' s' h' l', step (h, l, c0') (h', l', c0)
-> summarize c0' s'
-> exists c', summarizeThreads c' (cs1 ++ (c0', s') :: cs2)
/\ step (h, l, c') (h', l', c).
Proof.
induct 1; simplify.
apply split_center in x; first_order; subst.
eapply IHsummarizeThreads1 in H1; try reflexivity; eauto.
first_order.
change (cs1 ++ (c0', s') :: x ++ ss2) with (cs1 ++ ((c0', s') :: x) ++ ss2).
rewrite app_assoc.
eauto.
eapply IHsummarizeThreads2 in H1; try reflexivity; eauto.
first_order.
rewrite <- app_assoc.
eauto.
cases cs1; simplify.
invert x.
eauto using summarize_step.
invert x.
cases cs1; simplify; try equality.
Qed.
Lemma translate_trace_commute : forall i h l c h' l' c',
stepsi (S i) (h, l, c) (h', l', c')
-> (forall h'' l'' c'', step (h', l', c') (h'', l'', c'') -> False)
-> forall c0 s cs, summarizeThreads c ((c0, s) :: cs)
-> forall x, nextAction c0 x
-> Forall (fun c_s => summarize (fst c_s) (snd c_s) /\ commutes x (snd c_s)) cs
-> forall x0 x1 x2, step (h, l, c0) (x0, x1, x2)
-> exists h'' l'' c'', step (h, l, c0) (h'', l'', x2)
/\ summarizeThreads c'' ((x2, s) :: cs)
/\ stepsi i (h'', l'', c'') (h', l', c').
Proof.
induct 1; simplify.
invert H0.
clear IHstepsi.
eapply step_pick in H; eauto.
first_order; subst.
cases x3; simplify.
invert H.
eapply nextAction_det in H0; eauto; propositional; subst.
eauto 10.
invert H.
change ((c0, s) :: x3 ++ (x4, x5) :: x6)
with (((c0, s) :: x3) ++ (x4, x5) :: x6) in H2.
eapply step_into_summarizeThreads in H2; eauto.
first_order.
apply Forall_app_fwd2 in H4.
invert H4; simplify; propositional.
eapply commutes_noblock in H3; eauto.
first_order.
eapply step_into_summarizeThreads with (cs1 := []) in H6; eauto.
first_order.
cases st2.
cases p.
cases st0.
cases p.
eapply step_pick in H; eauto.
first_order.
cases x3; simplify.
invert H.
eapply nextAction_det in H0; eauto; propositional; subst.
eauto 10.
invert H.
change ((c0, s) :: x3 ++ (x4, x5) :: x6)
with (((c0, s) :: x3) ++ (x4, x5) :: x6) in H2.
eapply step_into_summarizeThreads in H2; eauto.
first_order.
specialize (Forall_app_fwd1 _ _ H4).
apply Forall_app_fwd2 in H4.
invert H4; simplify; propositional.
assert (Hn : nextAction c0 x) by assumption.
eapply commutes_noblock in H3; eauto.
first_order.
eapply IHstepsi in H3; clear IHstepsi; eauto using summarize_step.
first_order.
eapply commutes_sound with (c1 := c0) (c2 := x4) (c0 := x) in H10; eauto.
first_order.
eapply step_out_of_summarizeThreads with (cs1 := (x2, s) :: x3) in H11; eauto.
simplify; first_order.
eauto 10.
Qed.
Lemma summarizeThreads_Forall : forall c cs,
summarizeThreads c cs
-> Forall (fun c_s => summarize (fst c_s) (snd c_s)) cs.
Proof.
induct 1; eauto.
Qed.
Lemma Forall2 : forall A (P Q R : A -> Prop) ls,
Forall P ls
-> Forall Q ls
-> (forall x, P x -> Q x -> R x)
-> Forall R ls.
Proof.
induct 1; invert 1; eauto.
Qed.
Lemma translate_trace : forall i h l c h' l' c',
stepsi i (h, l, c) (h', l', c')
-> (forall h'' l'' c'', step (h', l', c') (h'', l'', c'') -> False)
-> notAboutToFail c' = false
-> forall cs, summarizeThreads c cs
-> exists h' l' cs', stepC^* (h, l, cs) (h', l', cs')
/\ Exists (fun c_s => notAboutToFail (fst c_s) = false) cs'.
Proof.
induct i; simplify.
invert H.
eauto 10.
cases cs.
exfalso; eauto.
cases p.
destruct (classic (exists c1 h' l' c', nextAction c0 c1
/\ Forall (fun c_s => commutes c1 (snd c_s)) cs
/\ step (h, l, c0) (h', l', c'))).
first_order.
eapply translate_trace_commute in H; eauto.
first_order.
eapply IHi in H7; eauto.
first_order.
do 3 eexists; propositional.
eapply TrcFront.
eauto.
eassumption.
assumption.
apply summarizeThreads_Forall in H2.
invert H2.
eauto using Forall2.
invert H.
cases st2.
cases p.
eapply translate_trace_matching in H5; eauto.
first_order.
eapply IHi in H6; eauto.
first_order.
eauto 6.
Qed.
Lemma Forall_Exists_contra : forall A (f : A -> bool) ls,
Exists (fun x => f x = false) ls
-> Forall (fun x => f x = true) ls
-> False.
Proof.
induct 1; invert 1; equality.
Qed.
Theorem step_stepC : forall h l c (cs : list (cmd * summary)) n,
summarizeThreads c cs
-> boundRunningTime c n
-> invariantFor (trsys_ofC h l cs) (fun p => let '(_, _, cs) := p in
List.Forall (fun c_s => notAboutToFail (fst c_s) = true) cs)
-> invariantFor (trsys_of h l c) (fun p =>
let '(_, _, c) := p in
notAboutToFail c = true).
Proof.
simplify.
apply NNPP; propositional.
unfold invariantFor in H2.
apply not_all_ex_not in H2; first_order.
apply imply_to_and in H2; propositional.
apply not_all_ex_not in H4; first_order.
apply imply_to_and in H2; propositional.
cases x0.
cases p.
subst.
simplify.
cases (notAboutToFail c0); propositional.
assert (exists n', boundRunningTime c0 n' /\ n' <= n) by eauto using boundRunningTime_steps.
first_order.
eapply complete_trace in H2; eauto.
first_order.
specialize (trc_trans H4 H2); simplify.
assert (notAboutToFail x2 = false) by eauto using notAboutToFail_steps.
unfold invariantFor in H1; simplify.
apply steps_stepsi in H7; first_order.
eapply translate_trace in H7; eauto.
first_order.
apply H1 in H7; auto.
eapply Forall_Exists_contra.
apply H9.
assumption.
Qed.
Ltac analyzer := repeat (match goal with
| [ |- context[if ?E then _ else _] ] => cases E
| _ => econstructor
end; simplify; try solve [ sets ]).
Ltac por_solve := simplify; repeat econstructor; sets; linear_arithmetic.
Ltac por_lister :=
repeat match goal with
| [ H : ?ls ++ _ = _ :: _ |- _ ] => cases ls; simplify; invert H
| [ H : @eq (list _) _ _ |- _ ] => apply (f_equal (@length _)) in H; simplify; linear_arithmetic
end.
Ltac por_invert1 :=
match goal with
| [ H : forall (c0 : cmd) (h'' : heap) (l'' : locks) (c'' : cmd), _ -> _ |- _ ] =>
(exfalso; eapply H; try por_solve; por_lister; por_solve) || (clear H; por_lister)
| _ => model_check_invert1
end.
Ltac por_invert := simplify; repeat por_invert1.
Ltac por_closure :=
repeat (apply oneStepClosure_empty
|| (apply oneStepClosure_split; [ por_invert; try equality; solve [ singletoner ] | ])).
Ltac por_step :=
eapply MscStep; [ por_closure | simplify ].
Ltac por_done :=
apply MscDone; eapply oneStepClosure_solve; [ por_closure | simplify; solve [ sets ] ].
Theorem independent_threads_ok_again :
invariantFor (trsys_of $0 {} independent_threads)
(fun p => let '(_, _, c) := p in
notAboutToFail c = true).
Proof.
eapply step_stepC with (cs := [(_, {| Reads := {0, 1};
Writes := {1};
Locks := {} |})]
++ [(_, {| Reads := {2};
Writes := {2};
Locks := {} |})]).
analyzer.
analyzer.
simplify.
eapply invariant_weaken.
apply multiStepClosure_ok; simplify.
por_step.
por_step.
por_step.
por_step.
por_step.
por_step.
por_step.
por_step.
por_step.
por_done.
sets.
Grab Existential Variables.
exact 0.
exact 0.
exact 0.
exact 0.
exact 0.
exact 0.
Qed.