Up to index of Isabelle/HOL/TLA/Memory
theory Memory(* File: Memory.thy ID: $Id: Memory.thy,v 1.8 2008/05/17 21:53:19 wenzelm Exp $ Author: Stephan Merz Copyright: 1997 University of Munich *) header {* RPC-Memory example: Memory specification *} theory Memory imports MemoryParameters ProcedureInterface begin types memChType = "(memOp, Vals) channel" memType = "(Locs => Vals) stfun" (* intention: MemLocs => MemVals *) resType = "(PrIds => Vals) stfun" consts (* state predicates *) MInit :: "memType => Locs => stpred" PInit :: "resType => PrIds => stpred" (* auxiliary predicates: is there a pending read/write request for some process id and location/value? *) RdRequest :: "memChType => PrIds => Locs => stpred" WrRequest :: "memChType => PrIds => Locs => Vals => stpred" (* actions *) GoodRead :: "memType => resType => PrIds => Locs => action" BadRead :: "memType => resType => PrIds => Locs => action" ReadInner :: "memChType => memType => resType => PrIds => Locs => action" Read :: "memChType => memType => resType => PrIds => action" GoodWrite :: "memType => resType => PrIds => Locs => Vals => action" BadWrite :: "memType => resType => PrIds => Locs => Vals => action" WriteInner :: "memChType => memType => resType => PrIds => Locs => Vals => action" Write :: "memChType => memType => resType => PrIds => Locs => action" MemReturn :: "memChType => resType => PrIds => action" MemFail :: "memChType => resType => PrIds => action" RNext :: "memChType => memType => resType => PrIds => action" UNext :: "memChType => memType => resType => PrIds => action" (* temporal formulas *) RPSpec :: "memChType => memType => resType => PrIds => temporal" UPSpec :: "memChType => memType => resType => PrIds => temporal" MSpec :: "memChType => memType => resType => Locs => temporal" IRSpec :: "memChType => memType => resType => temporal" IUSpec :: "memChType => memType => resType => temporal" RSpec :: "memChType => resType => temporal" USpec :: "memChType => temporal" (* memory invariant: in the paper, the invariant is hidden in the definition of the predicate S used in the implementation proof, but it is easier to verify at this level. *) MemInv :: "memType => Locs => stpred" defs MInit_def: "MInit mm l == PRED mm!l = #InitVal" PInit_def: "PInit rs p == PRED rs!p = #NotAResult" RdRequest_def: "RdRequest ch p l == PRED Calling ch p & (arg<ch!p> = #(read l))" WrRequest_def: "WrRequest ch p l v == PRED Calling ch p & (arg<ch!p> = #(write l v))" (* a read that doesn't raise BadArg *) GoodRead_def: "GoodRead mm rs p l == ACT #l : #MemLoc & ((rs!p)$ = $(mm!l))" (* a read that raises BadArg *) BadRead_def: "BadRead mm rs p l == ACT #l ~: #MemLoc & ((rs!p)$ = #BadArg)" (* the read action with l visible *) ReadInner_def: "ReadInner ch mm rs p l == ACT $(RdRequest ch p l) & (GoodRead mm rs p l | BadRead mm rs p l) & unchanged (rtrner ch ! p)" (* the read action with l quantified *) Read_def: "Read ch mm rs p == ACT (EX l. ReadInner ch mm rs p l)" (* similar definitions for the write action *) GoodWrite_def: "GoodWrite mm rs p l v == ACT #l : #MemLoc & #v : #MemVal & ((mm!l)$ = #v) & ((rs!p)$ = #OK)" BadWrite_def: "BadWrite mm rs p l v == ACT ~ (#l : #MemLoc & #v : #MemVal) & ((rs!p)$ = #BadArg) & unchanged (mm!l)" WriteInner_def: "WriteInner ch mm rs p l v == ACT $(WrRequest ch p l v) & (GoodWrite mm rs p l v | BadWrite mm rs p l v) & unchanged (rtrner ch ! p)" Write_def: "Write ch mm rs p l == ACT (EX v. WriteInner ch mm rs p l v)" (* the return action *) MemReturn_def: "MemReturn ch rs p == ACT ( ($(rs!p) ~= #NotAResult) & ((rs!p)$ = #NotAResult) & Return ch p (rs!p))" (* the failure action of the unreliable memory *) MemFail_def: "MemFail ch rs p == ACT $(Calling ch p) & ((rs!p)$ = #MemFailure) & unchanged (rtrner ch ! p)" (* next-state relations for reliable / unreliable memory *) RNext_def: "RNext ch mm rs p == ACT ( Read ch mm rs p | (EX l. Write ch mm rs p l) | MemReturn ch rs p)" UNext_def: "UNext ch mm rs p == ACT (RNext ch mm rs p | MemFail ch rs p)" RPSpec_def: "RPSpec ch mm rs p == TEMP Init(PInit rs p) & [][ RNext ch mm rs p ]_(rtrner ch ! p, rs!p) & WF(RNext ch mm rs p)_(rtrner ch ! p, rs!p) & WF(MemReturn ch rs p)_(rtrner ch ! p, rs!p)" UPSpec_def: "UPSpec ch mm rs p == TEMP Init(PInit rs p) & [][ UNext ch mm rs p ]_(rtrner ch ! p, rs!p) & WF(RNext ch mm rs p)_(rtrner ch ! p, rs!p) & WF(MemReturn ch rs p)_(rtrner ch ! p, rs!p)" MSpec_def: "MSpec ch mm rs l == TEMP Init(MInit mm l) & [][ EX p. Write ch mm rs p l ]_(mm!l)" IRSpec_def: "IRSpec ch mm rs == TEMP (ALL p. RPSpec ch mm rs p) & (ALL l. #l : #MemLoc --> MSpec ch mm rs l)" IUSpec_def: "IUSpec ch mm rs == TEMP (ALL p. UPSpec ch mm rs p) & (ALL l. #l : #MemLoc --> MSpec ch mm rs l)" RSpec_def: "RSpec ch rs == TEMP (EEX mm. IRSpec ch mm rs)" USpec_def: "USpec ch == TEMP (EEX mm rs. IUSpec ch mm rs)" MemInv_def: "MemInv mm l == PRED #l : #MemLoc --> mm!l : #MemVal" lemmas RM_action_defs = MInit_def PInit_def RdRequest_def WrRequest_def MemInv_def GoodRead_def BadRead_def ReadInner_def Read_def GoodWrite_def BadWrite_def WriteInner_def Write_def MemReturn_def RNext_def lemmas UM_action_defs = RM_action_defs MemFail_def UNext_def lemmas RM_temp_defs = RPSpec_def MSpec_def IRSpec_def lemmas UM_temp_defs = UPSpec_def MSpec_def IUSpec_def (* The reliable memory is an implementation of the unreliable one *) lemma ReliableImplementsUnReliable: "|- IRSpec ch mm rs --> IUSpec ch mm rs" by (force simp: UNext_def UPSpec_def IUSpec_def RM_temp_defs elim!: STL4E [temp_use] squareE) (* The memory spec implies the memory invariant *) lemma MemoryInvariant: "|- MSpec ch mm rs l --> [](MemInv mm l)" by (tactic {* auto_inv_tac (@{simpset} addsimps (@{thms RM_temp_defs} @ @{thms RM_action_defs})) 1 *}) (* The invariant is trivial for non-locations *) lemma NonMemLocInvariant: "|- #l ~: #MemLoc --> [](MemInv mm l)" by (auto simp: MemInv_def intro!: necT [temp_use]) lemma MemoryInvariantAll: "|- (ALL l. #l : #MemLoc --> MSpec ch mm rs l) --> (ALL l. [](MemInv mm l))" apply clarify apply (auto elim!: MemoryInvariant [temp_use] NonMemLocInvariant [temp_use]) done (* The memory engages in an action for process p only if there is an unanswered call from p. We need this only for the reliable memory. *) lemma Memoryidle: "|- ~$(Calling ch p) --> ~ RNext ch mm rs p" by (auto simp: Return_def RM_action_defs) (* Enabledness conditions *) lemma MemReturn_change: "|- MemReturn ch rs p --> <MemReturn ch rs p>_(rtrner ch ! p, rs!p)" by (force simp: MemReturn_def angle_def) lemma MemReturn_enabled: "!!p. basevars (rtrner ch ! p, rs!p) ==> |- Calling ch p & (rs!p ~= #NotAResult) --> Enabled (<MemReturn ch rs p>_(rtrner ch ! p, rs!p))" apply (tactic {* action_simp_tac @{simpset} [thm "MemReturn_change" RSN (2, thm "enabled_mono") ] [] 1 *}) apply (tactic {* action_simp_tac (@{simpset} addsimps [thm "MemReturn_def", thm "Return_def", thm "rtrner_def"]) [exI] [thm "base_enabled", thm "Pair_inject"] 1 *}) done lemma ReadInner_enabled: "!!p. basevars (rtrner ch ! p, rs!p) ==> |- Calling ch p & (arg<ch!p> = #(read l)) --> Enabled (ReadInner ch mm rs p l)" apply (case_tac "l : MemLoc") apply (force simp: ReadInner_def GoodRead_def BadRead_def RdRequest_def intro!: exI elim!: base_enabled [temp_use])+ done lemma WriteInner_enabled: "!!p. basevars (mm!l, rtrner ch ! p, rs!p) ==> |- Calling ch p & (arg<ch!p> = #(write l v)) --> Enabled (WriteInner ch mm rs p l v)" apply (case_tac "l:MemLoc & v:MemVal") apply (force simp: WriteInner_def GoodWrite_def BadWrite_def WrRequest_def intro!: exI elim!: base_enabled [temp_use])+ done lemma ReadResult: "|- Read ch mm rs p & (!l. $(MemInv mm l)) --> (rs!p)` ~= #NotAResult" by (force simp: Read_def ReadInner_def GoodRead_def BadRead_def MemInv_def) lemma WriteResult: "|- Write ch mm rs p l --> (rs!p)` ~= #NotAResult" by (auto simp: Write_def WriteInner_def GoodWrite_def BadWrite_def) lemma ReturnNotReadWrite: "|- (ALL l. $MemInv mm l) & MemReturn ch rs p --> ~ Read ch mm rs p & (ALL l. ~ Write ch mm rs p l)" by (auto simp: MemReturn_def dest!: WriteResult [temp_use] ReadResult [temp_use]) lemma RWRNext_enabled: "|- (rs!p = #NotAResult) & (!l. MemInv mm l) & Enabled (Read ch mm rs p | (? l. Write ch mm rs p l)) --> Enabled (<RNext ch mm rs p>_(rtrner ch ! p, rs!p))" by (force simp: RNext_def angle_def elim!: enabled_mono2 dest: ReadResult [temp_use] WriteResult [temp_use]) (* Combine previous lemmas: the memory can make a visible step if there is an outstanding call for which no result has been produced. *) lemma RNext_enabled: "!!p. !l. basevars (mm!l, rtrner ch!p, rs!p) ==> |- (rs!p = #NotAResult) & Calling ch p & (!l. MemInv mm l) --> Enabled (<RNext ch mm rs p>_(rtrner ch ! p, rs!p))" apply (auto simp: enabled_disj [try_rewrite] intro!: RWRNext_enabled [temp_use]) apply (case_tac "arg (ch w p)") apply (tactic {* action_simp_tac (@{simpset} addsimps [thm "Read_def", temp_rewrite (thm "enabled_ex")]) [thm "ReadInner_enabled", exI] [] 1 *}) apply (force dest: base_pair [temp_use]) apply (erule contrapos_np) apply (tactic {* action_simp_tac (@{simpset} addsimps [thm "Write_def", temp_rewrite (thm "enabled_ex")]) [thm "WriteInner_enabled", exI] [] 1 *}) done end
lemma RM_action_defs:
MInit mm l == mm!l = #InitVal
PInit rs p == rs!p = #NotAResult
RdRequest ch p l == Calling ch p ∧ arg<ch!p> = #(read l)
WrRequest ch p l v == Calling ch p ∧ arg<ch!p> = #(write l v)
MemInv mm l == #l ∈ #MemLoc --> mm!l ∈ #MemVal
GoodRead mm rs p l == #l ∈ #MemLoc ∧ (rs!p)$ = $(mm!l)
BadRead mm rs p l == #l ∉ #MemLoc ∧ (rs!p)$ = #BadArg
ReadInner ch mm rs p l ==
$RdRequest ch p l ∧
(GoodRead mm rs p l ∨ BadRead mm rs p l) ∧ unchanged (rtrner ch!p)
Read ch mm rs p == ∃l. ReadInner ch mm rs p l
GoodWrite mm rs p l v ==
#l ∈ #MemLoc ∧ #v ∈ #MemVal ∧ (mm!l)$ = #v ∧ (rs!p)$ = #OK
BadWrite mm rs p l v ==
¬ (#l ∈ #MemLoc ∧ #v ∈ #MemVal) ∧ (rs!p)$ = #BadArg ∧ unchanged (mm!l)
WriteInner ch mm rs p l v ==
$WrRequest ch p l v ∧
(GoodWrite mm rs p l v ∨ BadWrite mm rs p l v) ∧ unchanged (rtrner ch!p)
Write ch mm rs p l == ∃v. WriteInner ch mm rs p l v
MemReturn ch rs p ==
$(rs!p) ≠ #NotAResult ∧ (rs!p)$ = #NotAResult ∧ Return ch p (rs!p)
RNext ch mm rs p ==
Read ch mm rs p ∨ (∃l. Write ch mm rs p l) ∨ MemReturn ch rs p
lemma UM_action_defs:
MInit mm l == mm!l = #InitVal
PInit rs p == rs!p = #NotAResult
RdRequest ch p l == Calling ch p ∧ arg<ch!p> = #(read l)
WrRequest ch p l v == Calling ch p ∧ arg<ch!p> = #(write l v)
MemInv mm l == #l ∈ #MemLoc --> mm!l ∈ #MemVal
GoodRead mm rs p l == #l ∈ #MemLoc ∧ (rs!p)$ = $(mm!l)
BadRead mm rs p l == #l ∉ #MemLoc ∧ (rs!p)$ = #BadArg
ReadInner ch mm rs p l ==
$RdRequest ch p l ∧
(GoodRead mm rs p l ∨ BadRead mm rs p l) ∧ unchanged (rtrner ch!p)
Read ch mm rs p == ∃l. ReadInner ch mm rs p l
GoodWrite mm rs p l v ==
#l ∈ #MemLoc ∧ #v ∈ #MemVal ∧ (mm!l)$ = #v ∧ (rs!p)$ = #OK
BadWrite mm rs p l v ==
¬ (#l ∈ #MemLoc ∧ #v ∈ #MemVal) ∧ (rs!p)$ = #BadArg ∧ unchanged (mm!l)
WriteInner ch mm rs p l v ==
$WrRequest ch p l v ∧
(GoodWrite mm rs p l v ∨ BadWrite mm rs p l v) ∧ unchanged (rtrner ch!p)
Write ch mm rs p l == ∃v. WriteInner ch mm rs p l v
MemReturn ch rs p ==
$(rs!p) ≠ #NotAResult ∧ (rs!p)$ = #NotAResult ∧ Return ch p (rs!p)
RNext ch mm rs p ==
Read ch mm rs p ∨ (∃l. Write ch mm rs p l) ∨ MemReturn ch rs p
MemFail ch rs p ==
$Calling ch p ∧ (rs!p)$ = #MemFailure ∧ unchanged (rtrner ch!p)
UNext ch mm rs p == RNext ch mm rs p ∨ MemFail ch rs p
lemma RM_temp_defs:
RPSpec ch mm rs p ==
Init PInit rs p ∧
[][RNext ch mm rs p]_(rtrner ch!p, rs!p) ∧
WF(RNext ch mm rs p)_(rtrner ch!p, rs!p) ∧
WF(MemReturn ch rs p)_(rtrner ch!p, rs!p)
MSpec ch mm rs l == Init MInit mm l ∧ [][∃p. Write ch mm rs p l]_(mm!l)
IRSpec ch mm rs ==
(∀p. RPSpec ch mm rs p) ∧ (∀l. #l ∈ #MemLoc --> MSpec ch mm rs l)
lemma UM_temp_defs:
UPSpec ch mm rs p ==
Init PInit rs p ∧
[][UNext ch mm rs p]_(rtrner ch!p, rs!p) ∧
WF(RNext ch mm rs p)_(rtrner ch!p, rs!p) ∧
WF(MemReturn ch rs p)_(rtrner ch!p, rs!p)
MSpec ch mm rs l == Init MInit mm l ∧ [][∃p. Write ch mm rs p l]_(mm!l)
IUSpec ch mm rs ==
(∀p. UPSpec ch mm rs p) ∧ (∀l. #l ∈ #MemLoc --> MSpec ch mm rs l)
lemma ReliableImplementsUnReliable:
|- IRSpec ch mm rs --> IUSpec ch mm rs
lemma MemoryInvariant:
|- MSpec ch mm rs l --> []MemInv mm l
lemma NonMemLocInvariant:
|- #l ∉ #MemLoc --> []MemInv mm l
lemma MemoryInvariantAll:
|- (∀l. #l ∈ #MemLoc --> MSpec ch mm rs l) --> (∀l. []MemInv mm l)
lemma Memoryidle:
|- ¬ $Calling ch p --> ¬ RNext ch mm rs p
lemma MemReturn_change:
|- MemReturn ch rs p --> <MemReturn ch rs p>_(rtrner ch!p, rs!p)
lemma MemReturn_enabled:
basevars (rtrner ch!p, rs!p)
==> |- Calling ch p ∧ rs!p ≠ #NotAResult -->
Enabled (<MemReturn ch rs p>_(rtrner ch!p, rs!p))
lemma ReadInner_enabled:
basevars (rtrner ch!p, rs!p)
==> |- Calling ch p ∧ arg<ch!p> = #(read l) --> Enabled ReadInner ch mm rs p l
lemma WriteInner_enabled:
basevars (mm!l, rtrner ch!p, rs!p)
==> |- Calling ch p ∧ arg<ch!p> = #(write l v) -->
Enabled WriteInner ch mm rs p l v
lemma ReadResult:
|- Read ch mm rs p ∧ (∀l. $MemInv mm l) --> (rs!p)$ ≠ #NotAResult
lemma WriteResult:
|- Write ch mm rs p l --> (rs!p)$ ≠ #NotAResult
lemma ReturnNotReadWrite:
|- (∀l. $MemInv mm l) ∧ MemReturn ch rs p -->
¬ Read ch mm rs p ∧ (∀l. ¬ Write ch mm rs p l)
lemma RWRNext_enabled:
|- rs!p = #NotAResult ∧
(∀l. MemInv mm l) ∧ Enabled (Read ch mm rs p ∨ (∃l. Write ch mm rs p l)) -->
Enabled (<RNext ch mm rs p>_(rtrner ch!p, rs!p))
lemma RNext_enabled:
∀l. basevars (mm!l, rtrner ch!p, rs!p)
==> |- rs!p = #NotAResult ∧ Calling ch p ∧ (∀l. MemInv mm l) -->
Enabled (<RNext ch mm rs p>_(rtrner ch!p, rs!p))