diff --git a/.github/scripts/check_proofs.py b/.github/scripts/check_proofs.py index 999dbf52..f06309d9 100644 --- a/.github/scripts/check_proofs.py +++ b/.github/scripts/check_proofs.py @@ -48,7 +48,8 @@ tlapm = subprocess.run( [ tlapm_path, module_path, - '-I', module_dir + '-I', module_dir, + '--stretch', '5' ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ab1b0ab5..1aec20d7 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -108,7 +108,9 @@ jobs: - name: Check small models run: | # Need to have a nonempty list to pass as a skip parameter - SKIP=("does/not/exist") + # SKIP=("does/not/exist") + # strange issue with parsing TLC output + SKIP=("specifications/ewd840/EWD840.cfg") if [ ${{ matrix.unicode }} ]; then # Apalache does not yet support Unicode SKIP+=("specifications/EinsteinRiddle/Einstein.cfg") @@ -143,21 +145,16 @@ jobs: if: matrix.os != 'windows-latest' && !matrix.unicode run: | SKIP=( - ## ATD/EWD require TLAPS' update_enabled_cdot branch - specifications/ewd998/AsyncTerminationDetection_proof.tla + # Long-running; see https://github.com/tlaplus/tlapm/issues/85 specifications/ewd998/EWD998_proof.tla - # Failing; see https://github.com/tlaplus/Examples/issues/67 specifications/Bakery-Boulangerie/Bakery.tla specifications/Bakery-Boulangerie/Boulanger.tla - specifications/Paxos/Consensus.tla - specifications/PaxosHowToWinATuringAward/Consensus.tla - specifications/lamport_mutex/LamportMutex_proofs.tla - specifications/byzpaxos/VoteProof.tla - # Long-running; see https://github.com/tlaplus/tlapm/issues/85 specifications/LoopInvariance/Quicksort.tla specifications/LoopInvariance/SumSequence.tla + specifications/lamport_mutex/LamportMutex_proofs.tla specifications/bcastByz/bcastByz.tla - specifications/MisraReachability/ReachabilityProofs.tla + # specifications/MisraReachability/ReachabilityProofs.tla + specifications/byzpaxos/VoteProof.tla specifications/byzpaxos/BPConProof.tla # Takes about 30 minutes ) python $SCRIPT_DIR/check_proofs.py \ diff --git a/README.md b/README.md index 3e9983b0..c4c726a2 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Here is a list of specs included in this repository, with links to the relevant | [Loop Invariance](specifications/LoopInvariance) | Leslie Lamport | ✔ | ✔ | ✔ | ✔ | | | [Learn TLA⁺ Proofs](specifications/LearnProofs) | Andrew Helwer | ✔ | ✔ | ✔ | ✔ | | | [Boyer-Moore Majority Vote](specifications/Majority) | Stephan Merz | ✔ | ✔ | | ✔ | | -| [Proof x+x is Even](specifications/sums_even) | Stephan Merz | ✔ | ✔ | | ✔ | | +| [Proof x+x is Even](specifications/sums_even) | Martin Riener | ✔ | ✔ | | ✔ | | | [The N-Queens Puzzle](specifications/N-Queens) | Stephan Merz | ✔ | | ✔ | ✔ | | | [The Dining Philosophers Problem](specifications/DiningPhilosophers) | Jeff Hemphill | ✔ | | ✔ | ✔ | | | [The Car Talk Puzzle](specifications/CarTalkPuzzle) | Leslie Lamport | ✔ | | | ✔ | | @@ -48,11 +48,11 @@ Here is a list of specs included in this repository, with links to the relevant | [Byzantizing Paxos by Refinement](specifications/byzpaxos) | Leslie Lamport | | ✔ | ✔ | ✔ | | | [EWD840: Termination Detection in a Ring](specifications/ewd840) | Stephan Merz | | ✔ | | ✔ | | | [EWD998: Termination Detection in a Ring with Asynchronous Message Delivery](specifications/ewd998) | Stephan Merz, Markus Kuppe | | ✔ | (✔) | ✔ | | -| [The Paxos Protocol](specifications/Paxos) | Leslie Lamport | | ✔ | | ✔ | | +| [The Paxos Protocol](specifications/Paxos) | Leslie Lamport | | (✔) | | ✔ | | | [Asynchronous Reliable Broadcast](specifications/bcastByz) | Thanh Hai Tran, Igor Konnov, Josef Widder | | ✔ | | ✔ | | | [Distributed Mutual Exclusion](specifications/lamport_mutex) | Stephan Merz | | ✔ | | ✔ | | | [Two-Phase Handshaking](specifications/TwoPhase) | Leslie Lamport, Stephan Merz | | ✔ | | ✔ | | -| [Paxos (How to Win a Turing Award)](specifications/PaxosHowToWinATuringAward) | Leslie Lamport | | ✔ | | ✔ | | +| [Paxos (How to Win a Turing Award)](specifications/PaxosHowToWinATuringAward) | Leslie Lamport | | (✔) | | ✔ | | | [Dijkstra's Mutual Exclusion Algorithm](specifications/dijkstra-mutex) | Leslie Lamport | | | ✔ | ✔ | | | [The Echo Algorithm](specifications/echo) | Stephan Merz | | | ✔ | ✔ | | | [The TLC Safety Checking Algorithm](specifications/TLC) | Markus Kuppe | | | ✔ | ✔ | | diff --git a/manifest.json b/manifest.json index 3c0ab7e6..ad1d14dd 100644 --- a/manifest.json +++ b/manifest.json @@ -46,8 +46,8 @@ "ignore deadlock" ], "result": "success", - "distinctStates": 598608, - "totalStates": 3141768, + "distinctStates": 655200, + "totalStates": 3403584, "stateDepth": 1 } ] @@ -587,6 +587,20 @@ "features": [], "models": [] }, + { + "path": "specifications/FiniteMonotonic/Functions.tla", + "communityDependencies": [], + "tlaLanguageVersion": 2, + "features": [], + "models": [] + }, + { + "path": "specifications/FiniteMonotonic/Folds.tla", + "communityDependencies": [], + "tlaLanguageVersion": 2, + "features": [], + "models": [] + }, { "path": "specifications/FiniteMonotonic/MCCRDT.tla", "communityDependencies": [ @@ -3271,15 +3285,6 @@ } ] }, - { - "path": "specifications/TwoPhase/TLAPS.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [ - "proof" - ], - "models": [] - }, { "path": "specifications/TwoPhase/TwoPhase.tla", "communityDependencies": [], @@ -4502,7 +4507,8 @@ "size": "small", "mode": "exhaustive search", "features": [ - "ignore deadlock" + "ignore deadlock", + "liveness" ], "result": "success", "distinctStates": 302, @@ -4588,12 +4594,10 @@ ] }, { - "path": "specifications/ewd840/TLAPS.tla", + "path": "specifications/ewd840/SyncTerminationDetection_proof.tla", "communityDependencies": [], "tlaLanguageVersion": 2, - "features": [ - "proof" - ], + "features": ["proof"], "models": [] } ] @@ -4645,7 +4649,6 @@ { "path": "specifications/ewd998/EWD998.tla", "communityDependencies": [ - "Functions", "SequencesExt" ], "tlaLanguageVersion": 2, @@ -4658,7 +4661,8 @@ "mode": "exhaustive search", "features": [ "ignore deadlock", - "state constraint" + "state constraint", + "liveness" ], "result": "success" }, @@ -4853,6 +4857,20 @@ ], "models": [] }, + { + "path": "specifications/ewd998/Functions.tla", + "communityDependencies": [], + "tlaLanguageVersion": 2, + "features": [], + "models": [] + }, + { + "path": "specifications/ewd998/Folds.tla", + "communityDependencies": [], + "tlaLanguageVersion": 2, + "features": [], + "models": [] + }, { "path": "specifications/ewd998/SmokeEWD998.tla", "communityDependencies": [ @@ -4899,19 +4917,9 @@ } ] }, - { - "path": "specifications/ewd998/TLAPS.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [ - "proof" - ], - "models": [] - }, { "path": "specifications/ewd998/Utils.tla", "communityDependencies": [ - "Functions", "SequencesExt" ], "tlaLanguageVersion": 2, @@ -5007,13 +5015,6 @@ ], "tags": [], "modules": [ - { - "path": "specifications/lamport_mutex/Functions.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [], - "models": [] - }, { "path": "specifications/lamport_mutex/LamportMutex.tla", "communityDependencies": [], @@ -5050,36 +5051,6 @@ "stateDepth": 61 } ] - }, - { - "path": "specifications/lamport_mutex/NaturalsInduction.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [], - "models": [] - }, - { - "path": "specifications/lamport_mutex/SequenceTheorems.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [], - "models": [] - }, - { - "path": "specifications/lamport_mutex/TLAPS.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [ - "proof" - ], - "models": [] - }, - { - "path": "specifications/lamport_mutex/WellFoundedInduction.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [], - "models": [] } ] }, @@ -5194,7 +5165,7 @@ "description": "Two proofs that x+x is even for every natural number x", "sources": [], "authors": [ - "Stephan Merz" + "Martin Riener" ], "tags": [ "beginner" @@ -5219,15 +5190,6 @@ } ] }, - { - "path": "specifications/sums_even/TLAPS.tla", - "communityDependencies": [], - "tlaLanguageVersion": 2, - "features": [ - "proof" - ], - "models": [] - }, { "path": "specifications/sums_even/sums_even.tla", "communityDependencies": [], diff --git a/specifications/Bakery-Boulangerie/Bakery.pdf b/specifications/Bakery-Boulangerie/Bakery.pdf deleted file mode 100644 index e6666c76..00000000 Binary files a/specifications/Bakery-Boulangerie/Bakery.pdf and /dev/null differ diff --git a/specifications/Bakery-Boulangerie/Bakery.tla b/specifications/Bakery-Boulangerie/Bakery.tla index bfbae75b..c8a9f0cd 100644 --- a/specifications/Bakery-Boulangerie/Bakery.tla +++ b/specifications/Bakery-Boulangerie/Bakery.tla @@ -223,6 +223,47 @@ TypeOK == /\ num \in [Procs -> Nat] /\ pc \in [Procs -> {"ncs", "e1", "e2", "e3", "e4", "w1", "w2", "cs", "exit"}] +THEOREM TypeCorrect == Spec => []TypeOK +<1>. USE N \in Nat DEF ProcSet, Procs +<1>1. Init => TypeOK + BY DEF Init, TypeOK +<1>2. TypeOK /\ [Next]_vars => TypeOK' + <2>. SUFFICES ASSUME TypeOK, [Next]_vars + PROVE TypeOK' + OBVIOUS + <2>1. ASSUME NEW self \in Procs, ncs(self) + PROVE TypeOK' + BY <2>1 DEF TypeOK, ncs + <2>2. ASSUME NEW self \in Procs, e1(self) + PROVE TypeOK' + BY <2>2 DEF TypeOK, e1 + <2>3. ASSUME NEW self \in Procs, e2(self) + PROVE TypeOK' + BY <2>3 DEF TypeOK, e2 + <2>4. ASSUME NEW self \in Procs, e3(self) + PROVE TypeOK' + BY <2>4 DEF TypeOK, e3 + <2>5. ASSUME NEW self \in Procs, e4(self) + PROVE TypeOK' + BY <2>5 DEF TypeOK, e4 + <2>6. ASSUME NEW self \in Procs, w1(self) + PROVE TypeOK' + BY <2>6 DEF TypeOK, w1 + <2>7. ASSUME NEW self \in Procs, w2(self) + PROVE TypeOK' + BY <2>7 DEF TypeOK, w2 + <2>8. ASSUME NEW self \in Procs, cs(self) + PROVE TypeOK' + BY <2>8 DEF TypeOK, cs + <2>9. ASSUME NEW self \in Procs, exit(self) + PROVE TypeOK' + BY <2>9 DEF TypeOK, exit + <2>10. CASE UNCHANGED vars + BY <2>10 DEF TypeOK, vars + <2>. QED + BY <2>1, <2>2, <2>3, <2>4, <2>5, <2>6, <2>7, <2>8, <2>9, <2>10 DEF Next, p +<1>. QED BY <1>1, <1>2, PTL DEF Spec + (***************************************************************************) (* Before(i, j) is a condition that implies that num[i] > 0 and, if j is *) (* trying to enter its critical section and i does not change num[i], then *) @@ -247,21 +288,21 @@ Before(i,j) == /\ num[i] > 0 (***************************************************************************) (* Inv is the complete inductive invariant. *) (***************************************************************************) -Inv == /\ TypeOK - /\ \A i \in Procs : +IInv == \A i \in Procs : \* /\ (pc[i] \in {"ncs", "e1", "e2"}) => (num[i] = 0) - /\ (pc[i] \in {"e4", "w1", "w2", "cs"}) => (num[i] # 0) - /\ (pc[i] \in {"e2", "e3"}) => flag[i] - /\ (pc[i] = "w2") => (nxt[i] # i) - /\ pc[i] \in {(*"e2",*) "w1", "w2"} => i \notin unchecked[i] - /\ (pc[i] \in {"w1", "w2"}) => - \A j \in (Procs \ unchecked[i]) \ {i} : Before(i, j) - /\ /\ (pc[i] = "w2") - /\ \/ (pc[nxt[i]] = "e2") /\ (i \notin unchecked[nxt[i]]) - \/ pc[nxt[i]] = "e3" - => max[nxt[i]] >= num[i] - /\ (pc[i] = "cs") => \A j \in Procs \ {i} : Before(i, j) + /\ (pc[i] \in {"e4", "w1", "w2", "cs"}) => (num[i] # 0) + /\ (pc[i] \in {"e2", "e3"}) => flag[i] + /\ (pc[i] = "w2") => (nxt[i] # i) + /\ pc[i] \in {"w1", "w2"} => i \notin unchecked[i] + /\ (pc[i] \in {"w1", "w2"}) => + \A j \in (Procs \ unchecked[i]) \ {i} : Before(i, j) + /\ /\ (pc[i] = "w2") + /\ \/ (pc[nxt[i]] = "e2") /\ (i \notin unchecked[nxt[i]]) + \/ pc[nxt[i]] = "e3" + => max[nxt[i]] >= num[i] + /\ (pc[i] = "cs") => \A j \in Procs \ {i} : Before(i, j) +Inv == TypeOK /\ IInv ----------------------------------------------------------------------------- (***************************************************************************) (* Proof of Mutual Exclusion *) @@ -274,35 +315,35 @@ Inv == /\ TypeOK THEOREM Spec => []MutualExclusion <1> USE N \in Nat DEFS Procs, TypeOK, Before, \prec, ProcSet <1>1. Init => Inv - BY DEF Init, Inv -<1>2. Inv /\ [Next]_vars => Inv' - <2> SUFFICES ASSUME Inv, + BY DEF Init, Inv, IInv +<1>2. Inv /\ [Next]_vars => IInv' + <2> SUFFICES ASSUME TypeOK, IInv, [Next]_vars - PROVE Inv' - OBVIOUS + PROVE IInv' + BY DEF Inv <2>1. ASSUME NEW self \in Procs, ncs(self) - PROVE Inv' - BY <2>1 DEF ncs, Inv + PROVE IInv' + BY <2>1 DEF ncs, IInv <2>2. ASSUME NEW self \in Procs, e1(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e1" /\ UNCHANGED <> BY <2>2 DEF e1 <3>1. CASE /\ flag' = [flag EXCEPT ![self] = ~ flag[self]] /\ pc' = [pc EXCEPT ![self] = "e1"] /\ UNCHANGED <> - BY <3>1 DEF Inv + BY <3>1 DEF IInv <3>2. CASE /\ flag' = [flag EXCEPT ![self] = TRUE] /\ unchecked' = [unchecked EXCEPT ![self] = Procs \ {self}] /\ max' = [max EXCEPT ![self] = 0] /\ pc' = [pc EXCEPT ![self] = "e2"] - BY <3>2 DEF Inv + BY <3>2, SMTT(30) DEF IInv <3>. QED BY <3>1, <3>2, <2>2 DEF e1 <2>3. ASSUME NEW self \in Procs, e2(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e2" /\ UNCHANGED << num, flag, nxt >> BY <2>3 DEF e2 @@ -311,117 +352,142 @@ THEOREM Spec => []MutualExclusion num[i] > max[self], max' = [max EXCEPT ![self] = num[i]], pc' = [pc EXCEPT ![self] = "e2"] - PROVE Inv' - BY <3>1, Z3T(10) DEF Inv + PROVE IInv' + \* BY <3>1, SMTT(30) DEF IInv -- works + <4>. SUFFICES ASSUME NEW q \in Procs + PROVE IInv!(q)' + BY DEF IInv + <4>1. CASE q = self + BY <3>1, <4>1 DEF IInv + <4>2. CASE q # self + BY <3>1, <4>2 DEF IInv + <4>. QED BY <4>1, <4>2 <3>2. ASSUME NEW i \in unchecked[self], unchecked' = [unchecked EXCEPT ![self] = unchecked[self] \ {i}], ~(num[i] > max[self]), max' = max, pc' = [pc EXCEPT ![self] = "e2"] - PROVE Inv' - <4>. TypeOK' BY <3>2 DEF Inv - <4>1. \A ii \in Procs : (pc'[ii] \in {"e4", "w1", "w2", "cs"}) => (num'[ii] # 0) - BY <3>2 DEF Inv - <4>2. \A ii \in Procs : (pc'[ii] \in {"e2", "e3"}) => flag'[ii] - BY <3>2 DEF Inv - <4>3. \A ii \in Procs : (pc'[ii] = "w2") => (nxt'[ii] # ii) - BY <3>2 DEF Inv - <4>4. \A ii \in Procs : pc'[ii] \in {(*"e2",*) "w1", "w2"} => ii \notin unchecked'[ii] - BY <3>2 DEF Inv - <4>5. \A ii \in Procs : (pc'[ii] \in {"w1", "w2"}) => - \A j \in (Procs \ unchecked'[ii]) \ {ii} : Before(ii, j)' - BY <3>2 DEF Inv - <4>6. \A ii \in Procs : - /\ (pc'[ii] = "w2") - /\ \/ (pc'[nxt'[ii]] = "e2") /\ (ii \notin unchecked'[nxt'[ii]]) - \/ pc'[nxt'[ii]] = "e3" - => max'[nxt'[ii]] >= num'[ii] - BY <3>2 DEF Inv - <4>7. \A ii \in Procs : (pc'[ii] = "cs") => \A j \in Procs \ {ii} : Before(ii, j)' - BY <3>2 DEF Inv - <4>. QED BY (*<4>0,*) <4>1, <4>2, <4>3, <4>4, <4>5, <4>6, <4>7 DEF Inv + PROVE IInv' + BY <3>2 DEF IInv <3>3. CASE /\ unchecked[self] = {} /\ pc' = [pc EXCEPT ![self] = "e3"] /\ UNCHANGED << unchecked, max >> - BY <3>3 DEF Inv + <4>. SUFFICES ASSUME NEW i \in Procs + PROVE IInv!(i)' + BY DEF IInv + <4>1. CASE i = self + BY <3>3, <4>1 DEF IInv + <4>2. CASE i # self + BY <3>3, <4>2 DEF IInv + <4>. QED BY <4>1, <4>2 <3>. QED BY <3>1, <3>2, <3>3, <2>3 DEF e2 <2>4. ASSUME NEW self \in Procs, e3(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e3" /\ UNCHANGED << flag, unchecked, max, nxt >> BY <2>4 DEF e3 <3>1. CASE /\ \E k \in Nat: num' = [num EXCEPT ![self] = k] /\ pc' = [pc EXCEPT ![self] = "e3"] - BY <3>1 DEF Inv + BY <3>1 DEF IInv <3>2. CASE /\ \E i \in {j \in Nat : j > max[self]}: num' = [num EXCEPT ![self] = i] /\ pc' = [pc EXCEPT ![self] = "e4"] - BY <3>2, SMTT(60) DEF Inv + BY <3>2 DEF IInv <3>3. QED BY <3>1, <3>2, <2>4 DEF e3 <2>5. ASSUME NEW self \in Procs, e4(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e4" /\ UNCHANGED << num, max, nxt >> BY <2>5 DEF e4 <3>1. CASE /\ flag' = [flag EXCEPT ![self] = ~ flag[self]] /\ pc' = [pc EXCEPT ![self] = "e4"] /\ UNCHANGED unchecked - BY <3>1 DEF Inv + BY <3>1 DEF IInv <3>2. CASE /\ flag' = [flag EXCEPT ![self] = FALSE] /\ unchecked' = [unchecked EXCEPT ![self] = Procs \ {self}] /\ pc' = [pc EXCEPT ![self] = "w1"] - BY <3>2, Z3T(30) DEF Inv + BY <3>2 DEF IInv <3>. QED BY <3>1, <3>2, <2>5 DEF e4 <2>6. ASSUME NEW self \in Procs, w1(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "w1" /\ UNCHANGED << num, flag, unchecked, max >> BY <2>6 DEF w1 - <3>1. CASE /\ unchecked[self] # {} - /\ \E i \in unchecked[self]: - nxt' = [nxt EXCEPT ![self] = i] - /\ ~ flag[nxt'[self]] - /\ pc' = [pc EXCEPT ![self] = "w2"] - BY <3>1, Z3 DEF Inv + <3>1. ASSUME NEW i \in unchecked[self], + nxt' = [nxt EXCEPT ![self] = i], + ~ flag[nxt'[self]], + pc' = [pc EXCEPT ![self] = "w2"] + PROVE IInv' + \* BY <3>1, SMTT(30) DEF IInv -- works + <4>. SUFFICES ASSUME NEW j \in Procs + PROVE IInv!(j)' + BY DEF IInv + <4>1. CASE j = self + BY <3>1, <4>1 DEF IInv + <4>2. CASE j # self + BY <3>1, <4>2, SMTT(30) DEF IInv + <4>. QED BY <4>1, <4>2 <3>2. CASE /\ unchecked[self] = {} /\ pc' = [pc EXCEPT ![self] = "cs"] /\ nxt' = nxt - BY <3>2, Z3 DEF Inv + <4>. SUFFICES ASSUME NEW j \in Procs + PROVE IInv!(j)' + BY DEF IInv + <4>1. CASE j = self + BY <3>2, <4>1 DEF IInv + <4>2. CASE j # self + BY <3>2, <4>2, SMTT(30) DEF IInv + <4>. QED BY <4>1, <4>2 <3>. QED BY <3>1, <3>2, <2>6 DEF w1 <2>7. ASSUME NEW self \in Procs, w2(self) - PROVE Inv' - BY <2>7, Z3T(30) DEF w2, Inv + PROVE IInv' + <3>. /\ pc[self] = "w2" + /\ unchecked' = [unchecked EXCEPT ![self] = @ \ {nxt[self]}] + /\ pc' = [pc EXCEPT ![self] = "w1"] + /\ UNCHANGED << num, flag, max, nxt >> + BY <2>7 DEF w2 + <3>1. CASE num[nxt[self]] = 0 + BY <3>1 DEF IInv + <3>2. CASE num[self] < num[nxt[self]] + BY <3>2, SMTT(30) DEF IInv + <3>3. CASE num[self] = num[nxt[self]] /\ self < nxt[self] + BY <3>3, SMTT(30) DEF IInv + <3>. QED BY <2>7, <3>1, <3>2, <3>3 DEF w2 <2>8. ASSUME NEW self \in Procs, cs(self) - PROVE Inv' - BY <2>8, Z3 DEF cs, Inv + PROVE IInv' + \* BY <2>8, SMTT(30) DEF cs, IInv -works + <3>1. \A i,j \in Procs: Before(i,j) => Before(i,j)' + BY <2>8 DEF cs + <3>. HIDE DEF Before + <3>. QED BY <2>8, <3>1 DEF cs, IInv <2>9. ASSUME NEW self \in Procs, exit(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "exit" /\ UNCHANGED << flag, unchecked, max, nxt >> BY <2>9 DEF exit <3>1. CASE /\ \E k \in Nat: num' = [num EXCEPT ![self] = k] /\ pc' = [pc EXCEPT ![self] = "exit"] - BY <3>1 DEF Inv + BY <3>1 DEF IInv <3>2. CASE /\ num' = [num EXCEPT ![self] = 0] /\ pc' = [pc EXCEPT ![self] = "ncs"] - BY <3>2 DEF Inv + BY <3>2 DEF IInv <3>. QED BY <3>1, <3>2, <2>9 DEF exit <2>10. CASE UNCHANGED vars - BY <2>10 DEF vars, Inv + BY <2>10 DEF vars, IInv <2>11. QED BY <2>1, <2>10, <2>2, <2>3, <2>4, <2>5, <2>6, <2>7, <2>8, <2>9 DEF Next, p <1>3. Inv => MutualExclusion - BY SMT DEF MutualExclusion, Inv + BY SMT DEF MutualExclusion, Inv, IInv <1>4. QED - BY <1>1, <1>2, <1>3, PTL DEF Spec + BY <1>1, <1>2, <1>3, TypeCorrect, PTL DEF Spec, Inv ------------------------------------------------------------------------------ Trying(i) == pc[i] = "e1" InCS(i) == pc[i] = "cs" @@ -429,45 +495,15 @@ DeadlockFree == (\E i \in Procs : Trying(i)) ~> (\E i \in Procs : InCS(i)) StarvationFree == \A i \in Procs : Trying(i) ~> InCS(i) ----------------------------------------------------------------------------- -II == \A i \in Procs : -\* /\ (pc[i] \in {"ncs", "e1", "e2"}) => (num[i] = 0) \* not found Test 1 (21993 states) - /\ (pc[i] \in {"e4", "w1", "w2", "cs"}) => (num[i] # 0) \* found Test 1 - /\ (pc[i] \in {"e2", "e3"}) => flag[i] \* found Test 1 - /\ (pc[i] = "w2") => (nxt[i] # i) \* not found Test 1 (12115 states) or with N=2 - /\ pc[i] \in {"e2", "w1", "w2"} => i \notin unchecked[i] \* found Test 1 - /\ (pc[i] \in {"w1", "w2"}) => \* found Test 1 - \A j \in (Procs \ unchecked[i]) \ {i} : Before(i, j) - /\ /\ (pc[i] = "w2") \* found Test 1 - /\ \/ (pc[nxt[i]] = "e2") /\ (i \notin unchecked[nxt[i]]) - \/ pc[nxt[i]] = "e3" - => max[nxt[i]] >= num[i] - /\ (pc[i] = "cs") => \A j \in Procs \ {i} : Before(i, j) \* found Test 1 - -IInit == /\ num \in [Procs -> Nat] - /\ flag \in [Procs -> BOOLEAN] - /\ unchecked \in [Procs -> SUBSET Procs] - /\ max \in [Procs -> Nat] - /\ nxt \in [Procs -> Procs] - /\ pc \in [Procs -> {"ncs", "e1", "e2", "e3", - "e4", "w1", "w2", "cs", "exit"}] - /\ II - -ISpec == IInit /\ [][Next]_vars +(***************************************************************************) +(* The following spec can be used to check inductiveness of the invariant *) +(* with the help of TLC. *) +(***************************************************************************) +ISpec == Inv /\ [][Next]_vars ============================================================================= \* Modification History -\* Last modified Mon Mar 06 13:47:10 CET 2023 by merz -\* Last modified Tue Aug 27 12:23:10 PDT 2019 by loki -\* Last modified Sat May 19 16:40:23 CEST 2018 by merz -\* Last modified Thu May 17 07:02:45 PDT 2018 by lamport \* Created Thu Nov 21 15:54:32 PST 2013 by lamport Test 1: 5248 distinct initial states 151056 full initial states -IInit == /\ num \in [Procs -> Nat] - /\ flag \in [Procs -> BOOLEAN] - /\ unchecked \in [Procs -> SUBSET Procs] - /\ max \in [Procs -> {0}] \* Nat] - /\ nxt \in [Procs -> {1}] - /\ pc \in [Procs -> {"ncs", "e1", "e2", "e3", - "e4", "w1", "w2", "cs"}] - /\ II +IInit == TypeOK /\ IInv diff --git a/specifications/Bakery-Boulangerie/Boulanger.pdf b/specifications/Bakery-Boulangerie/Boulanger.pdf deleted file mode 100644 index 87005b03..00000000 Binary files a/specifications/Bakery-Boulangerie/Boulanger.pdf and /dev/null differ diff --git a/specifications/Bakery-Boulangerie/Boulanger.tla b/specifications/Bakery-Boulangerie/Boulanger.tla index 5aa0e89d..52ef212e 100644 --- a/specifications/Bakery-Boulangerie/Boulanger.tla +++ b/specifications/Bakery-Boulangerie/Boulanger.tla @@ -300,6 +300,47 @@ TypeOK == /\ num \in [Procs -> Nat] "e4", "w1", "w2", "cs", "exit"}] /\ previous \in [Procs -> Nat \cup {-1}] +THEOREM TypeCorrect == Spec => []TypeOK +<1>. USE N \in Nat DEF Procs, ProcSet +<1>1. Init => TypeOK + BY DEF Init, TypeOK +<1>2. TypeOK /\ [Next]_vars => TypeOK' + <2>. SUFFICES ASSUME TypeOK, [Next]_vars + PROVE TypeOK' + OBVIOUS + <2>1. ASSUME NEW self \in Procs, ncs(self) + PROVE TypeOK' + BY <2>1 DEF TypeOK, ncs + <2>2. ASSUME NEW self \in Procs, e1(self) + PROVE TypeOK' + BY <2>2 DEF TypeOK, e1 + <2>3. ASSUME NEW self \in Procs, e2(self) + PROVE TypeOK' + BY <2>3 DEF TypeOK, e2 + <2>4. ASSUME NEW self \in Procs, e3(self) + PROVE TypeOK' + BY <2>4 DEF TypeOK, e3 + <2>5. ASSUME NEW self \in Procs, e4(self) + PROVE TypeOK' + BY <2>5 DEF TypeOK, e4 + <2>6. ASSUME NEW self \in Procs, w1(self) + PROVE TypeOK' + BY <2>6 DEF TypeOK, w1 + <2>7. ASSUME NEW self \in Procs, w2(self) + PROVE TypeOK' + BY <2>7 DEF TypeOK, w2 + <2>8. ASSUME NEW self \in Procs, cs(self) + PROVE TypeOK' + BY <2>8 DEF TypeOK, cs + <2>9. ASSUME NEW self \in Procs, exit(self) + PROVE TypeOK' + BY <2>9 DEF TypeOK, exit + <2>10. CASE UNCHANGED vars + BY <2>10 DEF TypeOK, vars + <2>. QED + BY <2>1, <2>2, <2>3, <2>4, <2>5, <2>6, <2>7, <2>8, <2>9, <2>10 DEF Next, p +<1>. QED BY <1>1, <1>2, PTL DEF Spec + (***************************************************************************) (* Before(i, j) is a condition that implies that num[i] > 0 and, if j is *) (* trying to enter its critical section and i does not change num[i], then *) @@ -327,8 +368,7 @@ Before(i,j) == /\ num[i] > 0 (***************************************************************************) (* Inv is the complete inductive invariant. *) (***************************************************************************) -Inv == /\ TypeOK - /\ \A i \in Procs : +IInv == \A i \in Procs : /\ (pc[i] \in {"ncs", "e1", "e2"}) => (num[i] = 0) /\ (pc[i] \in {"e4", "w1", "w2", "cs"}) => (num[i] # 0) /\ (pc[i] \in {"e2", "e3"}) => flag[i] @@ -346,6 +386,8 @@ Inv == /\ TypeOK /\ pc[nxt[i]] \in {"e4", "w1", "w2", "cs"} => Before(i, nxt[i]) /\ (pc[i] = "cs") => \A j \in Procs \ {i} : Before(i, j) + +Inv == TypeOK /\ IInv ----------------------------------------------------------------------------- (***************************************************************************) (* Proof of Mutual Exclusion *) @@ -360,36 +402,46 @@ THEOREM Spec => []MutualExclusion <1> USE N \in Nat DEFS Procs, TypeOK, Before, \prec, ProcSet <1>1. Init => Inv - BY SMT DEF Init, Inv - -<1>2. Inv /\ [Next]_vars => Inv' - <2> SUFFICES ASSUME Inv, + BY DEF Init, Inv, IInv + +<1>2. Inv /\ [Next]_vars => IInv' + <2> SUFFICES ASSUME TypeOK, IInv, [Next]_vars - PROVE Inv' - OBVIOUS + PROVE IInv' + BY DEF Inv <2>1. ASSUME NEW self \in Procs, ncs(self) - PROVE Inv' - BY <2>1, Z3 DEF ncs, Inv + PROVE IInv' + <3>. /\ pc[self] = "ncs" + /\ pc' = [pc EXCEPT ![self] = "e1"] + /\ UNCHANGED << num, flag, unchecked, max, nxt, previous >> + BY <2>1 DEF ncs + <3>. SUFFICES ASSUME NEW i \in Procs PROVE IInv!(i)' + BY DEF IInv + <3>1. CASE i = self + BY <3>1 DEF IInv + <3>2. CASE i # self + BY <3>2, Zenon DEF IInv + <3>. QED BY <3>1, <3>2 <2>2. ASSUME NEW self \in Procs, e1(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e1" /\ UNCHANGED << num, nxt, previous >> BY <2>2 DEF e1 <3>1. CASE /\ flag' = [flag EXCEPT ![self] = ~ flag[self]] /\ pc' = [pc EXCEPT ![self] = "e1"] /\ UNCHANGED <> - BY <3>1 DEF Inv + BY <3>1 DEF IInv <3>2. CASE /\ flag' = [flag EXCEPT ![self] = TRUE] /\ unchecked' = [unchecked EXCEPT ![self] = Procs \ {self}] /\ max' = [max EXCEPT ![self] = 0] /\ pc' = [pc EXCEPT ![self] = "e2"] - BY <3>2 DEF Inv + BY <3>2 DEF IInv <3>. QED BY <3>1, <3>2, <2>2 DEF e1 <2>3. ASSUME NEW self \in Procs, e2(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e2" /\ UNCHANGED << num, flag, nxt, previous >> BY <2>3 DEF e2 @@ -398,75 +450,126 @@ THEOREM Spec => []MutualExclusion num[i] > max[self], max' = [max EXCEPT ![self] = num[i]], pc' = [pc EXCEPT ![self] = "e2"] - PROVE Inv' - BY <3>1, Z3 DEF Inv + PROVE IInv' + BY <3>1 DEF IInv <3>2. ASSUME NEW i \in unchecked[self], unchecked' = [unchecked EXCEPT ![self] = unchecked[self] \ {i}], ~(num[i] > max[self]), max' = max, pc' = [pc EXCEPT ![self] = "e2"] - PROVE Inv' - BY <3>2, Z3 DEF Inv + PROVE IInv' + \* BY <3>2, SMTT(30) DEF IInv -works + <4>. SUFFICES ASSUME NEW j \in Procs, IInv!(j) PROVE IInv!(j)' + BY DEF IInv + <4>1. CASE j = self + BY <3>2, <4>1 + <4>2. CASE j # self + BY <3>2, <4>2 + <4>. QED BY <4>1, <4>2 <3>3. CASE /\ unchecked[self] = {} /\ pc' = [pc EXCEPT ![self] = "e3"] /\ UNCHANGED << unchecked, max >> - BY <3>3, Z3 DEF Inv + <4>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <4>1. CASE i = self + BY <3>3, <4>1 + <4>2. CASE i # self + BY <3>3, <4>2 + <4>. QED BY <4>1, <4>2 <3>. QED BY <3>1, <3>2, <3>3, <2>3 DEF e2 <2>4. ASSUME NEW self \in Procs, e3(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e3" /\ UNCHANGED << flag, unchecked, max, nxt, previous >> BY <2>4 DEF e3 <3>1. CASE /\ \E k \in Nat: num' = [num EXCEPT ![self] = k] /\ pc' = [pc EXCEPT ![self] = "e3"] - BY <3>1, Z3 DEF Inv + BY <3>1 DEF IInv <3>2. CASE /\ num' = [num EXCEPT ![self] = max[self] + 1] /\ pc' = [pc EXCEPT ![self] = "e4"] - BY <3>2, Z3 DEF Inv + BY <3>2 DEF IInv <3>. QED BY <3>1, <3>2, <2>4 DEF e3 <2>5. ASSUME NEW self \in Procs, e4(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "e4" /\ UNCHANGED << num, max, nxt, previous >> BY <2>5 DEF e4 <3>1. CASE /\ flag' = [flag EXCEPT ![self] = ~ flag[self]] /\ pc' = [pc EXCEPT ![self] = "e4"] /\ UNCHANGED unchecked - BY <3>1, Z3 DEF Inv + BY <3>1 DEF IInv <3>2. CASE /\ flag' = [flag EXCEPT ![self] = FALSE] /\ num[self] = 1 /\ unchecked' = [unchecked EXCEPT ![self] = 1..(self-1)] /\ pc' = [pc EXCEPT ![self] = "w1"] - BY <3>2, Z3 DEF Inv + \* BY <3>2, SMTT(30) DEF IInv -- works + <4>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <4>1. CASE i = self + BY <3>2, <4>1 + <4>2. CASE i # self + \* BY <3>2, <4>2, SMTT(30) -- works + <5>1. \A k,l \in Procs : Before(k,l) => Before(k,l)' + BY <3>2 + <5>2. Before(i, nxt[i]) => Before(i, nxt[i])' + BY <5>1 + <5>. HIDE DEF Before + <5>. QED BY <3>2, <4>2, <5>1, <5>2 + <4>. QED BY <4>1, <4>2 <3>3. CASE /\ flag' = [flag EXCEPT ![self] = FALSE] /\ num[self] # 1 /\ unchecked' = [unchecked EXCEPT ![self] = Procs \ {self}] /\ pc' = [pc EXCEPT ![self] = "w1"] - BY <3>3, Z3 DEF Inv + \* BY <3>3, SMTT(30) DEF IInv -- works + <4>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <4>1. CASE i = self + BY <3>3, <4>1 + <4>2. CASE i # self + BY <3>3, <4>2 + <4>. QED BY <4>1, <4>2 <3>. QED BY <3>1, <3>2, <3>3, <2>5 DEF e4 <2>6. ASSUME NEW self \in Procs, w1(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "w1" /\ UNCHANGED << num, flag, unchecked, max >> BY <2>6 DEF w1 - <3>1. CASE /\ unchecked[self] # {} - /\ \E i \in unchecked[self]: - nxt' = [nxt EXCEPT ![self] = i] - /\ ~ flag[nxt'[self]] - /\ previous' = [previous EXCEPT ![self] = -1] - /\ pc' = [pc EXCEPT ![self] = "w2"] - BY <3>1, Z3 DEF Inv + <3>1. ASSUME NEW j \in unchecked[self], + nxt' = [nxt EXCEPT ![self] = j], + ~ flag[j], + previous' = [previous EXCEPT ![self] = -1], + pc' = [pc EXCEPT ![self] = "w2"] + PROVE IInv' + <4>. pc[j] \notin {"e2", "e3"} + BY <3>1 DEF IInv + <4>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <4>1. CASE i = self + BY <3>1, <4>1 + <4>2. CASE i # self + BY <3>1, <4>2 + <4>. QED BY <3>1 <3>2. CASE /\ unchecked[self] = {} /\ pc' = [pc EXCEPT ![self] = "cs"] /\ UNCHANGED << nxt, previous >> - BY <3>2, Z3 DEF Inv + \* BY <3>2, SMTT(30) DEF IInv -- works + <4>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <4>1. CASE i = self + BY <3>2, <4>1 + <4>2. CASE i # self + <5>1. \A j \in Procs : Before(i,j) => Before(i,j)' + BY <3>2, <4>2 + <5>. HIDE DEF Before + <5>. QED BY <3>2, <4>2, <5>1 + <4>. QED BY <4>1, <4>2 <3>. QED BY <3>1, <3>2, <2>6 DEF w1 <2>7. ASSUME NEW self \in Procs, w2(self) - PROVE Inv' + PROVE IInv' <3>. /\ pc[self] = "w2" /\ UNCHANGED << num, flag, max, nxt >> BY <2>7 DEF w2 @@ -475,64 +578,82 @@ THEOREM Spec => []MutualExclusion \/ /\ previous[self] # -1 /\ num[nxt[self]] # previous[self] /\ unchecked' = [unchecked EXCEPT ![self] = unchecked[self] \ {nxt[self]}] - /\ unchecked'[self] = {} - /\ pc' = [pc EXCEPT ![self] = "cs"] /\ UNCHANGED previous - BY <3>1, Z3 DEF Inv - <3>2. CASE /\ \/ num[nxt[self]] = 0 - \/ <> \prec <> - \/ /\ previous[self] # -1 - /\ num[nxt[self]] # previous[self] - /\ unchecked' = [unchecked EXCEPT ![self] = unchecked[self] \ {nxt[self]}] - /\ unchecked'[self] # {} - /\ pc' = [pc EXCEPT ![self] = "w1"] - /\ UNCHANGED previous - BY <3>2, Z3 DEF Inv - <3>3. CASE /\ ~ \/ num[nxt[self]] = 0 + <4>1. Before(self, nxt[self]) + <5>0. /\ IInv!(self) /\ IInv!(nxt[self]) + /\ num[self] > 0 + BY DEF IInv + <5>. HIDE DEF Before + <5>1. pc[nxt[self]] \in {"e4", "w1", "w2", "cs"} + => \/ <> \prec <> + \/ Before(self, nxt[self]) + BY <3>1 DEF IInv + <5>2. ASSUME pc[nxt[self]] \in {"w1", "w2", "cs"}, + Before(nxt[self], self) + PROVE FALSE + <6>1. /\ num[nxt[self]] > 0 + /\ <> \prec <> + BY <5>0, <5>2 DEF Before + <6>2. Before(self, nxt[self]) + BY <3>1, <5>1, <5>2, <6>1 DEF IInv + <6>. QED BY <5>2, <6>2 DEF Before + <5>3. /\ pc[nxt[self]] \in {"w1", "w2"} => self \in unchecked[nxt[self]] + /\ pc[nxt[self]] # "cs" + BY <5>0, <5>2 + <5>. QED BY <5>0, <5>1, <5>3 DEF Before + <4>2. CASE /\ unchecked'[self] = {} + /\ pc' = [pc EXCEPT ![self] = "cs"] + <5>1. unchecked[self] \subseteq {nxt[self]} + BY <3>1, <4>2, Zenon + <5>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <5>. QED BY <3>1, <4>1, <4>2, <5>1 + <4>3. CASE /\ unchecked'[self] # {} + /\ pc' = [pc EXCEPT ![self] = "w1"] + <5>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <5>. QED BY <3>1, <4>1, <4>3 + <4>. QED BY <2>7, <3>1, <4>2, <4>3 DEF w2 + <3>2. CASE /\ ~ \/ num[nxt[self]] = 0 \/ <> \prec <> \/ /\ previous[self] # -1 /\ num[nxt[self]] # previous[self] /\ previous' = [previous EXCEPT ![self] = num[nxt[self]]] /\ pc' = [pc EXCEPT ![self] = "w2"] /\ UNCHANGED unchecked - BY <3>3, Z3 DEF Inv - <3>. QED BY <3>1, <3>2, <3>3, <2>7 DEF w2 + BY <3>2 DEF IInv + <3>. QED BY <3>1, <3>2, <2>7 DEF w2 <2>8. ASSUME NEW self \in Procs, cs(self) - PROVE Inv' - BY <2>8, Z3 DEF cs, Inv + PROVE IInv' + \* BY <2>8, SMTT(30) DEF cs, IInv -- works + <3>1. \A i,j \in Procs : Before(i,j) => Before(i,j)' + BY <2>8 DEF cs + <3>. HIDE DEF Before + <3>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <3>. QED BY <2>8, <3>1 DEF cs <2>9. ASSUME NEW self \in Procs, exit(self) - PROVE Inv' - <3>. /\ pc[self] = "exit" - /\ UNCHANGED << flag, unchecked, max, nxt, previous >> - BY <2>9 DEF exit - <3>1. CASE /\ \E k \in Nat: num' = [num EXCEPT ![self] = k] - /\ pc' = [pc EXCEPT ![self] = "exit"] - BY <3>1, Z3 DEF Inv - <3>2. CASE /\ num' = [num EXCEPT ![self] = 0] - /\ pc' = [pc EXCEPT ![self] = "ncs"] - BY <3>2, Z3 DEF Inv - <3>. QED BY <3>1, <3>2, <2>9 DEF exit + PROVE IInv' + \* BY <2>9, SMTT(30) DEF exit, IInv --works + <3>. SUFFICES ASSUME NEW i \in Procs, IInv!(i) PROVE IInv!(i)' + BY DEF IInv + <3>. QED BY <2>9 DEF exit <2>10. CASE UNCHANGED vars - BY <2>10, Z3 DEF vars, Inv + BY <2>10 DEF vars, IInv <2>11. QED - BY <2>1, <2>10, <2>2, <2>3, <2>4, <2>5, <2>6, <2>7, <2>8, <2>9 DEF Next, p + BY <2>1, <2>2, <2>3, <2>4, <2>5, <2>6, <2>7, <2>8, <2>9, <2>10 DEF Next, p <1>3. Inv => MutualExclusion - BY SMT DEF Inv, MutualExclusion + BY DEF Inv, IInv, MutualExclusion <1>4. QED - BY <1>1, <1>2, <1>3, PTL DEF Spec + BY <1>1, <1>2, <1>3, TypeCorrect, PTL DEF Spec, Inv ------------------------------------------------------------------------------ Trying(i) == pc[i] = "e1" InCS(i) == pc[i] = "cs" DeadlockFree == (\E i \in Procs : Trying(i)) ~> (\E i \in Procs : InCS(i)) StarvationFree == \A i \in Procs : Trying(i) ~> InCS(i) ============================================================================= -\* Modification History -\* Last modified Tue Aug 27 12:22:38 PDT 2019 by loki -\* Last modified Thu May 24 20:03:58 CEST 2018 by merz -\* Last modified Thu May 24 13:49:22 CEST 2018 by merz -\* Last modified Tue Jul 21 17:55:23 PDT 2015 by lamport \* Created Thu Nov 21 15:54:32 PST 2013 by lamport diff --git a/specifications/FiniteMonotonic/CRDT.tla b/specifications/FiniteMonotonic/CRDT.tla index ea5cfa10..a337cb44 100644 --- a/specifications/FiniteMonotonic/CRDT.tla +++ b/specifications/FiniteMonotonic/CRDT.tla @@ -1,8 +1,9 @@ ------------------------------- MODULE CRDT --------------------------------- -EXTENDS Naturals +EXTENDS Naturals, FiniteSets CONSTANT Node +ASSUME NodeAssumption == IsFiniteSet(Node) VARIABLE counter vars == counter @@ -39,9 +40,8 @@ Spec == /\ Init /\ [][Next]_counter -THEOREM Spec => []Safety -THEOREM Spec => []TypeOK +----------------------------------------------------------------------------- (***************************************************************************) (* Fairness and liveness assumptions. *) (* We assume that Gossip actions will eventually occur when enabled, and *) @@ -58,7 +58,5 @@ FairSpec == /\ Spec /\ Fairness -THEOREM FairSpec => Convergence -THEOREM FairSpec => Monotonicity ============================================================================= diff --git a/specifications/FiniteMonotonic/CRDT_proof.tla b/specifications/FiniteMonotonic/CRDT_proof.tla index ce3f62b9..a8ce9f98 100644 --- a/specifications/FiniteMonotonic/CRDT_proof.tla +++ b/specifications/FiniteMonotonic/CRDT_proof.tla @@ -1,7 +1,5 @@ ------------------------------- MODULE CRDT_proof --------------------------------- -EXTENDS CRDT, Naturals, FiniteSets, NaturalsInduction, TLAPS - -ASSUME NodeAssumption == IsFiniteSet(Node) +EXTENDS CRDT, Functions, NaturalsInduction, TLAPS (***************************************************************************) (* Proofs of safety properties. *) @@ -26,21 +24,12 @@ THEOREM Spec => Monotonicity <1>1. TypeOK /\ [Next]_vars => [Monotonic]_vars BY DEF TypeOK, Safety, Next, Increment, Gossip, vars, Monotonic <1>. QED BY <1>1, TypeCorrect, PTL DEF Spec, Monotonicity, vars - ----------------------------------------------------------------------------- (***************************************************************************) -(* Auxiliary definitions in preparation for the liveness proof. *) -(* Sum the values of a vector of natural numbers indexed by Node. *) -(* This operator could be defined using a Fold, but since there is no *) -(* library of theorems about Fold, we define it directly from scratch. *) -(* We then state a few facts about Sum, without proof. *) +(* Sum the values of a vector of natural numbers. We state a few facts *) +(* about Sum, without proof. *) (***************************************************************************) -Sum(f) == - LET SumS[S \in SUBSET Node] == - IF S = {} THEN 0 - ELSE LET x == CHOOSE x \in S : TRUE - IN f[x] + SumS[S \ {x}] - IN SumS[Node] +Sum(f) == FoldFunction(+, 0, f) LEMMA SumType == ASSUME NEW f \in [Node -> Nat] @@ -65,6 +54,285 @@ LEMMA SumStronglyMonotonic == PROVE Sum(f) < Sum(g) PROOF OMITTED +(***************************************************************************) +(* Definition of the termination measure. *) +(* Distance(o) sums the differences between node o's knowledge of the *) +(* counters of other nodes and their true values. *) +(* Measure sums Distance(o), for all nodes o. *) +(* We prove elementary facts about the termination measure and in *) +(* particular show how the Gossip action interacts with it. *) +(***************************************************************************) +DistFun(o) == [n \in Node |-> counter[n][n] - counter[o][n]] + +Distance(o) == Sum(DistFun(o)) + +Measure == Sum([o \in Node |-> Distance(o)]) + +LEMMA MeasureType == + ASSUME TypeOK, Safety + PROVE /\ \A o \in Node : DistFun(o) \in [Node -> Nat] + /\ \A o \in Node : Distance(o) \in Nat + /\ Measure \in Nat +<1>. ASSUME NEW o \in Node + PROVE DistFun(o) \in [Node -> Nat] + BY DEF TypeOK, Safety, DistFun +<1>. QED BY SumType, Zenon DEF Distance, Measure + +\* We need a copy of the above theorem where all variables are primed. +\* One could derive this from MeasureType using PTL, but we just copy +\* and paste the proof. +LEMMA MeasureTypePrime == + ASSUME TypeOK', Safety' + PROVE /\ \A o \in Node : DistFun(o)' \in [Node -> Nat] + /\ \A o \in Node : Distance(o)' \in Nat + /\ Measure' \in Nat +<1>. ASSUME NEW o \in Node + PROVE DistFun(o)' \in [Node -> Nat] + BY DEF TypeOK, Safety, DistFun +<1>. QED BY SumType, Zenon DEF Distance, Measure + +\* The termination measure is zero iff all nodes agree on the +\* counter values of all nodes. +LEMMA MeasureIsZero == + ASSUME TypeOK, Safety + PROVE /\ \A o \in Node : Distance(o) = 0 + <=> \A n \in Node : counter[o][n] = counter[n][n] + /\ Measure = 0 + <=> \A v,w,n \in Node : counter[v][n] = counter[w][n] +<1>1. ASSUME NEW o \in Node, Distance(o) = 0, NEW n \in Node + PROVE counter[o][n] = counter[n][n] + BY <1>1, MeasureType, SumIsZero DEF Distance, DistFun, TypeOK, Safety +<1>2. ASSUME NEW o \in Node, \A n \in Node : counter[o][n] = counter[n][n] + PROVE Distance(o) = 0 + BY <1>2, MeasureType, SumIsZero DEF Distance, DistFun, TypeOK +<1>3. ASSUME Measure = 0, NEW v \in Node, NEW w \in Node, NEW n \in Node + PROVE counter[v][n] = counter[w][n] + BY <1>1, <1>3, MeasureType, SumIsZero DEF Measure +<1>4. ASSUME \A v,w,n \in Node : counter[v][n] = counter[w][n] + PROVE Measure = 0 + BY <1>2, <1>4, MeasureType, SumIsZero DEF Measure +<1>. QED BY <1>1, <1>2, <1>3, <1>4 + +\* A Gossip action will never increase the measure. +LEMMA GossipDoesntIncreaseMeasure == + ASSUME TypeOK, TypeOK', Safety, Safety', + [\E n,o \in Node : Gossip(n,o)]_vars + PROVE /\ \A v,w \in Node : DistFun(v)'[w] <= DistFun(v)[w] + /\ \A v \in Node : Distance(v)' <= Distance(v) + /\ Measure' <= Measure +<1>1. CASE \E n,o \in Node : Gossip(n,o) + <2>1. PICK n \in Node, o \in Node : Gossip(n,o) + BY <1>1 + <2>2. ASSUME NEW v \in Node, NEW w \in Node + PROVE DistFun(v)'[w] <= DistFun(v)[w] + <3>1. CASE w = o + BY <2>1, <2>1 DEF Gossip, DistFun, TypeOK, Safety + <3>2. CASE w # o + BY <2>1, <3>2 DEF Gossip, DistFun, TypeOK + <3>. QED BY <3>1, <3>2 + <2>. QED + BY <2>2, SumWeaklyMonotonic, MeasureType, MeasureTypePrime, Zenon + DEF Distance, Measure +<1>2. CASE UNCHANGED vars + BY <1>2, MeasureType DEF DistFun, Distance, Measure, vars +<1>. QED BY <1>1, <1>2 + +\* A non-stuttering Gossip action decreases the measure. +LEMMA GossipDecreasesMeasure == + ASSUME TypeOK, TypeOK', Safety, Safety', + <<\E n,o \in Node : Gossip(n,o)>>_vars + PROVE Measure' < Measure +<1>. PICK n \in Node, o \in Node : <>_vars + OBVIOUS +<1>1. PICK v \in Node : counter[o][v] < counter[n][v] + BY DEF Gossip, vars, TypeOK +<1>2. DistFun(o)'[v] < DistFun(o)[v] + BY <1>1 DEF Gossip, vars, TypeOK, Safety, DistFun +<1>. QED + BY <1>2, GossipDoesntIncreaseMeasure, SumStronglyMonotonic, + MeasureType, MeasureTypePrime, Zenon + DEF Distance, Measure + +----------------------------------------------------------------------------- +(***************************************************************************) +(* Proof of the convergence property for the specification with fairness. *) +(***************************************************************************) + +\* First prove when <>_vars is enabled. + +LEMMA EnabledGossip == + ASSUME NEW n \in Node, NEW o \in Node, TypeOK + PROVE (ENABLED <>_vars) <=> + \E v \in Node : counter[o][v] < counter[n][v] +<1>. USE DEF TypeOK +<1>1. ASSUME ENABLED <>_vars + PROVE \E v \in Node : counter[o][v] < counter[n][v] + <2>. CASE <>_counter + BY DEF Gossip + <2>. QED BY <1>1, ExpandENABLED DEF Gossip, vars +<1>2. ASSUME NEW v \in Node, counter[o][v] < counter[n][v] + PROVE ENABLED <>_vars + <2>. DEFINE Max(a, b) == IF a > b THEN a ELSE b + ctr == [counter EXCEPT ![o] = + [nv \in Node |-> Max(counter[n][nv], counter[o][nv])]] + <2>. ctr[o][v] # counter[o][v] + BY <1>2 + <2>. QED BY ExpandENABLED, Zenon DEF Gossip, vars +<1>. QED BY <1>1, <1>2 + +(***************************************************************************) +(* We now prove convergence for the tail of the behavior in which only *) +(* Gossip actions may occur. For convenience, we define a TLA+ *) +(* specification characterizing this eventual behavior. *) +(***************************************************************************) + +OGSpec == + /\ [](TypeOK /\ Safety) + /\ [][\E n, o \in Node : Gossip(n,o)]_vars + /\ [](\A n, o \in Node : WF_vars(Gossip(n,o))) + +\* The following theorem is central to establishing liveness. +\* Its proof is quite tedious because of a delicate interplay of +\* predicate and temporal logic reasoning. +THEOREM OGLiveness == OGSpec => <>(\A n, o \in Node : counter[n] = counter[o]) +<1>. DEFINE Q == \A n, o \in Node : counter[n] = counter[o] + P(m) == Measure = m + L(m) == [](P(m) => <>Q) +<1>1. ASSUME NEW m \in Nat, + \* must explicitly "box" the following assumption, + \* otherwise PTL reasoning fails below. + [](\A k \in 0 .. (m-1) : OGSpec => L(k)) + PROVE [](OGSpec => L(m)) + <2>. DEFINE OGNext == \E n, o \in Node : Gossip(n,o) + <2>1. CASE m = 0 + <3>1. TypeOK /\ Safety /\ P(m) => Q + BY <2>1, MeasureIsZero DEF TypeOK + <3>. QED BY <3>1, PTL DEF OGSpec + <2>2. CASE m > 0 + <3>1. OGSpec => [](P(m) => [](\E k \in 0 .. m : P(k))) + <4>1. TypeOK /\ Safety /\ P(m) => \E k \in 0 .. m : P(k) + BY MeasureType + <4>2. /\ TypeOK /\ Safety /\ TypeOK' /\ Safety' + /\ \E k \in 0 .. m : P(k) + /\ [OGNext]_vars + => (\E k \in 0 .. m : P(k))' + BY MeasureTypePrime, GossipDoesntIncreaseMeasure + <4>. QED BY <4>1, <4>2, PTL DEF OGSpec + <3>5. OGSpec => [](P(m) /\ <><>_vars => <> \E k \in 0 .. (m-1) : P(k)) + <4>1. /\ TypeOK /\ Safety /\ TypeOK' /\ Safety' + /\ \E k \in 0 .. m : P(k) + /\ <>_vars + => (\E k \in 0 .. (m-1) : P(k))' + BY MeasureTypePrime, GossipDecreasesMeasure + <4>. QED BY <3>1, <4>1, PTL DEF OGSpec + <3>6. OGSpec => [](P(m) /\ [][~OGNext]_vars => <> \E k \in 0 .. (m-1) : P(k)) + <4>. DEFINE C(n,o) == counter[o][n] < counter[n][n] + <4>1. OGSpec /\ [][~OGNext]_vars /\ P(m) => \E u,v \in Node : []C(u,v) + <5>1. TypeOK /\ Safety /\ P(m) => \E u,v \in Node : C(u,v) + <6>. SUFFICES ASSUME TypeOK, Safety, P(m) + PROVE \E n,o \in Node : C(n,o) + OBVIOUS + <6>1. PICK a,b,c \in Node : counter[a][c] # counter[b][c] + BY <2>2, MeasureType, MeasureIsZero + <6>2. CASE counter[a][c] < counter[b][c] + BY <6>1, <6>2 DEF Safety, TypeOK + <6>3. CASE counter[b][c] < counter[a][c] + BY <6>1, <6>3 DEF Safety, TypeOK + <6>. QED BY <6>1, <6>2, <6>3 DEF TypeOK + <5>2. OGSpec /\ [][~OGNext]_vars /\ P(m) => \E u,v \in Node : C(u,v) + BY <5>1, PTL DEF OGSpec + <5>3. OGSpec /\ [][~OGNext]_vars => \A u,v \in Node : C(u,v) => []C(u,v) + <6>. SUFFICES ASSUME NEW u \in Node, NEW v \in Node + PROVE C(u,v) /\ [][OGNext]_vars /\ [][~OGNext]_vars => []C(u,v) + BY DEF OGSpec + <6>. C(u,v) /\ [OGNext]_vars /\ [~OGNext]_vars => C(u,v)' + BY DEF vars + <6>. QED BY PTL + <5>. QED BY <5>2, <5>3 + <4>2. OGSpec /\ [](\E k \in 0 .. m : P(k)) /\ (\E u,v \in Node : []C(u,v)) + => <> \E k \in 0 .. (m-1) : P(k) + <5>. SUFFICES + ASSUME NEW u \in Node, NEW v \in Node + PROVE OGSpec /\ [](\E k \in 0 .. m : P(k)) /\ []C(u,v) + => <> \E k \in 0 .. (m-1) : P(k) + OBVIOUS + <5>1. TypeOK /\ C(u,v) => ENABLED <>_vars + BY EnabledGossip + <5>2. /\ TypeOK /\ TypeOK' /\ Safety /\ Safety' + /\ \E k \in 0 .. m : P(k) + /\ <>_vars + => (\E k \in 0 .. (m-1) : P(k))' + BY MeasureTypePrime, GossipDecreasesMeasure + <5>3. OGSpec => WF_vars(Gossip(u,v)) + <6>1. (\A n,o \in Node : WF_vars(Gossip(n,o))) => WF_vars(Gossip(u,v)) + OBVIOUS + <6>. QED BY <6>1, PTL DEF OGSpec + <5>. QED BY <5>1, <5>2, <5>3, PTL DEF OGSpec + <4>. HIDE DEF OGNext, P, C + <4>3. OGSpec /\ [][~OGNext]_vars /\ P(m) /\ [](\E k \in 0 .. m : P(k)) + => <>(\E k \in 0 .. (m-1) : P(k)) + BY <4>1, <4>2 + <4>. QED BY <3>1, <4>3, PTL DEF OGSpec + <3>7. OGSpec => [](P(m) => <> \E k \in 0 .. (m-1) : P(k)) + BY <3>5, <3>6, PTL + <3>8. OGSpec => []((\E k \in 0 .. (m-1) : P(k)) => <>Q) + <4>1. (\A k \in 0 .. (m-1) : OGSpec => L(k)) + => (OGSpec => [](\A k \in 0 .. (m-1) : P(k) => <>Q)) + OBVIOUS + <4>2. (\A k \in 0 .. (m-1) : P(k) => <>Q) + => ((\E k \in 0 .. (m-1) : P(k)) => <>Q) + OBVIOUS + <4>. QED BY <1>1, <4>1, <4>2, PTL + <3>. QED BY <3>7, <3>8, PTL + <2>. QED BY <2>1, <2>2 +<1>. DEFINE S(m) == [](OGSpec => L(m)) +\* The following step just commutes [] and \A in the assumption of <1>1 +\* so that we can apply the induction theorem in the following step. +<1>2. ASSUME NEW m \in Nat, + \A k \in 0 .. (m-1) : S(k) + PROVE S(m) + BY <1>1 +<1>3. \A m \in Nat : S(m) + <2>. HIDE DEF S + <2>. QED BY <1>2, GeneralNatInduction, Isa +\* Now turn the outermost universal quantifier into an existential quantifier +\* on the left-hand side of the consequent. +<1>4. OGSpec => []((\E m \in Nat : P(m)) => <>Q) + <2>1. (\A m \in Nat : P(m) => <> Q) => ((\E m \in Nat : P(m)) => <>Q) + OBVIOUS + <2>2. [](\A m \in Nat : P(m) => <> Q) => []((\E m \in Nat : P(m)) => <>Q) + BY <2>1, PTL + <2>3. ASSUME NEW m \in Nat + PROVE OGSpec => L(m) + <3>1. S(m) + BY <1>3 + <3>. QED BY <3>1, PTL + <2>. QED BY <1>3, <2>2, <2>3 +\* Clearly P(m) must hold for some natural number initially. +<1>5. OGSpec => \E m \in Nat : P(m) + <2>. TypeOK /\ Safety => \E m \in Nat : P(m) + BY MeasureType + <2>. QED BY PTL DEF OGSpec +<1>. QED BY <1>4, <1>5, PTL + +(***************************************************************************) +(* The main liveness theorem is now obtained as a simple corollary. *) +(***************************************************************************) +THEOREM FairSpec => Convergence +<1>1. (\A n,o \in Node : WF_vars(Gossip(n,o))) => + [](\A n,o \in Node : WF_vars(Gossip(n,o))) + \* Tedious proof of an "obvious" fact, due to interplay of first-order + \* and temporal reasoning. Could this be proved automatically? + <2>1. ASSUME NEW n \in Node, NEW o \in Node + PROVE WF_vars(Gossip(n,o)) => []WF_vars(Gossip(n,o)) + BY PTL + <2>. QED BY <2>1, Isa +<1>. QED + BY <1>1, TypeCorrect, Safe, OGLiveness, PTL + DEF FairSpec, OGSpec, Fairness, Convergence + +============================================================================= + ----------------------------------------------------------------------------- (***************************************************************************) (* Proof of the convergence property for the specification with fairness. *) diff --git a/specifications/FiniteMonotonic/Folds.tla b/specifications/FiniteMonotonic/Folds.tla new file mode 100644 index 00000000..d98ad132 --- /dev/null +++ b/specifications/FiniteMonotonic/Folds.tla @@ -0,0 +1,30 @@ +------------------------------- MODULE Folds ------------------------------- + +MapThenFoldSet(op(_,_), base, f(_), choose(_), S) == +(******************************************************************************) +(* Starting from base, apply op to f(x), for all x \in S, by choosing the set *) +(* elements with `choose`. If there are multiple ways for choosing an element,*) +(* op should be associative and commutative. Otherwise, the result may depend *) +(* on the concrete implementation of `choose`. *) +(* *) +(* FoldSet, a simpler version for sets is contained in FiniteSetsEx. *) +(* FoldFunction, a simpler version for functions is contained in Functions. *) +(* FoldSequence, a simpler version for sequences is contained in SequencesExt.*) +(* *) +(* Example: *) +(* *) +(* MapThenFoldSet(LAMBDA x,y: x \cup y, *) +(* {}, *) +(* LAMBDA x: {{x}}, *) +(* LAMBDA set: CHOOSE x \in set: TRUE, *) +(* {1,2}) *) +(* = {{1},{2}} *) +(******************************************************************************) + LET iter[s \in SUBSET S] == + IF s = {} THEN base + ELSE LET x == choose(s) + IN op(f(x), iter[s \ {x}]) + IN iter[S] + + +============================================================================= diff --git a/specifications/FiniteMonotonic/Functions.tla b/specifications/FiniteMonotonic/Functions.tla new file mode 100644 index 00000000..4b0652b0 --- /dev/null +++ b/specifications/FiniteMonotonic/Functions.tla @@ -0,0 +1,176 @@ +------------------------------ MODULE Functions ----------------------------- +(***************************************************************************) +(* `^{\large\bf \vspace{12pt} *) +(* Notions about functions including injection, surjection, and bijection.*) +(* Originally contributed by Tom Rodeheffer, MSR. *) +(* \vspace{12pt}}^' *) +(***************************************************************************) + +LOCAL INSTANCE Folds + +(***************************************************************************) +(* Restriction of a function to a set (should be a subset of the domain). *) +(***************************************************************************) +Restrict(f,S) == [ x \in S |-> f[x] ] + +(***************************************************************************) +(* Restriction of a function to the subset of its domain satisfying a *) +(* test predicate. *) +(* *) +(* Example: *) +(* (LET f == (0 :> "a" @@ 1 :> "b" @@ 2 :> "c") *) +(* IN RestrictDomain(f, LAMBDA x : x \in {0,2})) *) +(* = (0 :> "a" @@ 2 :> "c") *) +(***************************************************************************) +RestrictDomain(f, Test(_)) == Restrict(f, {x \in DOMAIN f : Test(x)}) + +(***************************************************************************) +(* Restriction of a function to the subset of its domain for which the *) +(* function values satisfy a test predicate. *) +(* *) +(* Example: *) +(* (LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* IN RestrictValues(f, LAMBDA y : y \in {0,2})) *) +(* = ("a" :> 0 @@ "b" :> 2) *) +(* *) +(* This is similar to the operator SelectSeq from the standard Sequences *) +(* module and related to standard "filter" functions in functional *) +(* programming. However, SelectSeq produces sequences, whereas *) +(* RestrictValues will in general not. For example, *) +(* *) +(* RestrictValues([0,1,2], LAMBDA y : y \in {0,2}) *) +(* = (1 :> 0 @@ 3 :> 2) *) +(***************************************************************************) +RestrictValues(f, Test(_)) == + LET S == {x \in DOMAIN f : Test(f[x])} + IN Restrict(f, S) + +(***************************************************************************) +(* Check if a function narrow is a restriction of a function wide, i.e. *) +(* Is the domain of narrow a subset of that of wide, and does the *) +(* projection of wide on the domain of narrow have the same image as *) +(* narrow does. *) +(* *) +(* Examples: *) +(* IsRestriction([one |-> 1], [one |-> 1, two |-> 2]) *) +(* IsRestriction([one |-> 1], [one |-> 1]) *) +(* ~IsRestriction([one |-> 1, two |-> 2], [one |-> 1, two |-> 3]) *) +(* ~IsRestriction([one |-> 1], [2 |-> two]) *) +(* ~IsRestriction([one |-> 1, two |-> 2], [two |-> 2]) *) +(***************************************************************************) +IsRestriction(narrow, wide) == + /\ DOMAIN narrow \subseteq DOMAIN wide + /\ \A x \in DOMAIN narrow \intersect DOMAIN wide: narrow[x] = wide[x] + +(***************************************************************************) +(* Range of a function. *) +(* Note: The image of a set under function f can be defined as *) +(* Range(Restrict(f,S)). *) +(***************************************************************************) +Range(f) == { f[x] : x \in DOMAIN f } + +(***************************************************************************) +(* Assuming DOMAIN f \subseteq DOMAIN g, apply the binary operation T to *) +(* the corresponding elements of the two functions f and g. *) +(* *) +(* Example: *) +(* LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* g == ("a" :> 1 @@ "b" :> 1 @@ "c" :> 3) *) +(* IN Pointwise(f,g,+) = ("a" :> 1 @@ "b" :> 2 @@ "c" :> 5 ) *) +(***************************************************************************) +Pointwise(f, g, T(_,_)) == [ e \in DOMAIN f |-> T(f[e], g[e]) ] + +(***************************************************************************) +(* The inverse of a function. *) +(* Example: *) +(* LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* IN Inverse(f, DOMAIN f, Range(f)) = *) +(* (0 :> "a" @@ 1 :> "b" @@ 2 :> "c") *) +(* Example: *) +(* LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* IN Inverse(f, DOMAIN f, {1,3}) = *) +(* 1 :> "b" @@ 3 :> "a") *) +(***************************************************************************) +Inverse(f,S,T) == [t \in T |-> CHOOSE s \in S : t \in Range(f) => f[s] = t] + +(***************************************************************************) +(* The inverse of a function. *) +(***************************************************************************) +AntiFunction(f) == Inverse(f, DOMAIN f, Range(f)) + +(***************************************************************************) +(* A function is injective iff it maps each element in its domain to a *) +(* distinct element. *) +(* *) +(* This definition is overridden by TLC in the Java class Functions.java *) +(* The operator is overridden by the Java method with the same name. *) +(***************************************************************************) +IsInjective(f) == \A a,b \in DOMAIN f : f[a] = f[b] => a = b + +(***************************************************************************) +(* Set of injections between two sets. *) +(***************************************************************************) +Injection(S,T) == { M \in [S -> T] : IsInjective(M) } + + +(***************************************************************************) +(* A map is a surjection iff for each element in the range there is some *) +(* element in the domain that maps to it. *) +(***************************************************************************) +Surjection(S,T) == { M \in [S -> T] : \A t \in T : \E s \in S : M[s] = t } + + +(***************************************************************************) +(* A map is a bijection iff it is both an injection and a surjection. *) +(***************************************************************************) +Bijection(S,T) == Injection(S,T) \cap Surjection(S,T) + + +(***************************************************************************) +(* An injection, surjection, or bijection exists if the corresponding set *) +(* is nonempty. *) +(***************************************************************************) +ExistsInjection(S,T) == Injection(S,T) # {} +ExistsSurjection(S,T) == Surjection(S,T) # {} +ExistsBijection(S,T) == Bijection(S,T) # {} + +-------------------------------------------------------------------------------- + +FoldFunction(op(_,_), base, fun) == + (***************************************************************************) + (* Applies the binary function op on all elements of fun in arbitrary *) + (* order starting with op(f[k], base). The resulting function is: *) + (* op(f[i],op(f[j], ..., op(f[k],base) ...)) *) + (* *) + (* op must be associative and commutative, because we can not assume a *) + (* particular ordering of i, j, and k *) + (* *) + (* Example: *) + (* FoldFunction(LAMBDA x,y: {x} \cup y, {}, <<1,2,1>>) = {1,2} *) + (***************************************************************************) + MapThenFoldSet(op, base, LAMBDA i : fun[i], LAMBDA s: CHOOSE x \in s : TRUE, DOMAIN fun) + + +FoldFunctionOnSet(op(_,_), base, fun, indices) == + (***************************************************************************) + (* Applies the binary function op on the given indices of fun in arbitrary *) + (* order starting with op(f[k], base). The resulting function is: *) + (* op(f[i],op(f[j], ..., op(f[k],base) ...)) *) + (* *) + (* op must be associative and commutative, because we can not assume a *) + (* particular ordering of i, j, and k *) + (* *) + (* indices must be a subset of DOMAIN(fun) *) + (* *) + (* Example: *) + (* FoldFunctionOnSet(LAMBDA x,y: {x} \cup y, {}, <<1,2>>, {}) = {} *) + (***************************************************************************) + MapThenFoldSet(op, base, LAMBDA i : fun[i], LAMBDA s: CHOOSE x \in s : TRUE, indices) + +============================================================================= +\* Modification History +\* Last modified Tue Nov 01 08:46:11 CET 2022 by merz +\* Last modified Mon Apr 05 03:25:53 CEST 2021 by marty +\* Last modified Wed Jun 05 12:14:19 CEST 2013 by bhargav +\* Last modified Fri May 03 12:55:35 PDT 2013 by tomr +\* Created Thu Apr 11 10:30:48 PDT 2013 by tomr diff --git a/specifications/LoopInvariance/BinarySearch.pdf b/specifications/LoopInvariance/BinarySearch.pdf index 54a5ca32..44160ad0 100644 Binary files a/specifications/LoopInvariance/BinarySearch.pdf and b/specifications/LoopInvariance/BinarySearch.pdf differ diff --git a/specifications/LoopInvariance/BinarySearch.tla b/specifications/LoopInvariance/BinarySearch.tla index cc2574a8..48383673 100644 --- a/specifications/LoopInvariance/BinarySearch.tla +++ b/specifications/LoopInvariance/BinarySearch.tla @@ -252,8 +252,3 @@ THEOREM Spec => []resultCorrect <1>4. QED BY <1>1, <1>2, <1>3, PTL DEF Spec ============================================================================= -\* Modification History -\* Last modified Fri Feb 17 16:12:03 CET 2023 by merz -\* Last modified Tue Aug 27 12:59:52 PDT 2019 by loki -\* Last modified Fri May 03 16:28:58 PDT 2019 by lamport -\* Created Wed Apr 17 15:15:12 PDT 2019 by lamport diff --git a/specifications/LoopInvariance/Quicksort.pdf b/specifications/LoopInvariance/Quicksort.pdf index 1b1f3e5b..265e06be 100644 Binary files a/specifications/LoopInvariance/Quicksort.pdf and b/specifications/LoopInvariance/Quicksort.pdf differ diff --git a/specifications/LoopInvariance/Quicksort.tla b/specifications/LoopInvariance/Quicksort.tla index 8c0f80ef..380f2e9a 100644 --- a/specifications/LoopInvariance/Quicksort.tla +++ b/specifications/LoopInvariance/Quicksort.tla @@ -21,7 +21,7 @@ (* *) (* http://lamport.azurewebsites.net/tla/proving-safety.pdf *) (***************************************************************************) -EXTENDS Integers, Sequences, FiniteSets, TLAPS, SequenceTheorems +EXTENDS Integers, Sequences, FiniteSets, TLAPS, SequenceTheorems, FiniteSetTheorems (*************************************************************************) (* This statement imports some standard modules, including ones used by *) (* the TLAPS proof system. *) @@ -48,19 +48,143 @@ ASSUME ValAssump == Values \subseteq Int (* *) (* In TLA+, DOMAIN f is the domain of a function f. *) (***************************************************************************) -PermsOf(s) == - LET Automorphisms(S) == { f \in [S -> S] : - \A y \in S : \E x \in S : f[x] = y } - f ** g == [x \in DOMAIN g |-> f[g[x]]] - IN { s ** f : f \in Automorphisms(DOMAIN s) } - - (**************************************************************************) - (* We define Max(S) and Min(S) to be the maximum and minimum, *) - (* respectively, of a finite, non-empty set S of integers. *) - (**************************************************************************) - Max(S) == CHOOSE x \in S : \A y \in S : x >= y - Min(S) == CHOOSE x \in S : \A y \in S : x =< y - +Automorphisms(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + +f ** g == [x \in DOMAIN g |-> f[g[x]]] + +PermsOf(s) == { s ** f : f \in Automorphisms(DOMAIN s) } + +LEMMA AutomorphismsCompose == + ASSUME NEW S, NEW f \in Automorphisms(S), NEW g \in Automorphisms(S) + PROVE f ** g \in Automorphisms(S) +BY DEF Automorphisms, ** + +LEMMA PermsOfLemma == + ASSUME NEW T, NEW s \in Seq(T), NEW t \in PermsOf(s) + PROVE /\ t \in Seq(T) + /\ Len(t) = Len(s) + /\ \A i \in 1 .. Len(s) : \E j \in 1 .. Len(s) : t[i] = s[j] + /\ \A i \in 1 .. Len(s) : \E j \in 1 .. Len(t) : t[j] = s[i] +BY DOMAIN t = DOMAIN s DEF PermsOf, Automorphisms, ** + +LEMMA PermsOfPermsOf == + ASSUME NEW T, NEW s \in Seq(T), NEW t \in PermsOf(s), NEW u \in PermsOf(t) + PROVE u \in PermsOf(s) +<1>1. PICK f \in Automorphisms(DOMAIN s) : t = s ** f + BY DEF PermsOf +<1>2. PICK g \in Automorphisms(DOMAIN t) : u = t ** g + BY DEF PermsOf +<1>3. DOMAIN t = DOMAIN s + BY PermsOfLemma +<1>4. f ** g \in Automorphisms(DOMAIN s) + BY <1>3, AutomorphismsCompose +<1>5. u = s ** (f ** g) + BY <1>1, <1>2, <1>3, Zenon DEF Automorphisms, ** +<1>. QED BY <1>4, <1>5 DEF PermsOf + +(**************************************************************************) +(* We define Max(S) and Min(S) to be the maximum and minimum, *) +(* respectively, of a finite, non-empty set S of integers. *) +(**************************************************************************) +Max(S) == CHOOSE x \in S : \A y \in S : x >= y +Min(S) == CHOOSE x \in S : \A y \in S : x =< y + +LEMMA MinIsMin == + ASSUME NEW S \in SUBSET Int, NEW x \in S, \A y \in S : x <= y + PROVE x = Min(S) +BY DEF Min + +LEMMA MaxIsMax == + ASSUME NEW S \in SUBSET Int, NEW x \in S, \A y \in S : x >= y + PROVE x = Max(S) +BY DEF Max + +LEMMA NonemptyMin == + ASSUME NEW S \in SUBSET Int, IsFiniteSet(S), NEW x \in S + PROVE /\ Min(S) \in S + /\ Min(S) <= x +<1>. DEFINE P(T) == T \in SUBSET Int => + /\ T # {} => Min(T) \in T + /\ \A y \in T : Min(T) <= y +<1>1. P({}) + OBVIOUS +<1>2. ASSUME NEW T, NEW y, y \notin T, P(T) + PROVE P(T \cup {y}) + <2>. HAVE T \cup {y} \in SUBSET Int + <2>1. CASE T = {} + <3>1. y = Min(T \cup {y}) + BY <2>1 DEF Min + <3>. QED BY <2>1, <3>1 + <2>2. CASE T # {} + <3>1. CASE y < Min(T) + <4>1. /\ y \in T \cup {y} + /\ \A z \in T \cup {y} : y <= z + BY <1>2, <3>1 + <4>2. y = Min(T \cup {y}) + BY <4>1 DEF Min + <4>. QED BY <4>1, <4>2 + <3>2. CASE ~(y < Min(T)) + <4>. DEFINE mn == Min(T) + <4>1. /\ mn \in T \cup {y} + /\ \A z \in T \cup {y} : mn <= z + BY <1>2, <2>2, <3>2 + <4>. HIDE DEF mn + <4>2. mn = Min(T \cup {y}) + BY <4>1 DEF Min + <4>. QED BY <4>1, <4>2 + <3>. QED BY <3>1, <3>2 + <2>. QED BY <2>1, <2>2 +<1>3. \A T : IsFiniteSet(T) => P(T) + <2>. HIDE DEF P + <2>. QED BY <1>1, <1>2, FS_Induction, IsaM("blast") +<1>. QED BY <1>3 + +LEMMA NonemptyMax == + ASSUME NEW S \in SUBSET Int, IsFiniteSet(S), NEW x \in S + PROVE /\ Max(S) \in S + /\ x <= Max(S) +<1>. DEFINE P(T) == T \in SUBSET Int => + /\ T # {} => Max(T) \in T + /\ \A y \in T : y <= Max(T) +<1>1. P({}) + OBVIOUS +<1>2. ASSUME NEW T, NEW y, y \notin T, P(T) + PROVE P(T \cup {y}) + <2>. HAVE T \cup {y} \in SUBSET Int + <2>1. CASE T = {} + <3>1. y = Max(T \cup {y}) + BY <2>1 DEF Max + <3>. QED BY <2>1, <3>1 + <2>2. CASE T # {} + <3>1. CASE y > Max(T) + <4>1. /\ y \in T \cup {y} + /\ \A z \in T \cup {y} : y >= z + BY <1>2, <3>1 + <4>2. y = Max(T \cup {y}) + BY <4>1 DEF Max + <4>. QED BY <4>1, <4>2 + <3>2. CASE ~(y > Max(T)) + <4>. DEFINE mx == Max(T) + <4>1. /\ mx \in T \cup {y} + /\ \A z \in T \cup {y} : z <= mx + BY <1>2, <2>2, <3>2 + <4>. HIDE DEF mx + <4>2. mx = Max(T \cup {y}) + BY <4>1 DEF Max + <4>. QED BY <4>1, <4>2 + <3>. QED BY <3>1, <3>2 + <2>. QED BY <2>1, <2>2 +<1>3. \A T : IsFiniteSet(T) => P(T) + <2>. HIDE DEF P + <2>. QED BY <1>1, <1>2, FS_Induction, IsaM("blast") +<1>. QED BY <1>3 + +LEMMA IntervalMinMax == + ASSUME NEW i \in Int, NEW j \in Int, i <= j + PROVE i = Min(i .. j) /\ j = Max(i .. j) +BY DEF Min, Max + (***************************************************************************) (* The operator Partitions is defined so that if I is an interval that's a *) (* subset of 1..Len(s) and p \in Min(I) .. Max(I)-1, the Partitions(I, p, *) @@ -74,8 +198,19 @@ PermsOf(s) == Partitions(I, p, s) == {t \in PermsOf(s) : /\ \A i \in (1..Len(s)) \ I : t[i] = s[i] + /\ \A i \in I : \E j \in I : t[i] = s[j] /\ \A i, j \in I : (i =< p) /\ (p < j) => (t[i] =< t[j])} - + +LEMMA PartitionsLemma == + ASSUME NEW T, NEW s \in Seq(T), NEW I \in SUBSET (1 .. Len(s)), + NEW p \in I, NEW t \in Partitions(I, p, s) + PROVE /\ t \in Seq(T) + /\ Len(t) = Len(s) + /\ \A i \in (1 .. Len(s)) \ I : t[i] = s[i] + /\ \A i \in I : \E j \in I : t[i] = s[j] + /\ \A i,j \in I : i <= p /\ p < j => t[i] <= t[j] +BY PermsOfLemma DEF Partitions + (***************************************************************************) (* Our algorithm has three variables: *) (* *) @@ -188,7 +323,8 @@ UV == U \cup {{i} : i \in 1..Len(seq) \ UNION U} DomainPartitions == {DP \in SUBSET SUBSET (1..Len(seq0)) : /\ (UNION DP) = 1..Len(seq0) - /\ \A I \in DP : I = Min(I)..Max(I) + \* /\ \A I \in DP : I = Min(I)..Max(I) + /\ \A I \in DP : \E mn,mx \in 1 .. Len(seq0) : I = mn .. mx /\ \A I, J \in DP : (I # J) => (I \cap J = {}) } RelSorted(I, J) == \A i \in I, j \in J : (i < j) => (seq[i] =< seq[j]) @@ -197,7 +333,7 @@ TypeOK == /\ seq \in Seq(Values) \ {<<>>} /\ seq0 \in Seq(Values) \ {<<>>} /\ U \in SUBSET ( (SUBSET (1..Len(seq0))) \ {{}} ) /\ pc \in {"a", "Done"} - + Inv == /\ TypeOK /\ (pc = "Done") => (U = {}) /\ UV \in DomainPartitions @@ -229,32 +365,16 @@ THEOREM Spec => []PCorrect <2>2. pc = "Done" => U = {} BY DEF Init <2>3. UV \in DomainPartitions - <3>1. UV = {1..Len(seq0)} - (*********************************************************************) - (* Follows easily from definition of UV, seq0 = seq, and seq a *) - (* non-empty sequence. *) - (*********************************************************************) - <3>2. UV \in SUBSET SUBSET (1..Len(seq0)) - BY <3>1 DEF Inv - <3>3. (UNION UV) = 1..Len(seq0) - BY <3>1 - <3>4. 1..Len(seq0) = Min(1..Len(seq0))..Max(1..Len(seq0)) - (*********************************************************************) - (* Because seq0 = seq and seq a non-empty sequence imply Len(seq0) a *) - (* positive natural number. *) - (*********************************************************************) - <3>5. \A I, J \in UV : I = J - BY <3>1 - <3>6. QED - BY <3>1, <3>2, <3>3, <3>4, <3>5 DEF DomainPartitions + BY DEF Init, UV, DomainPartitions <2>4. seq \in PermsOf(seq0) <3>1. seq \in PermsOf(seq) - (*********************************************************************) - (* This is obvious because the identity function is a permutation of *) - (* 1..Len(seq). *) - (*********************************************************************) + <4>. DEFINE f == [i \in 1 .. Len(seq) |-> i] + <4>. /\ f \in [DOMAIN seq -> DOMAIN seq] + /\ \A y \in DOMAIN seq : \E x \in DOMAIN seq : f[x] = y + BY DEF Init + <4>. QED BY DEF Init, PermsOf, Automorphisms, ** <3>2. QED - BY <3>1 DEF Init \* , Inv, TypeOK, DomainPartitions, RelSorted, UV, PermsOf + BY <3>1 DEF Init <2>5. UNION UV = 1..Len(seq0) BY DEF Init, Inv, TypeOK, DomainPartitions, RelSorted, UV <2>6. \A I, J \in UV : (I # J) => RelSorted(I, J) @@ -283,6 +403,14 @@ THEOREM Spec => []PCorrect /\ seq' = seq /\ seq0' = seq0 BY <4>2, <4>3 DEF a + <5>. IsFiniteSet(I) + <6>. IsFiniteSet(1 .. Len(seq0)) + BY FS_Interval DEF Inv, TypeOK + <6>. I \subseteq 1 .. Len(seq0) + BY DEF Inv, TypeOK + <6>. QED BY FS_Subset + <5>j. PICK j : I = {j} + BY <4>3, FS_Singleton <5>2. QED <6>1. UV' = UV (***************************************************************) @@ -290,6 +418,11 @@ THEOREM Spec => []PCorrect (* to the set {{i} : i \in 1..Len(seq) \ UNION U}, thereby *) (* keeping it in UV. *) (***************************************************************) + <7>1. j \in 1 .. Len(seq) + BY <5>j, PermsOfLemma DEF Inv, TypeOK + <7>2. \A J \in U : I # J => j \notin J + BY <5>j, Zenon DEF Inv, TypeOK, DomainPartitions, UV + <7>. QED BY <5>1, <5>j, <7>1, <7>2 DEF UV <6>2. TypeOK' BY <4>1, <4>3, <5>1 DEF Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, Min, Max, UV @@ -300,7 +433,7 @@ THEOREM Spec => []PCorrect BY <4>1, <4>3, <5>1, <6>1 DEF Inv, TypeOK, DomainPartitions <6>5. (seq \in PermsOf(seq0))' - BY <4>1, <4>3, <5>1 + BY <4>1, <4>3, <5>1, Isa DEF Inv, TypeOK, PermsOf <6>6. (UNION UV = 1..Len(seq0))' BY <5>1, <6>1 DEF Inv @@ -312,21 +445,43 @@ THEOREM Spec => []PCorrect <4>4. CASE Cardinality(I) # 1 <5>1. seq0' = seq0 BY DEF a - <5> DEFINE I1(p) == Min(I)..p - I2(p) == (p+1)..Max(I) - <5>2. PICK p \in Min(I) .. (Max(I)-1) : + <5>I. PICK mn \in 1 .. Len(seq0), mx \in 1 .. Len(seq0) : I = mn .. mx + BY DEF Inv, UV, DomainPartitions + <5>mn. mn < mx + <6>. SUFFICES ASSUME mn >= mx PROVE FALSE + OBVIOUS + <6>1. CASE mn > mx + <7>. I = {} + BY <5>I, <6>1 + <7>. QED BY DEF Inv, TypeOK + <6>2. CASE mn = mx + <7>. I = {mn} + BY <5>I, <6>2 + <7>. QED BY <4>4, FS_Singleton + <6>. QED BY <6>1, <6>2 + <5> DEFINE I1(p) == mn .. p + I2(p) == (p+1).. mx + <5>2. PICK p \in mn .. (mx-1) : /\ seq' \in Partitions(I, p, seq) /\ U' = ((U \ {I}) \cup {I1(p), I2(p)}) - BY <4>2, <4>4 + BY <4>2, <4>4, <5>I, <5>mn, IntervalMinMax + <5>p. mn <= p /\ p < mx + BY <5>mn <5>3. /\ /\ I1(p) # {} - /\ I1(p) = Min(I1(p)).. Max(I1(p)) /\ I1(p) \subseteq 1..Len(seq0) /\ /\ I2(p) # {} - /\ I2(p) = Min(I2(p)).. Max(I2(p)) /\ I2(p) \subseteq 1..Len(seq0) /\ I1(p) \cap I2(p) = {} /\ I1(p) \cup I2(p) = I - /\ \A i \in I1(p), j \in I2(p) : (i < j) /\ (seq[i] =< seq[j]) + \* /\ \A i \in I1(p), j \in I2(p) : (i < j) /\ (seq[i] =< seq[j]) + <6>1. mn \in I1(p) /\ mx \in I2(p) + BY <5>p + <6>2. /\ I1(p) \subseteq 1 .. Len(seq0) + /\ I2(p) \subseteq 1 .. Len(seq0) + BY DEF Inv, TypeOK + <6>4. I1(p) \cup I2(p) = I + BY <5>I + <6>. QED BY <6>1, <6>2, <6>4 (*****************************************************************) (* Since I is in U, invariant Inv implies I is a non-empty *) (* subinterval of 1..Len(seq), and the <4>4 case assumption *) @@ -336,35 +491,21 @@ THEOREM Spec => []PCorrect (* whose union is I. The final conjunct follows from the *) (* definition of Partitions(I, p, seq). *) (*****************************************************************) - <5>4. /\ Len(seq) = Len(seq') + <5>4. /\ seq' \in Seq(Values) + /\ Len(seq) = Len(seq') /\ Len(seq) = Len(seq0) - (*****************************************************************) - (* By <5>2 and definition of Partitions. *) - (*****************************************************************) + BY <5>2, PermsOfLemma DEF Partitions, Inv, TypeOK <5>5. UNION U = UNION U' - (*****************************************************************) - (* By <5>2 and <5>3, since the action removes I from U and adds *) - (* I1(p) and I2(p) to it. *) - (*****************************************************************) + BY <5>2, <5>3 <5>6. UV' = (UV \ {I}) \cup {I1(p), I2(p)} BY <5>1, <5>2, <5>3, <5>4, <5>5 DEF UV - (*****************************************************************) - (* By <5>2, <5>3, and definition of UV, since Len(seq) = *) - (* Len(seq'). *) - (*****************************************************************) <5>7. TypeOK' <6>1. (seq \in Seq(Values) \ {<<>>})' - (***************************************************************) - (* By <5>2 and definitions of Partitions and PermsOf, since *) - (* seq a non-empty sequence of Values implies PermsOf(seq) is *) - (* one too. *) - (***************************************************************) + BY <5>4 DEF Inv, TypeOK <6>2. (seq0 \in Seq(Values) \ {<<>>})' BY <5>1 DEF TypeOK, Inv <6>3. (U \in SUBSET ( (SUBSET (1..Len(seq0))) \ {{}} ))' - (***************************************************************) - (* By <5>2 and <5>3. *) - (***************************************************************) + BY <5>1, <5>2, <5>3 DEF Inv, TypeOK <6>4. (pc \in {"a", "Done"})' BY <4>1 <6>5. QED @@ -372,60 +513,93 @@ THEOREM Spec => []PCorrect <5>8. ((pc = "Done") => (U = {}))' BY <4>1 <5>9. (UV \in DomainPartitions)' - <6> HIDE DEF I1, I2 + \* <6> HIDE DEF I1, I2 <6>1. UV' \in SUBSET SUBSET (1..Len(seq0')) BY <5>6, <5>3, <5>4, <5>1 DEF Inv <6>2. UNION UV' = 1..Len(seq0') BY <5>6, <5>3, <5>4, <5>1 DEF Inv <6>3. ASSUME NEW J \in UV' - PROVE J = Min(J)..Max(J) - <7>1. CASE J \in UV - BY <7>1 DEF Inv, DomainPartitions - <7>2. CASE J = I1(p) - BY <7>2, <5>3 - <7>3. CASE J = I2(p) - BY <7>3, <5>3 - <7>4. QED - BY <7>1, <7>2, <7>3, <5>6 + PROVE \E i,j \in 1 .. Len(seq0') : J = i .. j + BY <5>1, <5>mn, <5>6 DEF Inv, TypeOK, DomainPartitions <6>4. ASSUME NEW J \in UV', NEW K \in UV', J # K PROVE J \cap K = {} - (***************************************************************) - (* If J and K are in UV, then this follows from Inv. If one *) - (* of them is in UV and the other equals I1(p) or I2(p), it *) - (* follows because I1(p) \cup I2(p) = I and I is disjoint from *) - (* other elements of UV. If J and K are I1(p) and I2(p), then *) - (* it follows from the definitions of I1(p) and I2(p). By *) - (* <5>6, this covers all possibilities. *) - (***************************************************************) + <7>1. CASE J \in UV /\ K \in UV + BY <6>4, <7>1 DEF Inv, DomainPartitions + <7>2. CASE J \in (UV \ {I}) /\ K \in {I1(p), I2(p)} + <8>. J \cap I = {} + BY <7>2 DEF UV, Inv, DomainPartitions + <8>. QED BY <7>2, <5>I + <7>3. CASE J \in {I1(p), I2(p)} /\ K \in (UV \ {I}) + <8>. K \cap I = {} + BY <7>3 DEF UV, Inv, DomainPartitions + <8>. QED BY <7>3, <5>I + <7>4. CASE J \in {I1(p), I2(p)} /\ K \in {I1(p), I2(p)} + BY <6>4, <7>4 + <7>. QED BY <5>6, <7>1, <7>2, <7>3, <7>4 <6>5. QED - BY <6>1, <6>2, <6>3, <6>4 DEF DomainPartitions, Min, Max + BY <6>1, <6>2, <6>3, <6>4 DEF DomainPartitions \*, Min, Max <5>10. (seq \in PermsOf(seq0))' - (*****************************************************************) - (* By <5>2 and definition of Partitions, seq' \in PermsOf(seq), *) - (* and seq \in PermsOf(seq0) implies PermsOf(seq) = *) - (* PermsOf(seq0). *) - (*****************************************************************) + BY <5>1, <5>2, PermsOfPermsOf DEF Inv, TypeOK, Partitions <5>11. (UNION UV = 1..Len(seq0))' - <6> HIDE DEF I1, I2 - <6> QED - BY <5>6, <5>3, <5>4, <5>1 DEF Inv - <5>12. (\A I_1, J \in UV : (I_1 # J) => RelSorted(I_1, J))' - <6> SUFFICES ASSUME NEW I_1 \in UV', NEW J \in UV', - (I_1 # J)', - NEW i \in I_1', NEW j \in J', - (i < j)' - PROVE (seq[i] =< seq[j])' + BY <5>6, <5>3, <5>4, <5>1 DEF Inv + <5>12. (\A II, JJ \in UV : (II # JJ) => RelSorted(II, JJ))' + <6> SUFFICES ASSUME NEW II \in UV', NEW JJ \in UV', + II # JJ, + NEW i \in II, NEW j \in JJ, + i < j + PROVE seq'[i] =< seq'[j] BY DEF RelSorted - <6> QED - (***************************************************************) - (* IF I_1 and J are in UV, then this follows from Inv. If one *) - (* of them is in UV and the other equals I1(p) or I2(p), it *) - (* follows from Inv because RelSorted(I, K) and RelSorted(K, *) - (* I) holds for all K in UV and I1(p) and I2(p) are subsets of *) - (* I. If I_1 and J are I1(p) and I2(p), then it follows from *) - (* the definitions of I1 and I2. By <5>6, this covers all *) - (* possibilities. *) - (***************************************************************) + <6>. /\ i \in 1 .. Len(seq) + /\ j \in 1 .. Len(seq) + BY <5>1, <5>4, <5>9 DEF DomainPartitions + <6>I. /\ I \in SUBSET (1 .. Len(seq)) + /\ p \in I + BY <5>I, <5>2, PermsOfLemma DEF Inv, TypeOK + <6>1. CASE II \in UV \ {I} /\ JJ \in UV \ {I} + BY <5>2, <6>1, Zenon + DEF Inv, TypeOK, UV, DomainPartitions, Partitions, RelSorted + <6>2. CASE II \in UV \ {I} /\ JJ \in {I1(p), I2(p)} + <7>1. JJ \subseteq I + BY <5>3, <6>2 + <7>2. PICK k \in I : seq'[j] = seq[k] + BY <5>2, <7>1, <6>I, PartitionsLemma DEF Inv, TypeOK + <7>3. II \cap I = {} + BY <6>2, Zenon DEF UV, Inv, DomainPartitions + <7>4. PICK mnI, mxI \in 1 .. Len(seq0) : II = mnI .. mxI + BY <6>2 DEF Inv, DomainPartitions + <7>5. i < k + BY <5>I, <6>2, <7>1, <7>3 DEF Inv, TypeOK + <7>6. seq[i] <= seq[k] + BY <6>2, <7>1, <7>5 DEF Inv, RelSorted, UV + <7>7. seq'[i] = seq[i] + BY <5>2, <6>2, <6>I, <7>3, PartitionsLemma DEF Inv, TypeOK + <7>. QED BY <7>2, <7>6, <7>7 + <6>3. CASE II \in {I1(p), I2(p)} /\ JJ \in UV \ {I} + <7>1. II \subseteq I + BY <5>3, <6>3 + <7>2. PICK k \in I : seq'[i] = seq[k] + BY <5>2, <7>1, <6>I, PartitionsLemma DEF Inv, TypeOK + <7>3. JJ \cap I = {} + BY <6>3, Zenon DEF UV, Inv, DomainPartitions + <7>4. PICK mnJ, mxJ \in 1 .. Len(seq0) : JJ = mnJ .. mxJ + BY <6>3 DEF Inv, DomainPartitions + <7>5. k < j + BY <5>I, <6>3, <7>1, <7>3 DEF Inv, TypeOK + <7>6. seq[k] <= seq[j] + BY <6>3, <7>1, <7>5 DEF Inv, RelSorted, UV + <7>7. seq'[j] = seq[j] + <8>1. j \in (1 .. Len(seq)) \ I + BY <7>3 + <8>2. /\ seq \in Seq(Values) + /\ seq' \in Partitions(I, p, seq) + BY <5>2 DEF Inv, TypeOK + <8>. QED BY <6>I, <8>1, <8>2, PartitionsLemma + <7>. QED BY <7>2, <7>6, <7>7 + <6>4. CASE II = I1(p) /\ JJ = I2(p) + BY <5>2, <5>3, <6>I, <6>4, PartitionsLemma DEF Inv, TypeOK + <6>5. CASE II = I2(p) /\ JJ = I2(p) + BY <6>5 \* contradiction: i < j impossible + <6> QED BY <5>6, <6>1, <6>2, <6>3, <6>4, <6>5 <5>13. QED BY <5>7, <5>8, <5>9, <5>10, <5>11, <5>12 DEF Inv <4>5. QED @@ -437,34 +611,34 @@ THEOREM Spec => []PCorrect <4>2. ((pc = "Done") => (U = {}))' OBVIOUS <4>3. (UV \in DomainPartitions)' - OBVIOUS + BY Isa <4>4. (seq \in PermsOf(seq0))' - OBVIOUS + BY Isa <4>5. (UNION UV = 1..Len(seq0))' OBVIOUS <4>6. (\A I, J \in UV : (I # J) => RelSorted(I, J))' OBVIOUS <4>7. QED - BY <4>1, <4>2, <4>3, <4>4, <4>5, <4>6 DEF Inv + BY <4>1, <4>2, <4>3, <4>4, <4>5, <4>6, Zenon DEF Inv <3>3. QED BY <3>1, <3>2 <2>2. CASE UNCHANGED vars <3>1. TypeOK' - BY <2>2 DEF vars, Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, Min, Max + BY <2>2 DEF vars, Inv, TypeOK <3>2. ((pc = "Done") => (U = {}))' - BY <2>2 DEF vars, Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, Min, Max + BY <2>2 DEF vars, Inv <3>3. (UV \in DomainPartitions)' - BY <2>2 DEF vars, Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, Min, Max, UV + BY <2>2, Isa DEF vars, Inv, TypeOK, DomainPartitions, UV <3>4. (seq \in PermsOf(seq0))' - BY <2>2 DEF vars, Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, Min, Max + BY <2>2, Isa DEF vars, Inv, TypeOK, DomainPartitions, PermsOf <3>5. (UNION UV = 1..Len(seq0))' - BY <2>2 DEF vars, Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, Min, Max, UV + BY <2>2 DEF vars, Inv, UV <3>6. (\A I, J \in UV : (I # J) => RelSorted(I, J))' - BY <2>2 DEF vars, Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, Min, Max, UV + BY <2>2 DEF vars, Inv, TypeOK, DomainPartitions, PermsOf, RelSorted, UV <3>7. QED BY <3>1, <3>2, <3>3, <3>4, <3>5, <3>6 DEF Inv <2>3. QED - BY <2>1, <2>2 DEF Next + BY <2>1, <2>2 DEF Next, Terminating <1>3. Inv => PCorrect <2> SUFFICES ASSUME Inv, pc = "Done" @@ -481,10 +655,7 @@ THEOREM Spec => []PCorrect <3>1. /\ Len(seq) = Len(seq0) /\ Len(seq) \in Nat /\ Len(seq) > 0 - (*********************************************************************) - (* By seq \in PermsOf(seq0), seq a non-empty sequence, and *) - (* definition of PermsOf. *) - (*********************************************************************) + BY PermsOfLemma DEF Inv, TypeOK <3>2. UV = {{i} : i \in 1..Len(seq)} BY U = {} DEF Inv, TypeOK, UV <3>3. {p} \in UV /\ {q} \in UV @@ -496,6 +667,4 @@ THEOREM Spec => []PCorrect <1>4. QED BY <1>1, <1>2, <1>3, PTL DEF Spec ============================================================================= -\* Modification History -\* Last modified Fri May 03 16:28:36 PDT 2019 by lamport \* Created Mon Jun 27 08:20:07 PDT 2016 by lamport diff --git a/specifications/LoopInvariance/SumSequence.pdf b/specifications/LoopInvariance/SumSequence.pdf index 5838f7cd..2a617d22 100644 Binary files a/specifications/LoopInvariance/SumSequence.pdf and b/specifications/LoopInvariance/SumSequence.pdf differ diff --git a/specifications/LoopInvariance/SumSequence.tla b/specifications/LoopInvariance/SumSequence.tla index e3a33c03..07b2ec20 100644 --- a/specifications/LoopInvariance/SumSequence.tla +++ b/specifications/LoopInvariance/SumSequence.tla @@ -173,7 +173,7 @@ LEMMA Lemma1 == (***************************************************************************) THEOREM FrontDef == \A S : \A s \in Seq(S) : Front(s) = [i \in 1..(Len(s)-1) |-> s[i]] -BY DEF Front, SubSeq +BY DEF Front @@ -258,7 +258,7 @@ THEOREM Spec => []PCorrect <6>4. s \in Seq(Int) BY <6>3, <5>2, <4>2 <6>5. Front(s) = [i \in 1 .. Len(s)-1 |-> s[i]] - BY <5>1 DEF Front + BY <6>4, FrontDef <6> QED BY <6>4, <6>5, <5>1, <4>2, Lemma5 <5>5. curseq = [i \in 1..(Len(s)-1) |-> s[i]] @@ -276,7 +276,7 @@ THEOREM Spec => []PCorrect <2>2. CASE UNCHANGED vars BY <2>2 DEF Inv, TypeOK, vars <2>3. QED - BY <2>1, <2>2 DEF Next + BY <2>1, <2>2 DEF Next, Terminating <1>3. Inv => PCorrect <2> SUFFICES ASSUME Inv, pc = "Done" @@ -306,14 +306,14 @@ LEMMA Lemma1_Proof == SS[ss \in Seq(Int)] == IF ss = << >> THEN 0 ELSE DefSS(SS[Tail(ss)], ss) <1>1. TailInductiveDefHypothesis(SS, Int, 0, DefSS) - BY DEF TailInductiveDefHypothesis + BY Zenon DEF TailInductiveDefHypothesis <1>2. TailInductiveDefConclusion(SS, Int, 0, DefSS) - BY <1>1, TailInductiveDef + BY <1>1, TailInductiveDef, Zenon <1>3. SS = [ss \in Seq(Int) |-> IF ss = << >> THEN 0 ELSE ss[1] + SS[Tail(ss)]] - BY <1>2 DEF TailInductiveDefConclusion + BY <1>2, Zenon DEF TailInductiveDefConclusion <1> QED - BY <1>3 DEF SeqSum + BY <1>3, Zenon DEF SeqSum (***************************************************************************) @@ -351,7 +351,7 @@ LEMMA Lemma2a == OBVIOUS <1>3. \A i \in 1 .. Len(Tail(s)) : Tail(s)[i] = t[i] OBVIOUS -<1>. QED BY <1>1, <1>2, <1>3, SeqEqual, Zenon +<1>. QED BY <1>1, <1>2, <1>3 LEMMA Lemma3 == @@ -371,7 +371,7 @@ LEMMA Lemma3 == <2>2. Len(Front(s)) > 0 BY <2>1 <2>3. Front(s) # << >> - BY <2>1, <2>2 + BY <2>1, <2>2, Isa <2>4. Tail(Front(s)) = [i \in 1..(Len(Front(s))-1) |-> Front(s)[i+1]] BY <2>1, <2>3, Lemma2a <2>5. \A i \in 0..(Len(s)-2) : Front(s)[i+1] = s[i+1] @@ -387,7 +387,7 @@ LEMMA Lemma3 == <1>2. Front(Tail(s)) = [i \in 1..(Len(s) - 2) |-> s[i+1]] BY Len(s) \in Nat, Lemma2a DEF Front <1>3. QED - BY <1>1, <1>2 + BY <1>1, <1>2, Zenon (***************************************************************************) @@ -402,11 +402,11 @@ LEMMA Lemma4 == \A s \in Seq(Int) : SeqSum(s) \in Int <2> SUFFICES ASSUME NEW s \in Seq(Int), Len(s) = 0 PROVE SeqSum(s) \in Int - BY DEF P + BY Zenon DEF P <2>1. s = << >> OBVIOUS <2> QED - BY <2>1, Lemma1 + BY <2>1, Lemma1, Isa <1>2. ASSUME NEW N \in Nat, P(N) PROVE P(N+1) <2> SUFFICES ASSUME NEW s \in Seq(Int), @@ -423,12 +423,12 @@ LEMMA Lemma4 == \A s \in Seq(Int) : SeqSum(s) \in Int /\ Tail(s) \in Seq(Int) BY <2>2, Lemma2 <2>5. SeqSum(Tail(s)) \in Int - BY <1>2, <2>4 + BY <1>2, <2>4, Zenon <2>6. QED BY <2>2, <2>3, <2>5 <1> HIDE DEF P <1>3. \A N \in Nat : P(N) - BY <1>1, <1>2, NatInduction + BY <1>1, <1>2, NatInduction, Isa <1>4. QED BY <1>3 DEF P @@ -448,9 +448,9 @@ LEMMA Lemma5_Proof == PROVE SeqSum(s) = IF Len(s) = 0 THEN 0 ELSE SeqSum(Front(s)) + s[Len(s)] - BY DEF P + BY Zenon DEF P <2> QED - BY s = << >>, Lemma1 + BY s = << >>, Lemma1, Zenon <1>2. ASSUME NEW N \in Nat, P(N) PROVE P(N+1) <2> SUFFICES ASSUME NEW s \in Seq(Int), @@ -474,12 +474,12 @@ LEMMA Lemma5_Proof == <3> USE <2>3 <3> HIDE FrontDef \* DEF Front <3>1. SeqSum(Front(s)) = 0 - BY Lemma1, <2>1, Front(s) = << >> + BY Lemma1, <2>1, Front(s) = << >>, Zenon <3>2. Len(Tail(s)) = 0 BY HeadTailProperties <3>3. SeqSum(Tail(s)) = IF Tail(s) = << >> THEN 0 ELSE Tail(s)[1] + SeqSum(Tail(Tail(s))) - BY <2>2, Lemma1 + BY <2>2, Lemma1, Zenon <3>4. SeqSum(Tail(s)) = 0 BY <3>2, <2>2, EmptySeq, Tail(s) = << >>, <3>3 <3>5. QED @@ -491,24 +491,15 @@ LEMMA Lemma5_Proof == <4>1. Front(s) \in Seq(Int) BY <2>4, <2>2, Lemma2 <4>2. Front(t) \in Seq(Int) - BY <2>4, <2>2, Lemma2 + BY <2>4, <2>2, Lemma2, Zenon <4>3. Tail(Front(s)) \in Seq(Int) - <5> Len(s) > 1 - BY <2>4 - <5> Len(Front(s)) > 0 - BY Lemma2 - <5> Front(s) \in Seq(Int) - BY Lemma2 - <5> Tail(Front(s)) \in Seq(Int) - BY Lemma2 - <5> QED - BY Lemma2 + BY <2>4, Lemma2 <4>4. QED BY <4>1, <4>2, <4>3 <3>1. SeqSum(t) = SeqSum(Front(t)) + t[N] - BY <1>2, <2>2, <2>4 + BY <1>2, <2>2, <2>4, Isa <3>2. SeqSum(t) = SeqSum(Tail(Front(s))) + t[N] - BY <3>1, <2>4, Len(s) > 1, Lemma3 + BY <3>1, <2>4, Len(s) > 1, Lemma3, Zenon <3>3. t[N] = s[N+1] BY <2>2, <2>4 <3> HIDE DEF Front @@ -520,7 +511,7 @@ LEMMA Lemma5_Proof == <4>1. SeqSum(s) \in Int BY <2>4, <2>2, <2>1, Lemma4 <4>2. SeqSum(t) \in Int - BY <2>4, <2>2, <2>1, Lemma4 + BY <2>4, <2>2, <2>1, Lemma4, Zenon <4>3. SeqSum(Tail(Front(s))) \in Int <5>1. Len(s) > 1 BY <2>4 @@ -531,7 +522,7 @@ LEMMA Lemma5_Proof == <5>4. Tail(Front(s)) \in Seq(Int) BY <5>3 <5>5. QED - BY <2>4, <2>2, <2>1, <5>3, Lemma4 + BY <2>4, <2>2, <2>1, <5>3, Lemma4, Zenon <4>4. t[N] \in Int BY <2>4, <2>2, <2>1 <4>4a. s[1] \in Int @@ -554,12 +545,9 @@ LEMMA Lemma5_Proof == <2>5. QED BY <2>3, <2>4 <1>3. \A N \in Nat : P(N) - BY <1>1, <1>2, NatInduction + BY <1>1, <1>2, NatInduction, Isa <1>4. QED BY <1>3 ============================================================================= \* Modification History -\* Last modified Fri Jan 27 10:03:14 CET 2023 by merz -\* Last modified Tue Aug 27 12:59:10 PDT 2019 by loki -\* Last modified Fri May 03 16:40:42 PDT 2019 by lamport \* Created Fri Apr 19 14:13:06 PDT 2019 by lamport diff --git a/specifications/Majority/MajorityProof.tla b/specifications/Majority/MajorityProof.tla index ab0c74fe..b1feeb25 100644 --- a/specifications/Majority/MajorityProof.tla +++ b/specifications/Majority/MajorityProof.tla @@ -63,11 +63,11 @@ LEMMA Correctness == Spec => []Correct BY OccurrencesOne DEF Init, Inv <1>2. TypeOK /\ Inv /\ [Next]_vars => Inv' <2>. SUFFICES ASSUME TypeOK, Inv, Next PROVE Inv' - BY DEF Inv, vars, OccurrencesBefore, PositionsBefore + BY Zenon DEF Inv, vars, OccurrencesBefore, PositionsBefore <2>. i <= Len(seq) /\ i' = i+1 /\ seq' = seq BY DEF Next <2>0. \A v \in Value : OccurrencesBefore(v, i)' = OccurrencesBefore(v, i') - BY DEF OccurrencesBefore, PositionsBefore + BY Zenon DEF OccurrencesBefore, PositionsBefore <2>. USE OccurrencesType DEF TypeOK <2>1. CASE cnt = 0 /\ cand' = seq[i] /\ cnt' = 1 <3>1. i \in PositionsBefore(seq[i], i+1) @@ -83,14 +83,14 @@ LEMMA Correctness == Spec => []Correct <2>2. CASE cnt # 0 /\ cand = seq[i] /\ cand' = cand /\ cnt' = cnt + 1 BY <2>0, <2>2, OccurrencesPlusOne DEF Inv <2>3. CASE cnt # 0 /\ cand # seq[i] /\ cand' = cand /\ cnt' = cnt - 1 - <3>10. cnt' <= OccurrencesBefore(cand', i') + <3>1. cnt' <= OccurrencesBefore(cand', i') BY <2>3, OccurrencesPlusOne DEF Inv - <3>20. 2 * (OccurrencesBefore(cand', i') - cnt') <= i' - 1 - cnt' + <3>2. 2 * (OccurrencesBefore(cand', i') - cnt') <= i' - 1 - cnt' BY <2>3, OccurrencesPlusOne DEF Inv - <3>30. ASSUME NEW v \in Value \ {cand'} + <3>3. ASSUME NEW v \in Value \ {cand'} PROVE 2 * OccurrencesBefore(v, i') <= i' - 1 - cnt' BY <2>3, OccurrencesPlusOne DEF Inv - <3>. QED BY <2>0, <2>3, <3>10, <3>20, <3>30 DEF Inv + <3>. QED BY <2>0, <2>3, <3>1, <3>2, <3>3 DEF Inv <2>. QED BY <2>1, <2>2, <2>3 DEF Next <1>3. TypeOK /\ Inv => Correct BY OccurrencesType DEF TypeOK, Inv, Correct, Occurrences diff --git a/specifications/MisraReachability/ParReachProofs.pdf b/specifications/MisraReachability/ParReachProofs.pdf index 1046fed1..cc96a5a5 100644 Binary files a/specifications/MisraReachability/ParReachProofs.pdf and b/specifications/MisraReachability/ParReachProofs.pdf differ diff --git a/specifications/MisraReachability/ReachabilityProofs.pdf b/specifications/MisraReachability/ReachabilityProofs.pdf index b22207ac..e7ee7df9 100644 Binary files a/specifications/MisraReachability/ReachabilityProofs.pdf and b/specifications/MisraReachability/ReachabilityProofs.pdf differ diff --git a/specifications/MisraReachability/ReachabilityProofs.tla b/specifications/MisraReachability/ReachabilityProofs.tla index 8eb6da23..a9010ab5 100644 --- a/specifications/MisraReachability/ReachabilityProofs.tla +++ b/specifications/MisraReachability/ReachabilityProofs.tla @@ -13,7 +13,7 @@ (* All the lemmas except Reachable1 are obvious consequences of the *) (* definition of ReachableFrom. *) (***************************************************************************) -EXTENDS Reachability, NaturalsInduction +EXTENDS Reachability, NaturalsInduction, TLAPS (***************************************************************************) @@ -225,7 +225,7 @@ LEMMA Reachable1 == BY <4>2, <4>3, <4>4 <3> HIDE DEF R <3>3. QED - BY <3>1, <3>2, NatInduction + BY <3>1, <3>2, NatInduction, Isa (***********************************************************************) (* Proving q \in S \cup ReachableFrom(T) from <2>1 is straightforward. *) (***********************************************************************) diff --git a/specifications/MisraReachability/ReachableProofs.pdf b/specifications/MisraReachability/ReachableProofs.pdf index db9b6f62..e913b92c 100644 Binary files a/specifications/MisraReachability/ReachableProofs.pdf and b/specifications/MisraReachability/ReachableProofs.pdf differ diff --git a/specifications/Paxos/Consensus.tla b/specifications/Paxos/Consensus.tla index 25aa9bda..a23c65ae 100644 --- a/specifications/Paxos/Consensus.tla +++ b/specifications/Paxos/Consensus.tla @@ -54,5 +54,16 @@ THEOREM Invariance == Spec => []Inv Success == <>(chosen # {}) LiveSpec == Spec /\ WF_chosen(Next) +ASSUME ValuesNonempty == Value # {} + THEOREM LivenessTheorem == LiveSpec => Success +<1>1. [][Next]_chosen /\ WF_chosen(Next) => [](Init => Success) + <2>1. Init' \/ (chosen # {})' + BY DEF Init + <2>2. Init /\ <>_chosen => (chosen # {})' + BY DEF Init, Next + <2>3. Init => ENABLED <>_chosen + BY ValuesNonempty, ExpandENABLED DEF Init, Next + <2>. QED BY <2>1, <2>2, <2>3, PTL DEF Success +<1>. QED BY <1>1, PTL DEF LiveSpec, Spec ============================================================================= diff --git a/specifications/Paxos/Voting.tla b/specifications/Paxos/Voting.tla index 94757725..3f3a7420 100644 --- a/specifications/Paxos/Voting.tla +++ b/specifications/Paxos/Voting.tla @@ -17,6 +17,7 @@ ASSUME QuorumAssumption == /\ \A Q \in Quorum : Q \subseteq Acceptor /\ \A Q1, Q2 \in Quorum : Q1 \cap Q2 # {} THEOREM QuorumNonEmpty == \A Q \in Quorum : Q # {} +BY QuorumAssumption ----------------------------------------------------------------------------- (***************************************************************************) (* Ballot is a set of "ballot numbers". For simplicity, we let it be the *) diff --git a/specifications/PaxosHowToWinATuringAward/Consensus.tla b/specifications/PaxosHowToWinATuringAward/Consensus.tla index c29c7fae..54f4d20a 100644 --- a/specifications/PaxosHowToWinATuringAward/Consensus.tla +++ b/specifications/PaxosHowToWinATuringAward/Consensus.tla @@ -1,6 +1,6 @@ ----------------------------- MODULE Consensus ------------------------------ (***************************************************************************) -(* This is an very abstract specification of the consensus problem, in *) +(* This is a very abstract specification of the consensus problem, in *) (* which a set of processes must choose a single value. We abstract away *) (* even the processes. We specify the simple requirement that at most one *) (* value is chosen by describing the set of all chosen values. The naive *) diff --git a/specifications/TeachingConcurrency/Simple.pdf b/specifications/TeachingConcurrency/Simple.pdf index 9c19e7f7..39f92db2 100644 Binary files a/specifications/TeachingConcurrency/Simple.pdf and b/specifications/TeachingConcurrency/Simple.pdf differ diff --git a/specifications/TeachingConcurrency/Simple.tla b/specifications/TeachingConcurrency/Simple.tla index a84c598c..cb894a98 100644 --- a/specifications/TeachingConcurrency/Simple.tla +++ b/specifications/TeachingConcurrency/Simple.tla @@ -116,7 +116,6 @@ Inv == /\ TypeOK /\ \/ \E i \in 0..(N-1) : pc[i] /= "Done" \/ \E i \in 0..(N-1) : y[i] = 1 - (***************************************************************************) (* Here is the proof of correctness. The top-level steps <1>1 - <1>4 are *) (* the standard ones for an invariance proof, and the decomposition of the *) @@ -124,7 +123,7 @@ Inv == /\ TypeOK (* was trivial to get TLAPS to check the proof, except for the proof of *) (* <2>2. A comment explains the problem I had with that step. *) (***************************************************************************) -THEOREM Spec => []PCorrect +THEOREM Correctness == Spec => []PCorrect <1> USE NAssump <1>1. Init => Inv BY DEF Init, Inv, TypeOK, ProcSet @@ -156,6 +155,21 @@ THEOREM Spec => []PCorrect BY DEF Inv, TypeOK, PCorrect <1>4. QED BY <1>1, <1>2, <1>3, PTL DEF Spec + +(***************************************************************************) +(* It turns out that decomposing step <1>2 is not really necessary: the *) +(* following shorter proof is also accepted by TLAPS. *) +(***************************************************************************) +THEOREM Correctness2 == Spec => []PCorrect +<1>. USE NAssump DEF Inv, TypeOK, ProcSet +<1>1. Init => Inv + BY DEF Init +<1>2. Inv /\ [Next]_vars => Inv' + BY DEF Next, a, b, vars, Terminating, proc +<1>3. Inv => PCorrect + BY DEF PCorrect +<1>. QED BY <1>1, <1>2, <1>3, PTL DEF Spec + ============================================================================= \* Modification History \* Last modified Wed May 15 02:33:18 PDT 2019 by lamport diff --git a/specifications/TeachingConcurrency/SimpleRegular.pdf b/specifications/TeachingConcurrency/SimpleRegular.pdf index ee7aba28..27c3154c 100644 Binary files a/specifications/TeachingConcurrency/SimpleRegular.pdf and b/specifications/TeachingConcurrency/SimpleRegular.pdf differ diff --git a/specifications/TeachingConcurrency/SimpleRegular.tla b/specifications/TeachingConcurrency/SimpleRegular.tla index e1314ab6..84b9ae7f 100644 --- a/specifications/TeachingConcurrency/SimpleRegular.tla +++ b/specifications/TeachingConcurrency/SimpleRegular.tla @@ -140,7 +140,7 @@ Inv == /\ TypeOK (* As before, the decomposition of the proof of <1>2 was essentially *) (* generated with the Toolbox's Decompose Proof command. *) (***************************************************************************) -THEOREM Spec => []PCorrect +THEOREM Correctness == Spec => []PCorrect <1> USE NAssump DEF ProcSet <1>1. Init => Inv <2>1. Init => 0 \in 0..(N-1) /\ pc[0] /= "Done" @@ -176,6 +176,22 @@ THEOREM Spec => []PCorrect BY DEF Inv, TypeOK, PCorrect <1>4. QED BY <1>1, <1>2, <1>3, PTL DEF Spec + +(***************************************************************************) +(* As for the specification in module Simple, the proof can be shortened *) +(* avoiding the decomposition of step <1>2. In order to find the witness *) +(* for the existential quantifier, the proof of step <1>1 requires a small *) +(* hint showing that 0 is a suitable value. *) +(***************************************************************************) +THEOREM Correctness2 == Spec => []PCorrect +<1>. USE NAssump DEF Inv, TypeOK, ProcSet +<1>1. Init => Inv + BY 0 \in 0 .. N-1 DEF Init +<1>2. Inv /\ [Next]_vars => Inv' + BY DEF Next, vars, a1, a2, b, Terminating, proc +<1>3. Inv => PCorrect + BY DEF PCorrect +<1>. QED BY <1>1, <1>2, <1>3, PTL DEF Spec ====================================== \* Modification History \* Last modified Tue May 14 07:18:15 PDT 2019 by lamport diff --git a/specifications/TwoPhase/TLAPS.tla b/specifications/TwoPhase/TLAPS.tla deleted file mode 100644 index 3abf4b1b..00000000 --- a/specifications/TwoPhase/TLAPS.tla +++ /dev/null @@ -1,411 +0,0 @@ -------------------------------- MODULE TLAPS -------------------------------- - -(* Backend pragmas. *) - - -(***************************************************************************) -(* Each of these pragmas can be cited with a BY or a USE. The pragma that *) -(* is added to the context of an obligation most recently is the one whose *) -(* effects are triggered. *) -(***************************************************************************) - -(***************************************************************************) -(* The following pragmas should be used only as a last resource. They are *) -(* dependent upon the particular backend provers, and are unlikely to have *) -(* any effect if the set of backend provers changes. Moreover, they are *) -(* meaningless to a reader of the proof. *) -(***************************************************************************) - - -(**************************************************************************) -(* Backend pragma: use the SMT solver for arithmetic. *) -(* *) -(* This method exists under this name for historical reasons. *) -(**************************************************************************) - -SimpleArithmetic == TRUE (*{ by (prover:"smt3") }*) - - -(**************************************************************************) -(* Backend pragma: SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2. The supported *) -(* fragment includes first-order logic, set theory, functions and *) -(* records. *) -(* SMT calls the smt-solver with the default timeout of 5 seconds *) -(* while SMTT(n) calls the smt-solver with a timeout of n seconds. *) -(**************************************************************************) - -SMT == TRUE (*{ by (prover:"smt3") }*) -SMTT(X) == TRUE (*{ by (prover:"smt3"; timeout:@) }*) - - -(**************************************************************************) -(* Backend pragma: CVC3 SMT solver *) -(* *) -(* CVC3 is used by default but you can also explicitly call it. *) -(**************************************************************************) - -CVC3 == TRUE (*{ by (prover: "cvc33") }*) -CVC3T(X) == TRUE (*{ by (prover:"cvc33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Yices SMT solver *) -(* *) -(* This method translates the proof obligation to Yices native language. *) -(**************************************************************************) - -Yices == TRUE (*{ by (prover: "yices3") }*) -YicesT(X) == TRUE (*{ by (prover:"yices3"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: veriT SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls veriT.*) -(**************************************************************************) - -veriT == TRUE (*{ by (prover: "verit") }*) -veriTT(X) == TRUE (*{ by (prover:"verit"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Z3 SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls Z3. *) -(**************************************************************************) - -Z3 == TRUE (*{ by (prover: "z33") }*) -Z3T(X) == TRUE (*{ by (prover:"z33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: SPASS superposition prover *) -(* *) -(* This method translates the proof obligation to the DFG format language *) -(* supported by the ATP SPASS. The translation is based on the SMT one. *) -(**************************************************************************) - -Spass == TRUE (*{ by (prover: "spass") }*) -SpassT(X) == TRUE (*{ by (prover:"spass"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: The PTL propositional linear time temporal logic *) -(* prover. It currently is the LS4 backend. *) -(* *) -(* This method translates the negetation of the proof obligation to *) -(* Seperated Normal Form (TRP++ format) and checks for unsatisfiability *) -(**************************************************************************) - -LS4 == TRUE (*{ by (prover: "ls4") }*) -PTL == TRUE (*{ by (prover: "ls4") }*) - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -Zenon == TRUE (*{ by (prover:"zenon") }*) -ZenonT(X) == TRUE (*{ by (prover:"zenon"; timeout:@) }*) - -(********************************************************************) -(* Backend pragma: Isabelle with different timeouts and tactics *) -(* (default is 30 seconds/auto) *) -(********************************************************************) - -Isa == TRUE (*{ by (prover:"isabelle") }*) -IsaT(X) == TRUE (*{ by (prover:"isabelle"; timeout:@) }*) -IsaM(X) == TRUE (*{ by (prover:"isabelle"; tactic:@) }*) -IsaMT(X,Y) == TRUE (*{ by (prover:"isabelle"; tactic:@; timeout:@) }*) - -(***************************************************************************) -(* The following theorem expresses the (useful implication of the) law of *) -(* set extensionality, which can be written as *) -(* *) -(* THEOREM \A S, T : (S = T) <=> (\A x : (x \in S) <=> (x \in T)) *) -(* *) -(* Theorem SetExtensionality is sometimes required by the SMT backend for *) -(* reasoning about sets. It is usually counterproductive to include *) -(* theorem SetExtensionality in a BY clause for the Zenon or Isabelle *) -(* backends. Instead, use the pragma IsaWithSetExtensionality to instruct *) -(* the Isabelle backend to use the rule of set extensionality. *) -(***************************************************************************) -IsaWithSetExtensionality == TRUE - (*{ by (prover:"isabelle"; tactic:"(auto intro: setEqualI)")}*) - -THEOREM SetExtensionality == \A S,T : (\A x : x \in S <=> x \in T) => S = T -OBVIOUS - -(***************************************************************************) -(* The following theorem is needed to deduce NotInSetS \notin SetS from *) -(* the definition *) -(* *) -(* NotInSetS == CHOOSE v : v \notin SetS *) -(***************************************************************************) -THEOREM NoSetContainsEverything == \A S : \E x : x \notin S -OBVIOUS (*{by (isabelle "(auto intro: inIrrefl)")}*) ------------------------------------------------------------------------------ - - - -(********************************************************************) -(********************************************************************) -(********************************************************************) - - -(********************************************************************) -(* Old versions of Zenon and Isabelle pragmas below *) -(* (kept for compatibility) *) -(********************************************************************) - - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -SlowZenon == TRUE (*{ by (prover:"zenon"; timeout:20) }*) -SlowerZenon == TRUE (*{ by (prover:"zenon"; timeout:40) }*) -VerySlowZenon == TRUE (*{ by (prover:"zenon"; timeout:80) }*) -SlowestZenon == TRUE (*{ by (prover:"zenon"; timeout:160) }*) - - - -(********************************************************************) -(* Backend pragma: Isabelle's automatic search ("auto") *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* essentially simplification and equational reasoning. *) -(* Default imeout for all isabelle tactics is 30 seconds. *) -(********************************************************************) -Auto == TRUE (*{ by (prover:"isabelle"; tactic:"auto") }*) -SlowAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:120) }*) -SlowerAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:480) }*) -SlowestAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:960) }*) - -(********************************************************************) -(* Backend pragma: Isabelle's "force" tactic *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* quantifier reasoning. *) -(********************************************************************) -Force == TRUE (*{ by (prover:"isabelle"; tactic:"force") }*) -SlowForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:120) }*) -SlowerForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:480) }*) -SlowestForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:960) }*) - -(***********************************************************************) -(* Backend pragma: Isabelle's "simplification" tactics *) -(* *) -(* These tactics simplify the goal before running one of the automated *) -(* tactics. They are often necessary for obligations involving record *) -(* or tuple projections. Use the SimplfyAndSolve tactic unless you're *) -(* sure you can get away with just Simplification *) -(***********************************************************************) -SimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?") }*) -SlowSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:120) }*) -SlowerSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:480) }*) -SlowestSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:960) }*) - -Simplification == TRUE (*{ by (prover:"isabelle"; tactic:"clarsimp") }*) -SlowSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:120) }*) -SlowerSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:480) }*) -SlowestSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:960) }*) - -(**************************************************************************) -(* Backend pragma: Isabelle's tableau prover ("blast") *) -(* *) -(* This pragma bypasses Zenon and uses Isabelle's built-in theorem *) -(* prover, Blast. It is almost never better than Zenon by itself, but *) -(* becomes very useful in combination with the Auto pragma above. The *) -(* AutoBlast pragma first attempts Auto and then uses Blast to prove what *) -(* Auto could not prove. (There is currently no way to use Zenon on the *) -(* results left over from Auto.) *) -(**************************************************************************) -Blast == TRUE (*{ by (prover:"isabelle"; tactic:"blast") }*) -SlowBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:120) }*) -SlowerBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:480) }*) -SlowestBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:960) }*) - -AutoBlast == TRUE (*{ by (prover:"isabelle"; tactic:"auto, blast") }*) - - -(**************************************************************************) -(* Backend pragmas: multi-back-ends *) -(* *) -(* These pragmas just run a bunch of back-ends one after the other in the *) -(* hope that one will succeed. This saves time and effort for the user at *) -(* the expense of computation time. *) -(**************************************************************************) - -(* CVC3 goes first because it's bundled with TLAPS, then the other SMT - solvers are unlikely to succeed if CVC3 fails, so we run zenon and - Isabelle before them. *) -AllProvers == TRUE (*{ - by (prover:"cvc33") - by (prover:"zenon") - by (prover:"isabelle"; tactic:"auto") - by (prover:"spass") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllProversT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"zenon"; timeout:@) - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"spass"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - -AllSMT == TRUE (*{ - by (prover:"cvc33") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - }*) -AllSMTT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - }*) - -AllIsa == TRUE (*{ - by (prover:"isabelle"; tactic:"auto") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllIsaT(X) == TRUE (*{ - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - ----------------------------------------------------------------------------- -(***************************************************************************) -(* TEMPORAL LOGIC *) -(* *) -(* The following rules are intended to be used when TLAPS handles temporal *) -(* logic. They will not work now. Moreover when temporal reasoning is *) -(* implemented, these rules may be changed or omitted, and additional *) -(* rules will probably be added. However, they are included mainly so *) -(* their names will be defined, preventing the use of identifiers that are *) -(* likely to produce name clashes with future versions of this module. *) -(***************************************************************************) - - -(***************************************************************************) -(* The following proof rules (and their names) are from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleTLA1 == ASSUME STATE P, STATE f, - P /\ (f' = f) => P' - PROVE []P <=> P /\ [][P => P']_f - -THEOREM RuleTLA2 == ASSUME STATE P, STATE Q, STATE f, STATE g, - ACTION A, ACTION B, - P /\ [A]_f => Q /\ [B]_g - PROVE []P /\ [][A]_f => []Q /\ [][B]_g - -THEOREM RuleINV1 == ASSUME STATE I, STATE F, ACTION N, - I /\ [N]_F => I' - PROVE I /\ [][N]_F => []I - -THEOREM RuleINV2 == ASSUME STATE I, STATE f, ACTION N - PROVE []I => ([][N]_f <=> [][N /\ I /\ I']_f) - -THEOREM RuleWF1 == ASSUME STATE P, STATE Q, STATE f, ACTION N, ACTION A, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - P => ENABLED <>_f - PROVE [][N]_f /\ WF_f(A) => (P ~> Q) - -THEOREM RuleSF1 == ASSUME STATE P, STATE Q, STATE f, - ACTION N, ACTION A, TEMPORAL F, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - []P /\ [][N]_f /\ []F => <> ENABLED <>_f - PROVE [][N]_f /\ SF_f(A) /\ []F => (P ~> Q) - -(***************************************************************************) -(* The rules WF2 and SF2 in "The Temporal Logic of Actions" are obtained *) -(* from the following two rules by the following substitutions: `. *) -(* *) -(* ___ ___ _______________ *) -(* M <- M , g <- g , EM <- ENABLED <>_g .' *) -(***************************************************************************) -THEOREM RuleWF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ WF_f(A) /\ []F /\ <>[]EM => <>[]P - PROVE [][N]_f /\ WF_f(A) /\ []F => []<><>_g \/ []<>(~EM) - -THEOREM RuleSF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ SF_f(A) /\ []F /\ []<>EM => <>[]P - PROVE [][N]_f /\ SF_f(A) /\ []F => []<><>_g \/ <>[](~EM) - - -(***************************************************************************) -(* The following rule is a special case of the general temporal logic *) -(* proof rule STL4 from the paper "The Temporal Logic of Actions". The *) -(* general rule is for arbitrary temporal formulas F and G, but it cannot *) -(* yet be handled by TLAPS. *) -(***************************************************************************) -THEOREM RuleInvImplication == - ASSUME STATE F, STATE G, - F => G - PROVE []F => []G -PROOF OMITTED - -(***************************************************************************) -(* The following rule is a special case of rule TLA2 from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleStepSimulation == - ASSUME STATE I, STATE f, STATE g, - ACTION M, ACTION N, - I /\ I' /\ [M]_f => [N]_g - PROVE []I /\ [][M]_f => [][N]_g -PROOF OMITTED - -(***************************************************************************) -(* The following may be used to invoke a decision procedure for *) -(* propositional temporal logic. *) -(***************************************************************************) -PropositionalTemporalLogic == TRUE -============================================================================= diff --git a/specifications/bcastByz/bcastByz.tla b/specifications/bcastByz/bcastByz.tla index b4e383d4..43ce7814 100644 --- a/specifications/bcastByz/bcastByz.tla +++ b/specifications/bcastByz/bcastByz.tla @@ -276,7 +276,7 @@ THEOREM NTFRel == N \in Nat /\ T \in Nat /\ F \in Nat /\ (N > 3 * T) /\ (T >= F) (* Proc is always a finite set and its cardinality is N*) THEOREM ProcProp == Cardinality(Proc) = N /\ IsFiniteSet(Proc) /\ Cardinality(Proc) \in Nat - BY FS_Interval, NTFRel DEF Proc + BY FS_Interval, NTFRel, Isa DEF Proc (* If we have 1/ X, Y, and Z are finite, @@ -444,7 +444,7 @@ THEOREM FCConstraints_TypeOK_Init == <2>2 Cardinality(Proc) - Cardinality(Corr) <= T BY <1>7, <2>1, ProcProp, NTFRel <2>3 QED - BY <1>3, <1>4, <1>5, <1>6, <2>2, UMFS_CardinalityType, ProcProp + BY <1>3, <1>4, <1>5, <1>6, <2>2, UMFS_CardinalityType, ProcProp, Zenon <1>9 ByzMsgs \subseteq Proc \X M BY <1>2 <1>10 IsFiniteSet(ByzMsgs) @@ -479,7 +479,7 @@ THEOREM FCConstraints_TypeOK_Init == OBVIOUS <1> QED BY <1>1, <1>2, <1>3, <1>4, <1>5, <1>6, <1>7, <1>8, <1>9, - <1>10, <1>11, <1>12, <1>13, <1>14, <1>15, <1>16 + <1>10, <1>11, <1>12, <1>13, <1>14, <1>15, <1>16, Zenon THEOREM FCConstraints_TypeOK_IndInv_Unforg_NoBcast == @@ -517,7 +517,7 @@ THEOREM FCConstraints_TypeOK_IndInv_Unforg_NoBcast_TLC == <3> QED BY <1>7, <2>1, ProcProp, NTFRel <2>3 QED - BY <1>3, <1>4, <1>5, <1>6, <2>2, UMFS_CardinalityType, ProcProp + BY <1>3, <1>4, <1>5, <1>6, <2>2, UMFS_CardinalityType, ProcProp, Zenon <1>9 ByzMsgs \subseteq Proc \X M BY <1>2 <1>10 IsFiniteSet(ByzMsgs) @@ -553,7 +553,7 @@ THEOREM FCConstraints_TypeOK_IndInv_Unforg_NoBcast_TLC == OBVIOUS <1> QED BY <1>1, <1>2, <1>3, <1>4, <1>5, <1>6, <1>7, <1>8, <1>9, - <1>10, <1>11, <1>12, <1>13, <1>14, <1>15, <1>16 + <1>10, <1>11, <1>12, <1>13, <1>14, <1>15, <1>16, Zenon THEOREM FCConstraints_TypeOK_Next == @@ -717,7 +717,7 @@ THEOREM FCConstraints_TypeOK_Next == BY <4>1, <4>2 <3>4 CASE ReceiveFromAnySender(i) /\ UponAcceptNotSentBefore(i) <4>1 FCConstraints' - BY <3>4 DEF Receive, UponAcceptNotSentBefore, FCConstraints, ByzMsgs + BY <3>4, Zenon DEF Receive, UponAcceptNotSentBefore, FCConstraints, ByzMsgs <4>2 TypeOK' <5>1 pc' \in [ Proc -> {"V0", "V1", "SE", "AC"} ] BY <3>4 DEFS UponAcceptNotSentBefore, TypeOK @@ -752,7 +752,7 @@ THEOREM FCConstraints_TypeOK_Next == <6> QED BY <3>4, <6>1, <6>2, <6>3, <6>4 DEFS UponAcceptNotSentBefore, TypeOK, Receive <5>7 Corr' = Corr - BY <3>4 DEFS UponAcceptNotSentBefore + BY <3>4, Zenon DEFS UponAcceptNotSentBefore <5> QED BY <1>2, <3>4, <4>1, <5>1, <5>5, <5>6, <5>7 DEF TypeOK, FCConstraints <4> QED @@ -794,7 +794,7 @@ THEOREM FCConstraints_TypeOK_Next == <6> QED BY <3>5, <6>1, <6>2, <6>3, <6>4 DEFS UponAcceptSentBefore, TypeOK, Receive <5>7 Corr' = Corr - BY <3>5 DEFS UponAcceptSentBefore + BY <3>5, Zenon DEFS UponAcceptSentBefore <5> QED BY <1>2, <3>5, <4>1, <5>1, <5>5, <5>6, <5>7 DEF TypeOK, FCConstraints <4> QED @@ -962,7 +962,7 @@ THEOREM Unforg_Step2 == IndInv_Unforg_NoBcast /\ [Next]_vars => IndInv_Unforg_No <6>6 Receive(i, TRUE) <=> (\E newMessages \in SUBSET ByzMsgs : rcvd' = [ j \in Proc |-> IF j # i THEN rcvd[j] ELSE rcvd[i] \cup newMessages ]) - BY <5>1, <6>5 + BY <5>1, <6>5, Zenon <6>7 Receive(i, TRUE) BY <6>3 <6>8 \E newMessages \in SUBSET ByzMsgs : @@ -1036,7 +1036,7 @@ THEOREM Unforg_Step2 == IndInv_Unforg_NoBcast /\ [Next]_vars => IndInv_Unforg_No \/ ~(pc' = [pc EXCEPT ![i] = "SE"]) \/ ~(sent' = sent \cup { <> }) \/ ~(UNCHANGED << Corr, Faulty >>) - BY DEF UponNonFaulty + BY Zenon DEF UponNonFaulty <5>2 (Cardinality(rcvd'[i]) <= T) => ~UponNonFaulty(i) <6>1 T < N - 2 * T BY NTFRel diff --git a/specifications/byzpaxos/BPConProof.tla b/specifications/byzpaxos/BPConProof.tla index a55259cc..1e1c49c5 100644 --- a/specifications/byzpaxos/BPConProof.tla +++ b/specifications/byzpaxos/BPConProof.tla @@ -582,7 +582,7 @@ LEMMA NextDef == \/ Phase1c(self) \/ \E self \in FakeAcceptor : FakingAcceptor(self) <1>1. \A self : acceptor(self) <=> NextDef!2!1!(self) - BY DEF acceptor, Phase1b, Phase2av, Phase2b, LearnsSent + BY Zenon DEF acceptor, Phase1b, Phase2av, Phase2b, LearnsSent <1>2. \A self : leader(self) <=> NextDef!2!2!(self) BY DEF leader, Phase1a, Phase1c <1>3. \A self : facceptor(self) <=> NextDef!2!3!(self) @@ -605,7 +605,7 @@ Quorum == {S \cap Acceptor : S \in ByzQuorum} THEOREM QuorumTheorem == /\ \A Q1, Q2 \in Quorum : Q1 \cap Q2 # {} /\ \A Q \in Quorum : Q \subseteq Acceptor -BY BQA DEF Quorum +BY BQA, IsaM("blast") DEF Quorum, ByzAcceptor (***************************************************************************) (* We now define refinement mapping under which our algorithm implements *) @@ -719,7 +719,7 @@ LEMMA MaxBallotLemma1 == /\ y >= MaxBallot(S) BY MaxBallotProp <1>3. MaxBallot(S) \in Int /\ y \in Int - BY <1>1, <1>2, Isa DEF Ballot + BY <1>1, <1>2 DEF Ballot <1>. QED BY <1>1, <1>2, <1>3 LEMMA MaxBallotLemma2 == @@ -758,7 +758,7 @@ LEMMA MaxBallotLemma2 == <1>3. CASE ~(MaxBallot(S) >= MaxBallot(T)) <2>. SUFFICES ASSUME S # {} PROVE MaxBallot(S \cup T) = MaxBallot(T) - BY <1>3 + BY <1>3, Zenon <2>1. /\ MaxBallot(S) \in S /\ \A x \in S : MaxBallot(S) >= x BY MaxBallotProp @@ -844,7 +844,11 @@ bmsgsFinite == IsFiniteSet(1bOr2bMsgs) LEMMA FiniteMsgsLemma == ASSUME NEW m, bmsgsFinite, bmsgs' = bmsgs \cup {m} PROVE bmsgsFinite' -BY FS_AddElement DEF bmsgsFinite, 1bOr2bMsgs +<1>1. CASE m.type \in {"1b", "2b"} + BY <1>1, FS_AddElement, Isa DEF bmsgsFinite, 1bOr2bMsgs +<1>2. CASE m.type \notin {"1b", "2b"} + BY <1>2, FS_AddElement, Isa DEF bmsgsFinite, 1bOr2bMsgs +<1>. QED BY <1>1, <1>2 (***************************************************************************) (* Invariant 1bInv1 asserts that if (good) acceptor `a' has mCBal[a] # -1, *) @@ -1126,7 +1130,7 @@ TypeOK => /\ 1cmsgs' = 1cmsgs /\ 2amsgs' = 2amsgs /\ acceptorMsgsOfType("2b")' = acceptorMsgsOfType("2b") - BY <2>1 DEF msgsOfType, 1bmsgs, acceptorMsgsOfType, KnowsSafeAt, 1cmsgs, 2amsgs + BY <2>1, Isa DEF msgsOfType, 1bmsgs, acceptorMsgsOfType, KnowsSafeAt, 1cmsgs, 2amsgs <2>. QED BY <2>a DEF msgs, 1bRestrict @@ -1157,9 +1161,12 @@ TypeOK => /\ 1bmsgs' = 1bmsgs /\ 1cmsgs' = 1cmsgs /\ acceptorMsgsOfType("2b")' = acceptorMsgsOfType("2b") - BY <2>1, <3>1 DEF msgsOfType, 1bmsgs, 1bRestrict, acceptorMsgsOfType, KnowsSafeAt, 1cmsgs - <3>. QED - BY <3>1, <3>2, <2>1, <2>3 DEF msgs, 2amsgs, msgsOfType, acceptorMsgsOfType + BY <2>1, <3>1, Isa DEF msgsOfType, 1bmsgs, 1bRestrict, acceptorMsgsOfType, KnowsSafeAt, 1cmsgs + <3>3. 2amsgs \subseteq 2amsgs' + BY <2>1 DEF 2amsgs, acceptorMsgsOfType, msgsOfType + <3>4. \A m2a \in 2amsgs' \ 2amsgs : m2a = ma + BY <2>1 DEF 2amsgs, acceptorMsgsOfType, msgsOfType + <3>. QED BY <2>3, <3>2, <3>3, <3>4, Zenon DEF msgs <2>6. QED BY <2>4, <2>5 @@ -1190,7 +1197,7 @@ TypeOK => /\ 1cmsgs' = 1cmsgs /\ 2amsgs' = 2amsgs /\ acceptorMsgsOfType("2b")' = acceptorMsgsOfType("2b") \cup {bm} - BY <2>1 DEF msgsOfType, 1bmsgs, 1bRestrict, 1cmsgs, KnowsSafeAt, 2amsgs, acceptorMsgsOfType + BY <2>1, Isa DEF msgsOfType, 1bmsgs, 1bRestrict, 1cmsgs, KnowsSafeAt, 2amsgs, acceptorMsgsOfType <2>4. msgs' = msgs \cup {bm} BY <2>2 DEF msgs <2>. QED @@ -1208,11 +1215,15 @@ TypeOK => <3>1. bmsgs' = bmsgs BY <1>4 DEF LearnsSent <3>2. PICK S \in SUBSET sentMsgs("1b", b): - knowsSent' = [knowsSent EXCEPT ![self] = knowsSent[self] \cup S] + knowsSent' = [knowsSent EXCEPT ![self] = @ \cup S] BY <1>4, Zenon DEF LearnsSent + <3>ks. ASSUME NEW ac \in Acceptor, NEW bb, NEW vv, + KnowsSafeAt(ac,bb,vv) + PROVE KnowsSafeAt(ac,bb,vv)' + BY <3>2, <3>ks DEF TypeOK, KnowsSafeAt <3>3. ASSUME NEW m \in 1cmsgs PROVE m \in 1cmsgs' - BY <3>1, <3>2 DEF TypeOK, KnowsSafeAt, 1cmsgs, msgsOfType + BY <3>1, <3>ks DEF 1cmsgs, msgsOfType <3>4. ASSUME NEW m \in 1cmsgs', m \notin 1cmsgs PROVE m \in msgsOfType("1c") /\ m.bal = b <4>1. m \in msgsOfType("1c") @@ -1241,8 +1252,9 @@ TypeOK => <1>5. ASSUME NEW self \in Ballot, Phase1a(self) PROVE msgs' = msgs \cup {[type |-> "1a", bal |-> self]} - BY <1>5 DEF Phase1a, msgs, msgsOfType, 1bmsgs, 1bRestrict, 1cmsgs, KnowsSafeAt, - 2amsgs, acceptorMsgsOfType + BY <1>5, Isa + DEF Phase1a, msgs, msgsOfType, 1bmsgs, 1bRestrict, 1cmsgs, KnowsSafeAt, + 2amsgs, acceptorMsgsOfType <1>6. ASSUME NEW self \in Ballot, Phase1c(self) PROVE \E S \in SUBSET [type : {"1c"}, bal : {self}, val : Value]: @@ -1258,17 +1270,41 @@ TypeOK => BY <2>1, Zenon <2>2. /\ msgsOfType("1a")' = msgsOfType("1a") /\ 1bmsgs' = 1bmsgs - /\ 1cmsgs' = 1cmsgs \cup SS - /\ 2amsgs' = 2amsgs /\ acceptorMsgsOfType("2b")' = acceptorMsgsOfType("2b") - BY <2>1 DEF msgsOfType, 1bmsgs, 1bRestrict, 1cmsgs, KnowsSafeAt, 2amsgs, acceptorMsgsOfType - <2>3. QED - BY <2>2 DEF msgs + BY <2>1 DEF msgsOfType, 1bmsgs, 1bRestrict, acceptorMsgsOfType + <2>3. 1cmsgs' = 1cmsgs \cup SS + <3>1. ASSUME NEW ac \in Acceptor, NEW bb, NEW vv + PROVE KnowsSafeAt(ac, bb, vv)' <=> KnowsSafeAt(ac, bb, vv) + BY <2>1 DEF KnowsSafeAt + <3>. QED BY <2>1, <3>1 DEF 1cmsgs, msgsOfType + <2>4. 2amsgs' = 2amsgs + BY <2>1 DEF 2amsgs, acceptorMsgsOfType, msgsOfType + <2>. QED + BY <2>2, <2>3, <2>4 DEF msgs <1>7. ASSUME NEW self \in FakeAcceptor, FakingAcceptor(self) PROVE msgs' = msgs - BY <1>7, BQA DEF FakingAcceptor, msgs, 1bMessage, 2avMessage, 2bMessage, - msgsOfType, 1cmsgs, KnowsSafeAt, 1bmsgs, 2amsgs, acceptorMsgsOfType, msgsOfType + <2>1. PICK m \in 1bMessage \cup 2avMessage \cup 2bMessage : + /\ m.acc = self + /\ bmsgs' = bmsgs \cup {m} + /\ UNCHANGED knowsSent + BY <1>7 DEF FakingAcceptor + <2>2. m.type \in {"1b", "2av", "2b"} + BY DEF 1bMessage, 2avMessage, 2bMessage + <2>3. msgsOfType("1a")' = msgsOfType("1a") + BY <2>1, <2>2 DEF msgsOfType + <2>4. /\ 1bmsgs' = 1bmsgs + /\ acceptorMsgsOfType("2b")' = acceptorMsgsOfType("2b") + /\ acceptorMsgsOfType("2av")' = acceptorMsgsOfType("2av") + BY <2>1, BQA DEF 1bmsgs, acceptorMsgsOfType, msgsOfType + <2>5. ASSUME NEW ac \in Acceptor, NEW bb, NEW vv + PROVE KnowsSafeAt(ac, bb, vv)' <=> KnowsSafeAt(ac, bb, vv) + BY <2>1 DEF KnowsSafeAt + <2>6. 1cmsgs' = 1cmsgs + BY <2>1, <2>2, <2>5 DEF 1cmsgs, msgsOfType + <2>7. 2amsgs' = 2amsgs + BY <2>4 DEF 2amsgs + <2>. QED BY <2>3, <2>4, <2>6, <2>7 DEF msgs <1>9. QED BY <1>1, <1>2, <1>3, <1>4, <1>5, <1>6, <1>7, Zenon @@ -1279,7 +1315,8 @@ TypeOK => (***************************************************************************) THEOREM Invariance == Spec => []Inv <1>1. Init => Inv - BY FS_EmptySet DEF Init, Inv, TypeOK, bmsgsFinite, 1bOr2bMsgs, 1bInv1, 1bInv2, + BY FS_EmptySet, Zenon + DEF Init, Inv, TypeOK, bmsgsFinite, 1bOr2bMsgs, 1bInv1, 1bInv2, maxBalInv, 2avInv1, 2avInv2, 2avInv3, accInv, knowsSentInv <1>2. Inv /\ [Next]_vars => Inv' @@ -1301,12 +1338,14 @@ THEOREM Invariance == Spec => []Inv mbal |-> maxVBal[self], mval |-> maxVVal[self]] <4>1. msgs' = msgs \cup {mc} BY <3>1, MsgsLemma DEF Inv + <4>. mb \in 1bMessage + BY Zenon DEF Inv, TypeOK, 1bMessage, ByzAcceptor <4>2. TypeOK' - BY <3>1 DEF Inv, TypeOK, BMessage, 1bMessage, ByzAcceptor, Phase1b + BY <3>1 DEF Inv, TypeOK, BMessage, Phase1b <4>3. bmsgsFinite' BY <3>1, FiniteMsgsLemma, Zenon DEF Inv, bmsgsFinite, Phase1b <4>4. 1bInv1' - BY <3>1, <4>1, IsaT(100) DEF Phase1b, 1bInv1, Inv, accInv + BY <3>1, <4>1, Isa DEF Phase1b, 1bInv1, Inv, accInv <4>5. 1bInv2' BY <3>1 DEF Phase1b, 1bInv2, Inv, maxBalInv, TypeOK, 1bMessage, Ballot <4>6. maxBalInv' @@ -1332,7 +1371,7 @@ THEOREM Invariance == Spec => []Inv <4>11. knowsSentInv' BY <3>1 DEF Phase1b, Inv, knowsSentInv, msgsOfType <4>12. QED - BY <4>2, <4>3, <4>4, <4>5, <4>6, <4>7, <4>8, <4>9, <4>10, <4>11 DEF Inv + BY <4>2, <4>3, <4>4, <4>5, <4>6, <4>7, <4>8, <4>9, <4>10, <4>11, Zenon DEF Inv <3>2. CASE Phase2av(self, b) <4>1. PICK mc \in sentMsgs("1c", b) : /\ KnowsSafeAt(self, b, mc.val) @@ -1342,6 +1381,7 @@ THEOREM Invariance == Spec => []Inv /\ 2avSent' = [2avSent EXCEPT ![self] = {r \in 2avSent[self] : r.val # mc.val} \cup {[val |-> mc.val, bal |-> b]}] + /\ maxBal' = [maxBal EXCEPT ![self] = b] BY <3>2, Zenon DEF Phase2av <4>2. mc = [type |-> "1c", bal |-> mc.bal, val |-> mc.val] BY <4>1, BMessageLemma DEF sentMsgs, Inv, TypeOK, 1cMessage @@ -1362,7 +1402,7 @@ THEOREM Invariance == Spec => []Inv <4>6. bmsgsFinite' BY <4>1, FiniteMsgsLemma, Zenon DEF Inv, bmsgsFinite <4>7. 1bInv1' - BY <3>2, <4>1, <4>3, IsaT(100) DEF Phase2av, 1bInv1, Inv + BY <3>2, <4>1, <4>3 DEF Phase2av, 1bInv1, Inv <4>8. 1bInv2' BY <4>1 DEF Inv, 1bInv2 <4>9. maxBalInv' @@ -1378,7 +1418,7 @@ THEOREM Invariance == Spec => []Inv BY DEF 2avInv2 <5>2. CASE m.acc = self <6>1. CASE m = mb - BY <4>1, <6>1, Isa DEF Inv, TypeOK, Ballot + BY <4>1, <6>1 DEF Inv, TypeOK, Ballot <6>2. CASE m # mb <7>1. m \in bmsgs BY <4>1, <6>2 @@ -1415,8 +1455,16 @@ THEOREM Invariance == Spec => []Inv <5>2. CASE r \in 2avSent[a] BY <5>2, <4>4, <4>5, <3>2 DEF Phase2av, Inv, TypeOK, accInv, Ballot <5>3. CASE r \notin 2avSent[a] - BY <5>3, <3>2, <4>1, <4>2, <4>4 - DEF Phase2av, Inv, TypeOK, sentMsgs, msgsOfType, msgs, 1cmsgs, Ballot + <6>1. /\ a = self + /\ r = [val |-> mc.val, bal |-> b] + /\ KnowsSafeAt(self, b, mc.val) + /\ maxBal' = [maxBal EXCEPT ![a] = b] + BY <4>1, <5>3 DEF Inv, TypeOK + <6>2. r.bal <= maxBal'[a] + BY <6>1 DEF Inv, TypeOK, Ballot + <6>3. [type |-> "1c", bal |-> r.bal, val |-> r.val] \in msgs + BY <4>2, <6>1 DEF msgs, 1cmsgs, sentMsgs, msgsOfType + <6>. QED BY <4>4, <6>2, <6>3 <5>4. QED BY <5>2, <5>3 <4>14. knowsSentInv' @@ -1441,7 +1489,7 @@ THEOREM Invariance == Spec => []Inv <4>3. bmsgsFinite' BY <4>1, FiniteMsgsLemma, Zenon DEF Inv, bmsgsFinite <4>4. 1bInv1' - BY <4>1, Isa DEF Inv, 1bInv1 + BY <4>1 DEF Inv, 1bInv1 <4>5. 1bInv2' BY <4>1 DEF Inv, 1bInv2 <4>6. maxBalInv' @@ -1544,7 +1592,7 @@ THEOREM Invariance == Spec => []Inv <4>3. TypeOK' BY <3>2, <4>1 DEF Phase1c, Inv, TypeOK, BMessage, 1cMessage <4>4. bmsgsFinite' - BY <4>1 DEF Inv, bmsgsFinite, 1bOr2bMsgs + BY <4>1, Zenon DEF Inv, bmsgsFinite, 1bOr2bMsgs <4>5. 1bInv1' BY <3>2, <4>2, Zenon DEF Phase1c, Inv, 1bInv1 <4>6. 1bInv2' @@ -1600,7 +1648,7 @@ THEOREM Invariance == Spec => []Inv PROVE Inv' <3> USE UNCHANGED vars DEF Inv, vars <3> msgs = msgs' - BY DEF msgs, msgsOfType, 1bmsgs, 1bRestrict, acceptorMsgsOfType, 1cmsgs, + BY Isa DEF msgs, msgsOfType, 1bmsgs, 1bRestrict, acceptorMsgsOfType, 1cmsgs, KnowsSafeAt, 2amsgs <3> QED BY DEF TypeOK, bmsgsFinite, 1bOr2bMsgs, 1bInv1, 1bInv2, @@ -1624,19 +1672,25 @@ THEOREM Spec => P!Spec <2>1. MaxBallot({}) = -1 BY MaxBallotProp, FS_EmptySet <2>2. P!Init!1 /\ P!Init!2 /\ P!Init!3 - BY <2>1 DEF Init, PmaxBal, 1bOr2bMsgs, None, P!None + BY <2>1, Zenon DEF Init, PmaxBal, 1bOr2bMsgs, None, P!None <2>3. msgs = {} - BY BQA DEF Init, msgsOfType, acceptorMsgsOfType, 1bmsgs, 1cmsgs, 2amsgs, Quorum, msgs + \* BY BQA DEF Init, msgsOfType, acceptorMsgsOfType, 1bmsgs, 1cmsgs, 2amsgs, Quorum, msgs + <3>1. bmsgs = {} + BY DEF Init + <3>2. \A Q \in Quorum : Q # {} + BY BQA DEF Quorum + <3>. QED + BY <3>1, <3>2 DEF msgsOfType, acceptorMsgsOfType, 1bmsgs, 1cmsgs, 2amsgs, msgs <2>4. QED BY <2>2, <2>3 DEF P!Init <1>2. Inv /\ Inv' /\ [Next]_vars => [P!Next]_P!vars - <2> InvP == Inv' + <2> DEFINE InvP == Inv' <2> SUFFICES ASSUME Inv, InvP, Next PROVE P!TLANext \/ P!vars' = P!vars <3> UNCHANGED vars => UNCHANGED P!vars - BY DEF vars, P!vars, PmaxBal, 1bOr2bMsgs, msgs, msgsOfType, acceptorMsgsOfType, - 1bmsgs, 2amsgs, 1cmsgs, KnowsSafeAt + BY Isa DEF vars, P!vars, PmaxBal, 1bOr2bMsgs, msgs, msgsOfType, acceptorMsgsOfType, + 1bmsgs, 2amsgs, 1cmsgs, KnowsSafeAt <3> QED BY PNextDef DEF Inv, P!ProcSet, P!Init, Ballot, P!Ballot <2> HIDE DEF InvP @@ -1670,7 +1724,7 @@ THEOREM Spec => P!Spec BY DEF PmaxBal, 1bOr2bMsgs <4> HIDE DEF mA <4>4. S(self)' = S(self) \cup {b} - BY <4>2, Isa + BY <4>2 <4>5. MaxBallot(S(self) \cup {b}) = b <5> DEFINE SS == S(self) \cup {b} <5>1. IsFiniteSet(S(self)) @@ -1683,7 +1737,7 @@ THEOREM Spec => P!Spec <5>3. S(self) \subseteq Ballot \cup {-1} BY BMessageLemma DEF mA, Inv, TypeOK, 1bMessage, 2bMessage <5>4. \A x \in SS : b >= x - BY <3>4, <4>3, <5>1, <5>3, MaxBallotProp, Z3T(10) DEF Ballot + BY <3>4, <4>3, <5>1, <5>3, MaxBallotProp DEF Ballot <5>5. QED BY <5>2, <5>3, <5>4, MaxBallotLemma1 <4>6. \A a \in Acceptor : a # self => S(a)' = S(a) @@ -1717,7 +1771,7 @@ THEOREM Spec => P!Spec <4>2. P!sentMsgs("2a", b) = {} <5>1. SUFFICES ASSUME NEW m \in P!sentMsgs("2a", b) PROVE m = [type |-> "2a", bal |-> b, val |-> v] - BY <3>3, <4>1 DEF P!sentMsgs + BY <3>3, <4>1, Zenon DEF P!sentMsgs <5>2. /\ m \in 2amsgs /\ m.type = "2a" /\ m.bal = b @@ -1735,7 +1789,7 @@ THEOREM Spec => P!Spec /\ m2av.acc = a /\ m2av.bal = b /\ m2av.val = v - BY <4>1, MsgsTypeLemmaPrime, Isa DEF 2amsgs + BY <4>1, MsgsTypeLemmaPrime DEF 2amsgs <5>5. PICK a \in Q \cap Q2 : a \in Acceptor BY QuorumTheorem <5>6. PICK mav \in acceptorMsgsOfType("2av") : @@ -1880,7 +1934,7 @@ THEOREM Spec => P!Spec BY <4>4 <5>2. \A a \in Q(BQ) : \E m \in SQ(BQ) : /\ m.acc = a /\ m.mbal = -1 - BY <5>1, Isa DEF 1bRestrict + BY <5>1 DEF 1bRestrict <5>3. \A m \in SQ(BQ) : m.mbal = -1 BY <4>2, <5>2 DEF InvP, Inv, knowsSentInv, msgsOfType, 1bRestrict, 1bInv2 @@ -1964,7 +2018,7 @@ THEOREM Spec => P!Spec <5>7. P!ShowsSafeAt(Q(BQ), b, v)!1!2!2!(m1c) BY <5>5, <5>6 <5>. QED - BY <5>4, <5>7, Isa DEF P!ShowsSafeAt, Quorum + BY <5>4, <5>7 DEF P!ShowsSafeAt, Quorum <4>6. QED BY <3>1, <4>1, <4>4, <4>5 DEF KnowsSafeAt <3>6. QED @@ -1976,7 +2030,7 @@ THEOREM Spec => P!Spec <3>1. msgs' = msgs \cup {[type |-> "1a", bal |-> self]} BY <2>7, MsgsLemma DEF Inv <3>2. UNCHANGED << PmaxBal, maxVBal, maxVVal >> - BY <2>7, Isa DEF Phase1a, PmaxBal, 1bOr2bMsgs + BY <2>7 DEF Phase1a, PmaxBal, 1bOr2bMsgs <3>. QED BY <3>1, <3>2 DEF P!Phase1a, P!TLANext, Ballot, P!Ballot <2>8. ASSUME NEW self \in Ballot, @@ -2118,10 +2172,3 @@ THEOREM chosen \subseteq P!chosen BY Isa DEF chosen, P!chosen, Quorum, Ballot, P!Ballot ============================================================================== -\* Modification History -\* Last modified Sat Jul 25 17:34:50 PDT 2020 by lamport -\* Last modified Fri Jul 24 17:51:34 CEST 2020 by merz -\* Last modified Wed Apr 15 15:16:26 CEST 2020 by doligez -\* Last modified Mon Aug 18 14:57:27 CEST 2014 by tomer -\* Last modified Mon Mar 04 17:24:05 CET 2013 by doligez -\* Last modified Wed Dec 01 11:35:29 PST 2010 by lamport diff --git a/specifications/byzpaxos/Consensus.tla b/specifications/byzpaxos/Consensus.tla index 81444cbb..304f3642 100644 --- a/specifications/byzpaxos/Consensus.tla +++ b/specifications/byzpaxos/Consensus.tla @@ -147,7 +147,7 @@ LEMMA InductiveInvariance == OBVIOUS <1>1. CASE Next \* In the following BY proof, <1>1 denotes the case assumption Next - BY <1>1, FS_EmptySet, FS_Singleton DEF Inv, TypeOK, Next + BY <1>1, FS_Singleton DEF Inv, TypeOK, Next <1>2. CASE vars' = vars BY <1>2 DEF Inv, TypeOK, vars <1>3. QED @@ -178,42 +178,24 @@ Success == <>(chosen # {}) ASSUME ValueNonempty == Value # {} (***************************************************************************) -(* Since fairness is defined in terms of the ENABLED operator, we must *) -(* characterize states at which an action is enabled. It is usually a good *) -(* idea to prove a separate lemma for this. *) +(* Proving liveness requires reasoning about fairness assumptions, which *) +(* are defined in terms of enabledness of actions. It is usually a good *) +(* idea to prove a lemma that reduces ENABLED to a simple state predicate. *) (***************************************************************************) -LEMMA EnabledNext == - (ENABLED <>_vars) <=> (chosen = {}) -BY ValueNonempty, ExpandENABLED DEF Next, vars +LEMMA EnabledDef == (ENABLED <>_vars) <=> (chosen = {}) +BY ValueNonempty, ExpandENABLED DEF Next, vars -(***************************************************************************) -(* Here is our proof that Livespec implies Success. The overall approach *) -(* to the proof follows the rule WF1 discussed in *) -(* *) -(* `. AUTHOR = "Leslie Lamport", *) -(* TITLE = "The Temporal Logic of Actions", *) -(* JOURNAL = toplas, *) -(* volume = 16, *) -(* number = 3, *) -(* YEAR = 1994, *) -(* month = may, *) -(* PAGES = "872--923" .' *) -(* *) -(* In the actual proof, use of this rule is subsumed by appealing to the *) -(* PTL decision procedure for propositional temporal logic. When reasoning *) -(* about the liveness of more complex specifications, an additional *) -(* invariant would typically be required. *) -(***************************************************************************) -THEOREM LiveSpec => Success -<1>1. [][Next]_vars /\ WF_vars(Next) => [](Init => Success) - <2>1. Init' \/ (chosen # {})' - BY DEF Init - <2>2. Init /\ <>_vars => (chosen # {})' - BY DEF Init, Next, vars - <2>3. Init => ENABLED <>_vars - BY EnabledNext DEF Init - <2>. QED BY <2>1, <2>2, <2>3, PTL DEF Success -<1>2. QED BY <1>1, PTL DEF LiveSpec, Spec, Success +THEOREM Liveness == LiveSpec => Success +<1>. DEFINE P == chosen = {} + Q == chosen # {} +<1>1. P /\ [Next]_vars => P' \/ Q' + OBVIOUS +<1>2. P /\ <>_vars => Q' + BY DEF Next +<1>3. P => ENABLED <>_vars + BY EnabledDef +<1>. QED + BY <1>1, <1>2, <1>3, PTL DEF LiveSpec, Spec, Init, Success ----------------------------------------------------------------------------- (***************************************************************************) @@ -222,16 +204,6 @@ THEOREM LiveSpec => Success (***************************************************************************) THEOREM LiveSpecEquals == LiveSpec <=> Spec /\ ([]<><>_vars \/ []<>(chosen # {})) -<1>1. (chosen # {}) <=> ~(chosen = {}) - OBVIOUS -<1>2. ([]<>~ENABLED <>_vars) <=> []<>(chosen # {}) - BY <1>1, EnabledNext, PTL -<1>4. QED - BY <1>2, PTL DEF LiveSpec +BY (chosen # {}) <=> ~(chosen = {}), EnabledDef, PTL DEF LiveSpec, Spec + ============================================================================= -\* Modification History -\* Last modified Mon May 11 18:36:27 CEST 2020 by merz -\* Last modified Mon Aug 18 15:00:45 CEST 2014 by tomer -\* Last modified Mon Aug 18 14:58:57 CEST 2014 by tomer -\* Last modified Tue Feb 14 13:35:49 PST 2012 by lamport -\* Last modified Mon Feb 07 14:46:59 PST 2011 by lamport diff --git a/specifications/byzpaxos/PConProof.tla b/specifications/byzpaxos/PConProof.tla index 1682138c..be07358e 100644 --- a/specifications/byzpaxos/PConProof.tla +++ b/specifications/byzpaxos/PConProof.tla @@ -537,7 +537,6 @@ THEOREM Spec => [](chosen = V!chosen) (***************************************************************************) ============================================================================= \* Modification History -\* Last modified Fri May 22 09:20:18 CEST 2020 by merz \* Last modified Fri Jul 15 11:31:15 PDT 2011 by lamport ----------------------------------------------------------------------------- diff --git a/specifications/byzpaxos/VoteProof.tla b/specifications/byzpaxos/VoteProof.tla index c7108327..76a67c5b 100644 --- a/specifications/byzpaxos/VoteProof.tla +++ b/specifications/byzpaxos/VoteProof.tla @@ -24,7 +24,7 @@ CONSTANT Value, \* As in module Consensus, the set of choosable values. (***************************************************************************) ASSUME QA == /\ \A Q \in Quorum : Q \subseteq Acceptor /\ \A Q1, Q2 \in Quorum : Q1 \cap Q2 # {} - + THEOREM QuorumNonEmpty == \A Q \in Quorum : Q # {} PROOF BY QA ----------------------------------------------------------------------------- @@ -298,7 +298,7 @@ THEOREM SafeAtProp == /\ \A d \in (c+1)..(bb-1), a \in Q : DidNotVoteIn(a, d) SA[bb \in Ballot] == Def(SA, bb) <1>2. \A b : SafeAt(b, v) = SA[b] - BY DEF SafeAt + BY Zenon DEF SafeAt <1>3. ASSUME NEW n \in Nat, NEW g, NEW h, \A i \in 0..(n-1) : g[i] = h[i] PROVE Def(g, n) = Def(h, n) @@ -400,7 +400,9 @@ LEMMA SafeLemma == <3>5. QED BY <3>3, <3>4 <2>8. CASE c < cc - BY <2>8, <1>2, <2>5 + <3>. cc \in 0 .. b /\ c \in 0 .. cc-1 + BY <2>8 + <3>. QED BY <1>2, <2>5 <2>9. QED BY <2>6, <2>7, <2>8 <1>3. \A b \in Ballot : P(b) @@ -491,7 +493,9 @@ LEMMA VT0 == /\ TypeOK <3> PICK aa \in QQ \cap Q : TRUE BY QA <3>4. c \leq d - BY <3>1, <3>2, <3>3 DEF DidNotVoteIn + <4>. SUFFICES ASSUME c \in d+1 .. b-1 PROVE FALSE + BY <3>1 + <4>. QED BY <3>2, <3>3 DEF DidNotVoteIn <3>5. CASE c = d BY <3>2, <3>3, <3>4, <3>5 <3>6. CASE d > c @@ -775,6 +779,8 @@ THEOREM InductiveInvariance == VInv /\ [Next]_vars => VInv' PROVE /\ SafeAt(cc, w)' /\ \A ax \in Q : \A z \in Value : VotedFor(ax, cc, z)' => (z = w) + <6>. cc \in 0 .. e-1 + BY <5>3 <6>1. /\ SafeAt(cc, w) /\ \A ax \in Q : \A z \in Value : VotedFor(ax, cc, z) => (z = w) @@ -786,7 +792,7 @@ THEOREM InductiveInvariance == VInv /\ [Next]_vars => VInv' <7>1. CASE VotedFor(ax, cc, z) BY <6>1, <7>1 <7>2. CASE ~ VotedFor(ax, cc, z) - BY <7>2, <6>3, <5>1, <5>3 + BY <7>2, <6>3, <5>1 <7>3. QED BY <7>1, <7>2 <6>4. QED @@ -951,7 +957,7 @@ THEOREM VT3 == Spec => C!Spec BY <2>1, NextDef DEF VInv <2>3. ASSUME IncreaseMaxBal(self, b) PROVE C!vars' = C!vars - BY <2>3 DEF IncreaseMaxBal, C!vars, chosen, ChosenIn, VotedFor + BY <2>3, Zenon DEF IncreaseMaxBal, C!vars, chosen, ChosenIn, VotedFor <2>4. ASSUME NEW v \in Value, VoteFor(self, b, v) PROVE [C!Next]_C!vars @@ -985,7 +991,7 @@ THEOREM VT3 == Spec => C!Spec <4>6. QED BY <4>4, <4>5 <3>. QED - BY <3>3, <3>1, <3>2 DEF C!Next, C!vars + BY <3>3, <3>1, <3>2, Zenon DEF C!Next, C!vars <2>5. QED BY <2>2, <2>3, <2>4 DEF BallotAction <1>3. QED @@ -1057,7 +1063,11 @@ THEOREM VT4 == TypeOK /\ VInv2 /\ VInv3 => /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) BY <1>1, <1>2, SafeAtProp <1>5. CASE \A a \in Q, c \in 0..(b-1) : DidNotVoteIn(a, c) - BY <1>5, ValueNonempty + <2>. PICK v \in Value : TRUE + BY ValueNonempty + <2>. WITNESS v \in Value + <2>. WITNESS -1 \in -1 .. (b-1) + <2>. QED BY <1>5 <1>6. CASE \E a \in Q, c \in 0..(b-1) : ~DidNotVoteIn(a, c) <2>1. PICK c \in 0..(b-1) : /\ \E a \in Q : ~DidNotVoteIn(a, c) @@ -1070,8 +1080,12 @@ THEOREM VT4 == TypeOK /\ VInv2 /\ VInv3 => BY FS_Interval, FS_Subset, 0 \in Int, b-1 \in Int, Zenon <4>3. QED BY <3>1, <4>2, FiniteSetHasMax + <3>3. /\ c \in 0 .. (b-1) + /\ \E a \in Q : ~DidNotVoteIn(a,c) + /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) + BY <3>2 <3>. QED - BY <3>2 DEF Ballot + BY <3>3 <2>4. PICK a0 \in Q, v \in Value : VotedFor(a0, c, v) BY <2>1 DEF DidNotVoteIn <2>5. \A a \in Q : \A w \in Value : @@ -1241,10 +1255,40 @@ THEOREM Liveness == LiveSpec => C!LiveSpec <1>5. Spec /\ LiveAssumption!(Q, b) => <>[](\A self \in Q : maxBal[self] = b) + <2>. DEFINE MB(s) == maxBal[s] = b + <2>0. (\A self \in Q : <>[]MB(self)) => <>[](\A self \in Q : MB(self)) + \* BY <1>a, EventuallyAlwaysForall \* fails, even when hiding the definition of MB + <3>. HIDE DEF MB + <3>. DEFINE A(x) == <>[]MB(x) + L(T) == \A self \in T : A(self) \* NB: changing the names of the bound vars makes the QED step fail! + R(T) == \A self \in T : MB(self) + I(T) == L(T) => <>[]R(T) + <3>1. I({}) + <4>1. R({}) OBVIOUS + <4>. QED BY <4>1, PTL + <3>2. ASSUME NEW T, NEW x + PROVE I(T) => I(T \cup {x}) + <4>1. L(T \cup {x}) => A(x) + <5>. HIDE DEF A + <5>. QED OBVIOUS + <4>2. L(T \cup {x}) /\ I(T) => <>[]R(T) + OBVIOUS + <4>3. <>[]R(T) /\ A(x) => <>[](R(T) /\ MB(x)) + BY PTL + <4>4. R(T) /\ MB(x) => R(T \cup {x}) + OBVIOUS + <4>5. <>[](R(T) /\ MB(x)) => <>[]R(T \cup {x}) + BY <4>4, PTL + <4>. QED BY <4>1, <4>2, <4>3, <4>5 + <3>. HIDE DEF I + <3>3. \A T : IsFiniteSet(T) => I(T) + BY <3>1, <3>2, FS_Induction, IsaM("blast") + <3>4. I(Q) + BY <1>a, <3>3 + <3>. QED BY <3>4 DEF I <2>1. SUFFICES ASSUME NEW self \in Q - PROVE Spec /\ LiveAssumption!(Q, b) => <>[](maxBal[self] = b) -\* BY <1>a, EventuallyAlwaysForall \* doesn't check, even when introducing definitions - PROOF OMITTED + PROVE Spec /\ LiveAssumption!(Q, b) => <>[]MB(self) + BY <2>0, Isa <2> DEFINE P == LInv1 /\ ~(maxBal[self] = b) QQ == LInv1 /\ (maxBal[self] = b) A == BallotAction(self, b) @@ -1264,31 +1308,14 @@ THEOREM Liveness == LiveSpec => C!LiveSpec <4>5. QED BY <4>1, <4>3, <4>4 DEF BallotAction <3>3. P => ENABLED <>_vars - <4>1. (ENABLED <>_vars) <=> - \E votesp, maxBalp: - /\ \/ /\ b > maxBal[self] - /\ maxBalp = [maxBal EXCEPT ![self] = b] - /\ votesp = votes - \/ \E v \in Value : - /\ maxBal[self] \leq b - /\ DidNotVoteIn(self, b) - /\ \A p \in Acceptor \ {self} : - \A w \in Value : VotedFor(p, b, w) => (w = v) - /\ SafeAt(b, v) - /\ votesp = [votes EXCEPT ![self] = votes[self] - \cup {<>}] - /\ maxBalp = [maxBal EXCEPT ![self] = b] - /\ <> # <> -\* BY DEF BallotAction, IncreaseMaxBal, VoteFor, vars, SafeAt, -\* DidNotVoteIn, VotedFor - PROOF OMITTED <4>. SUFFICES ASSUME P PROVE \E votesp, maxBalp: /\ b > maxBal[self] /\ maxBalp = [maxBal EXCEPT ![self] = b] /\ votesp = votes /\ <> # <> - BY <4>1 + BY ExpandENABLED + DEF BallotAction, IncreaseMaxBal, VoteFor, vars, SafeAt, DidNotVoteIn, VotedFor <4> WITNESS votes, [maxBal EXCEPT ![self] = b] <4>. QED BY QA DEF VInv, TypeOK, Ballot <3>. QED BY <3>1, <3>2, <3>3, PTL @@ -1309,7 +1336,7 @@ THEOREM Liveness == LiveSpec => C!LiveSpec <2>. QED BY <2>2, <2>3, <2>4, <2>5, <2>6, <1>2, PTL -<1> DEFINE LNInv2 == \A a \in Q : maxBal[a] = b +<1> DEFINE LNInv2 == \A self \in Q : maxBal[self] = b \* again, the bound var must be called self! LInv2 == VInv /\ LNInv2 <1>6. LInv2 /\ [LNext]_vars => LInv2' @@ -1319,10 +1346,9 @@ THEOREM Liveness == LiveSpec => C!LiveSpec <2> DEFINE Voted(a) == \E v \in Value : VotedFor(a, b, v) <2>1. Spec /\ LiveAssumption!(Q, b) => <>[]LInv2 <3>1. Spec /\ LiveAssumption!(Q,b) => <>[]LNInv2 -\* BY <1>5 \* doesn't check - PROOF OMITTED + BY <1>5, Isa <3>. QED BY <3>1, VT2, PTL - <2>2. LInv2 /\ (\A a \in Q : Voted(a)) => (chosen # {}) + <2>2. LInv2 /\ (\A self \in Q : Voted(self)) => (chosen # {}) <3>1. SUFFICES ASSUME LInv2, \A a \in Q : Voted(a) PROVE chosen # {} @@ -1337,11 +1363,10 @@ THEOREM Liveness == LiveSpec => C!LiveSpec BY <4>3 <3>3. QED BY <3>2 DEF chosen, ChosenIn - <2>3. Spec /\ LiveAssumption!(Q, b) => (\A a \in Q : <>[]Voted(a)) + <2>3. Spec /\ LiveAssumption!(Q, b) => (\A self \in Q : <>[]Voted(self)) <3>1. SUFFICES ASSUME NEW self \in Q PROVE Spec /\ LiveAssumption!(Q, b) => <>[]Voted(self) -\* OBVIOUS \* doesn't check?! - PROOF OMITTED + BY Isa <3>2. Spec /\ LiveAssumption!(Q, b) => <>Voted(self) <4>2. [][LNext]_vars /\ WF_vars(BallotAction(self, b)) => ((LInv2 /\ ~Voted(self)) ~> LInv2 /\ Voted(self)) @@ -1363,40 +1388,21 @@ THEOREM Liveness == LiveSpec => C!LiveSpec <6>4. QED BY <6>1, <6>2, <6>3 DEF BallotAction <5>3. P => ENABLED <>_vars - <6>1. SUFFICES ASSUME P - PROVE ENABLED <>_vars - OBVIOUS - <6>2. (ENABLED <>_vars) <=> - \E votesp, maxBalp : - /\ \/ /\ b > maxBal[self] - /\ maxBalp = [maxBal EXCEPT ![self] = b] - /\ votesp = votes - \/ \E v \in Value : - /\ maxBal[self] \leq b - /\ DidNotVoteIn(self, b) - /\ \A p \in Acceptor \ {self} : - \A w \in Value : VotedFor(p, b, w) => (w = v) - /\ SafeAt(b, v) - /\ votesp = [votes EXCEPT ![self] = votes[self] + <6>1. SUFFICES + ASSUME P + PROVE \E maxBalp, votesp: + /\ \E v \in Value : + /\ maxBal[self] \leq b + /\ DidNotVoteIn(self, b) + /\ \A p \in Acceptor \ {self} : + \A w \in Value : VotedFor(p, b, w) => (w = v) + /\ SafeAt(b, v) + /\ votesp = [votes EXCEPT ![self] = votes[self] \cup {<>}] - /\ maxBalp = [maxBal EXCEPT ![self] = b] - /\ <> # <> -\* BY DEF BallotAction, IncreaseMaxBal, VoteFor, vars, SafeAt, -\* DidNotVoteIn, VotedFor - PROOF OMITTED - <6> SUFFICES - \E votesp, maxBalp: - /\ \E v \in Value : - /\ maxBal[self] \leq b - /\ DidNotVoteIn(self, b) - /\ \A p \in Acceptor \ {self} : - \A w \in Value : VotedFor(p, b, w) => (w = v) - /\ SafeAt(b, v) - /\ votesp = [votes EXCEPT ![self] = votes[self] - \cup {<>}] - /\ maxBalp = [maxBal EXCEPT ![self] = b] - /\ <> # <> - BY <6>2 + /\ maxBalp = [maxBal EXCEPT ![self] = b] + /\ <> # <> + BY ExpandENABLED + DEF BallotAction, IncreaseMaxBal, VoteFor, vars <6> DEFINE someVoted == \E p \in Acceptor \ {self} : \E w \in Value : VotedFor(p, b, w) vp == CHOOSE p \in Acceptor \ {self} : @@ -1412,13 +1418,14 @@ THEOREM Liveness == LiveSpec => C!LiveSpec BY <6>1, <6>3, VT4 DEF VInv, VInv2, Ballot <6> DEFINE votesp == [votes EXCEPT ![self] = votes[self] \cup {<>}] maxBalp == [maxBal EXCEPT ![self] = b] - <6> WITNESS votesp, maxBalp + <6> WITNESS maxBalp, votesp <6> SUFFICES /\ maxBal[self] \leq b /\ DidNotVoteIn(self, b) /\ \A p \in Acceptor \ {self} : \A w \in Value : VotedFor(p, b, w) => (w = v) /\ votesp # votes - BY <6>4, Zenon + <7>. HIDE DEF v + <7>. QED BY <6>4 <6>5. maxBal[self] \leq b BY <6>1 DEF Ballot <6>6. DidNotVoteIn(self, b) @@ -1473,9 +1480,35 @@ THEOREM Liveness == LiveSpec => C!LiveSpec BY <4>1, VT2, PTL DEF Spec <3>4. QED BY <3>2, <3>3, PTL - <2>4. (\A a \in Q : <>[]Voted(a)) => <>[](\A a \in Q : Voted(a)) -\* BY <1>a, EventuallyAlwaysForall \* doesn't check - PROOF OMITTED + <2>4. (\A self \in Q : <>[]Voted(self)) => <>[](\A self \in Q : Voted(self)) + \* again, we need to redo the proof instead of using lemma EventuallyAlwaysForall + <3>. DEFINE A(x) == <>[]Voted(x) + L(T) == \A self \in T : A(self) + R(T) == \A self \in T : Voted(self) + I(T) == L(T) => <>[]R(T) + <3>1. I({}) + <4>1. R({}) OBVIOUS + <4>. QED BY <4>1, PTL + <3>2. ASSUME NEW T, NEW x + PROVE I(T) => I(T \cup {x}) + <4>1. L(T \cup {x}) => A(x) + <5>. HIDE DEF A + <5>. QED OBVIOUS + <4>2. L(T \cup {x}) /\ I(T) => <>[]R(T) + OBVIOUS + <4>3. <>[]R(T) /\ A(x) => <>[](R(T) /\ Voted(x)) + BY PTL + <4>4. R(T) /\ Voted(x) => R(T \cup {x}) + OBVIOUS + <4>5. <>[](R(T) /\ Voted(x)) => <>[]R(T \cup {x}) + BY <4>4, PTL + <4>. QED BY <4>1, <4>2, <4>3, <4>5 + <3>. HIDE DEF I + <3>3. \A T : IsFiniteSet(T) => I(T) + BY <3>1, <3>2, FS_Induction, IsaM("blast") + <3>4. I(Q) + BY <1>a, <3>3 + <3>. QED BY <3>4 DEF I <2>. QED BY <2>1, VT2, <2>2, <2>3, <2>4, PTL @@ -1488,9 +1521,3 @@ THEOREM Liveness == LiveSpec => C!LiveSpec BY <2>2, <1>1, Isa =============================================================================== -\* Modification History -\* Last modified Fri Jul 24 18:20:31 CEST 2020 by merz -\* Last modified Wed Apr 29 12:24:23 CEST 2020 by merz -\* Last modified Mon May 28 08:53:38 PDT 2012 by lamport - - diff --git a/specifications/ewd840/EWD840.cfg b/specifications/ewd840/EWD840.cfg index 726b8a66..d970500b 100644 --- a/specifications/ewd840/EWD840.cfg +++ b/specifications/ewd840/EWD840.cfg @@ -1,8 +1,14 @@ CONSTANTS N = 3 -INIT Init -NEXT Next -INVARIANT Inv -CHECK_DEADLOCK FALSE +SPECIFICATION Spec +CHECK_DEADLOCK FALSE +INVARIANTS + TypeOK + TerminationDetection + Inv + +PROPERTIES + Liveness + TDSpec diff --git a/specifications/ewd840/EWD840.tla b/specifications/ewd840/EWD840.tla index 018d7ec3..36618d33 100644 --- a/specifications/ewd840/EWD840.tla +++ b/specifications/ewd840/EWD840.tla @@ -114,18 +114,18 @@ NeverChangeColor == [][ UNCHANGED color ]_vars (* Main safety property: if there is a white token at node 0 then every *) (* node is inactive. *) (***************************************************************************) +terminated == \A i \in Node : ~ active[i] + terminationDetected == /\ tpos = 0 /\ tcolor = "white" /\ color[0] = "white" /\ ~ active[0] -TerminationDetection == - terminationDetected => \A i \in Node : ~ active[i] +TerminationDetection == terminationDetected => terminated (***************************************************************************) (* Liveness property: termination is eventually detected. *) (***************************************************************************) -Liveness == - (\A i \in Node : ~ active[i]) ~> terminationDetected +Liveness == terminated ~> terminationDetected (***************************************************************************) (* The following property asserts that when every process always *) @@ -170,9 +170,7 @@ CheckInductiveSpec == TypeOK /\ Inv /\ [][Next]_vars (* instantiated by the symbols of the same name in the present module. *) (***************************************************************************) TD == INSTANCE SyncTerminationDetection - -THEOREM Spec => TD!Spec +TDSpec == TD!Spec ============================================================================= \* Modification History -\* Last modified Thu Jan 21 16:09:40 CET 2021 by merz \* Created Mon Sep 09 11:33:10 CEST 2013 by merz diff --git a/specifications/ewd840/EWD840_proof.tla b/specifications/ewd840/EWD840_proof.tla index e8b5257c..1cb8ef4f 100644 --- a/specifications/ewd840/EWD840_proof.tla +++ b/specifications/ewd840/EWD840_proof.tla @@ -4,7 +4,8 @@ (* termination detection algorithm. Checking the proof requires TLAPS to *) (* be installed. *) (***************************************************************************) -EXTENDS EWD840, TLAPS +EXTENDS EWD840, NaturalsInduction, TLAPS +USE NAssumption (***************************************************************************) (* The algorithm is type-correct: TypeOK is an inductive invariant. *) @@ -17,7 +18,7 @@ LEMMA TypeCorrect == Spec => []TypeOK [Next]_vars PROVE TypeOK' OBVIOUS - <2>. USE NAssumption DEF TypeOK, Node, Color + <2>. USE DEF TypeOK, Node, Color <2>1. CASE InitiateProbe BY <2>1 DEF InitiateProbe <2>2. ASSUME NEW i \in Node \ {0}, @@ -42,21 +43,23 @@ LEMMA TypeCorrect == Spec => []TypeOK (* Prove the main soundness property of the algorithm by (1) proving that *) (* Inv is an inductive invariant and (2) that it implies correctness. *) (***************************************************************************) -THEOREM Safety == Spec => []TerminationDetection +THEOREM Invariant == Spec => []Inv <1>1. Init => Inv - BY NAssumption DEF Init, Inv, Node + BY DEF Init, Inv, Node <1>2. TypeOK /\ Inv /\ [Next]_vars => Inv' - BY NAssumption - DEF TypeOK, Inv, Next, vars, Node, Color, + BY DEF TypeOK, Inv, Next, vars, Node, Color, System, Environment, InitiateProbe, PassToken, SendMsg, Deactivate -<1>3. Inv => TerminationDetection - BY NAssumption DEF Inv, TerminationDetection, terminationDetected, Node <1>. QED - BY <1>1, <1>2, <1>3, TypeCorrect, PTL DEF Spec + BY <1>1, <1>2, TypeCorrect, PTL DEF Spec +THEOREM Safety == Spec => []TerminationDetection +<1>. Inv => TerminationDetection + BY DEF Inv, TerminationDetection, terminationDetected, terminated, Node +<1>. QED + BY Invariant, TypeCorrect, PTL (***************************************************************************) -(* Step <1>3 of the above proof shows that Dijkstra's invariant implies *) +(* The above proof shows that Dijkstra's invariant implies the predicate *) (* TerminationDetection. If you find that one-line proof too obscure, here *) (* is a more detailed, hierarchical proof of that same implication. *) (***************************************************************************) @@ -65,7 +68,7 @@ LEMMA Inv => TerminationDetection color[0] = "white", ~ active[0], Inv PROVE \A i \in Node : ~ active[i] - BY <1>1 DEF TerminationDetection, terminationDetected + BY <1>1 DEF TerminationDetection, terminationDetected, terminated <1>2. ~ Inv!P2 BY tcolor = "white" DEF Inv <1>3. ~ Inv!P1 BY <1>1 DEF Inv <1>. QED @@ -74,11 +77,240 @@ LEMMA Inv => TerminationDetection <2>3. CASE i = 0 BY <2>1, <1>1, <2>3 <2>4. CASE i \in 1 .. N-1 <3>1. tpos < i BY tpos=0, <2>4, NAssumption - <3>2. i < N BY NAssumption, <2>4 + <3>2. i < N BY <2>4 <3>. QED BY <3>1, <3>2, <2>1 <2>. QED BY <2>3, <2>4 DEF Node +----------------------------------------------------------------------------- +(***************************************************************************) +(* Liveness of the algorithm. *) +(***************************************************************************) + +(***************************************************************************) +(* The proof of liveness relies on the fairness condition assumed for the *) +(* algorithm, which in turn is defined in terms of enabledness. It is *) +(* usually a good idea to reduce that enabledness condition to a standard *) +(* state predicate, and the following lemma does just that. *) +(***************************************************************************) +LEMMA EnabledSystem == + ASSUME TypeOK + PROVE (ENABLED <>_vars) <=> + \/ tpos = 0 /\ (tcolor = "black" \/ color[0] = "black") + \/ tpos \in Node \ {0} /\ (~active[tpos] \/ tcolor = "black" \/ color[tpos] = "black") +<1>1. <>_vars <=> System + <2>1. InitiateProbe => <>_vars + BY DEF TypeOK, InitiateProbe, vars + <2>2. ASSUME NEW i \in Node \ {0} + PROVE PassToken(i) => <>_vars + BY <2>2 DEF Node, PassToken, vars + <2>. QED BY <2>1, <2>2 DEF System +<1>2. (ENABLED <>_vars) <=> (ENABLED System) + BY <1>1, ENABLEDaxioms +<1>. QED BY <1>2, ExpandENABLED DEF System, InitiateProbe, PassToken, vars + +(***************************************************************************) +(* We need to prove that once the system has globally terminated, the *) +(* condition for detecting termination must eventually become true. As is *) +(* often the case with proving liveness, it is convenient to carry out *) +(* this proof by contradiction, so we also assume that termination is *) +(* never detected. The system may require three rounds: *) +(* 1. The first round brings the token back to node 0. *) +(* 2. The second round cleans all nodes. *) +(* 3. The third round brings back a clean token. *) +(***************************************************************************) + +(***************************************************************************) +(* Specification used for the liveness proof: we ignore the initial state *) +(* predicate but include the invariants of the algorithm. We also assume, *) +(* for the sake of contradiction, that termination is never detected. *) +(***************************************************************************) +TSpec == + /\ []TypeOK + /\ []Inv + /\ []~terminationDetected + /\ [][Next]_vars + /\ WF_vars(System) + +allWhite == \A n \in Node : color[n] = "white" + +(***************************************************************************) +(* The following three lemmas represent the idea of the system needing up *) +(* to three complete rounds of the token for detecting termination. Their *) +(* proofs rely on induction on the initial position of the token, and they *) +(* are essentially obtained by copy-and-paste. *) +(***************************************************************************) +LEMMA Round1 == + TSpec => (terminated ~> (terminated /\ tpos = 0)) +<1>. DEFINE P(n) == terminated /\ n \in Node /\ tpos = n + Q == P(0) + R(n) == TSpec => [](P(n) => <>Q) +<1>1. \A n \in Nat : R(n) + <2>1. R(0) + BY PTL + <2>2. ASSUME NEW n \in Nat PROVE R(n) => R(n+1) + <3>. DEFINE Pn == P(n) Pn1 == P(n+1) + <3>. USE DEF TypeOK, Node, Color, terminated + <3>1. TypeOK /\ Pn1 /\ [Next]_vars => Pn1' \/ Pn' + BY DEF Next, vars, System, Environment, InitiateProbe, PassToken, Deactivate, SendMsg + <3>2. TypeOK /\ Pn1 /\ <>_vars => Pn' + BY DEF System, vars, InitiateProbe, PassToken + <3>3. TypeOK /\ Pn1 => ENABLED <>_vars + BY EnabledSystem + <3>. QED BY <3>1, <3>2, <3>3, PTL DEF TSpec + <2>. HIDE DEF R + <2>. QED BY <2>1, <2>2, NatInduction, Isa +<1>2. TSpec => []((\E n \in Nat : P(n)) => <>Q) + <2>. HIDE DEF P,Q + <2>1. TSpec => [](\A n \in Nat : P(n) => <>Q) + BY <1>1 + <2>2. (\A n \in Nat : P(n) => <>Q) => ((\E n \in Nat : P(n)) => <>Q) + OBVIOUS + <2>. QED BY <2>1, <2>2, PTL +<1>3. TypeOK => (terminated => \E n \in Nat : P(n)) + BY DEF TypeOK, terminated, Node +<1>. QED BY <1>2, <1>3, PTL DEF TSpec + +LEMMA Round2 == TSpec => (terminated /\ tpos = 0 + ~> terminated /\ tpos = 0 /\ allWhite) +<1>. DEFINE P(n) == /\ terminated /\ n \in Node /\ tpos = n + /\ color[0] = "white" + /\ \A i \in n+1 .. N-1 : color[i] = "white" + Q == P(0) + R(n) == TSpec => [](P(n) => <>Q) +<1>1. \A n \in Nat : R(n) + <2>1. R(0) + BY PTL + <2>2. ASSUME NEW n \in Nat PROVE R(n) => R(n+1) + <3>. USE DEF TypeOK, Node, terminated + <3>1. TypeOK /\ P(n+1) /\ [Next]_vars => P(n+1)' \/ P(n)' + BY DEF Next, vars, System, Environment, InitiateProbe, + PassToken, Deactivate, SendMsg + <3>2. TypeOK /\ P(n+1) /\ <>_vars => P(n)' + BY DEF System, InitiateProbe, PassToken + <3>3. TypeOK /\ P(n+1) => ENABLED <>_vars + BY EnabledSystem + <3>. QED BY <3>1, <3>2, <3>3, PTL DEF TSpec + <2>. HIDE DEF R + <2>. QED BY <2>1, <2>2, NatInduction, Isa +<1>2. TSpec => []((\E n \in Nat : P(n)) => <>Q) + <2>. HIDE DEF P,Q + <2>1. TSpec => [](\A n \in Nat : P(n) => <>Q) + BY <1>1 + <2>2. (\A n \in Nat : P(n) => <>Q) => ((\E n \in Nat : P(n)) => <>Q) + OBVIOUS + <2>. QED BY <2>1, <2>2, PTL +<1>3. TSpec => (terminated /\ tpos = 0 ~> \E n \in Nat : P(n)) + <2>. DEFINE S == terminated /\ tpos = 0 + T == P(N-1) + <2>1. TypeOK /\ S /\ [Next]_vars => S' \/ T' + BY DEF TypeOK, Next, vars, System, Environment, InitiateProbe, PassToken, + Deactivate, SendMsg, terminated, Node + <2>2. TypeOK /\ S /\ <>_vars => T' + BY DEF TypeOK, System, InitiateProbe, PassToken, terminated, Node + <2>3. TypeOK /\ ~terminationDetected /\ S => ENABLED <>_vars + BY EnabledSystem DEF TypeOK, terminationDetected, terminated, Color + <2>4. T => \E n \in Nat : P(n) + OBVIOUS + <2>. QED BY <2>1, <2>2, <2>3, <2>4, PTL DEF TSpec +<1>4. Q => terminated /\ tpos = 0 /\ allWhite + BY DEF Node, allWhite +<1>. QED BY <1>2, <1>3, <1>4, PTL + +LEMMA Round3 == TSpec => (terminated /\ tpos = 0 /\ allWhite + ~> terminated /\ tpos = 0 /\ allWhite /\ tcolor = "white") +<1>. DEFINE P(n) == /\ terminated /\ n \in Node /\ tpos = n + /\ allWhite /\ tcolor = "white" + Q == P(0) + R(n) == TSpec => [](P(n) => <>Q) +<1>1. \A n \in Nat : R(n) + <2>1. R(0) + BY PTL + <2>2. ASSUME NEW n \in Nat PROVE R(n) => R(n+1) + <3>. USE DEF TypeOK, Node, terminated, allWhite + <3>1. TypeOK /\ P(n+1) /\ [Next]_vars => P(n+1)' \/ P(n)' + BY DEF Next, vars, System, Environment, InitiateProbe, + PassToken, Deactivate, SendMsg + <3>2. TypeOK /\ P(n+1) /\ <>_vars => P(n)' + BY DEF System, InitiateProbe, PassToken + <3>3. TypeOK /\ P(n+1) => ENABLED <>_vars + BY EnabledSystem + <3>. QED BY <3>1, <3>2, <3>3, PTL DEF TSpec + <2>. HIDE DEF R + <2>. QED BY <2>1, <2>2, NatInduction, Isa +<1>2. TSpec => []((\E n \in Nat : P(n)) => <>Q) + <2>. HIDE DEF P,Q + <2>1. TSpec => [](\A n \in Nat : P(n) => <>Q) + BY <1>1 + <2>2. (\A n \in Nat : P(n) => <>Q) => ((\E n \in Nat : P(n)) => <>Q) + OBVIOUS + <2>. QED BY <2>1, <2>2, PTL +<1>3. TSpec => (terminated /\ tpos = 0 /\ allWhite ~> \E n \in Nat : P(n)) + <2>. DEFINE S == terminated /\ tpos = 0 /\ allWhite + T == P(N-1) + <2>. USE DEF TypeOK, Node, terminated, allWhite + <2>1. TypeOK /\ S /\ [Next]_vars => S' \/ T' + BY DEF Next, vars, System, Environment, InitiateProbe, PassToken, + Deactivate, SendMsg + <2>2. TypeOK /\ S /\ <>_vars => T' + BY DEF System, InitiateProbe, PassToken + <2>3. TypeOK /\ ~terminationDetected /\ S => ENABLED <>_vars + BY EnabledSystem DEF terminationDetected, Color + <2>4. T => \E n \in Nat : P(n) + OBVIOUS + <2>. QED BY <2>1, <2>2, <2>3, <2>4, PTL DEF TSpec +<1>4. Q => terminated /\ tpos = 0 /\ allWhite /\ tcolor = "white" + BY DEF Node, allWhite +<1>. QED BY <1>2, <1>3, <1>4, PTL + +(***************************************************************************) +(* Liveness is a simple consequence of the above lemmas. *) +(***************************************************************************) +THEOREM Live == []TypeOK /\ []Inv /\ [][Next]_vars /\ WF_vars(System) => Liveness +<1>. terminated /\ tpos = 0 /\ allWhite /\ tcolor = "white" => terminationDetected + BY DEF terminated, allWhite, terminationDetected, Node +<1>. QED + BY Round1, Round2, Round3, PTL DEF TSpec, Liveness + +COROLLARY SpecLive == Spec => Liveness +BY Live, TypeCorrect, Invariant, PTL DEF Spec + +----------------------------------------------------------------------------- +(***************************************************************************) +(* The algorithm implements the high-level specification of termination *) +(* detection in a ring with synchronous communication between nodes. *) +(* Note that the parameters of the module SyncTerminationDetection are *) +(* instantiated by the symbols of the same name in the present module. *) +(***************************************************************************) +THEOREM Spec => TD!Spec +<1>. USE DEF Node, TD!Node +<1>1. Init => TD!Init + BY DEF Init, TD!Init, terminationDetected +<1>2. TypeOK /\ Inv /\ [Next]_vars => [TD!Next]_TD!vars + <2>. SUFFICES ASSUME TypeOK, Inv, Next PROVE [TD!Next]_TD!vars + BY DEF vars, TD!vars, terminationDetected + <2>. USE DEF TypeOK, Inv, Node, terminationDetected + <2>1. CASE InitiateProbe + BY <2>1 DEF InitiateProbe, TD!Next, TD!vars, TD!DetectTermination, TD!terminated + <2>2. ASSUME NEW i \in Node \ {0}, PassToken(i) PROVE [TD!Next]_TD!vars + BY <2>2 DEF PassToken, TD!Next, TD!vars, TD!DetectTermination, TD!terminated + <2>3. ASSUME NEW i \in Node, SendMsg(i) PROVE [TD!Next]_TD!vars + BY <2>3 DEF SendMsg, TD!Next, TD!Wakeup + <2>4. ASSUME NEW i \in Node, Deactivate(i) PROVE [TD!Next]_TD!vars + BY <2>4 DEF Deactivate, TD!Next, TD!Terminate, TD!terminated + <2>. QED BY <2>1, <2>2, <2>3, <2>4 DEF Next, System, Environment +<1>3. []TypeOK /\ []Inv /\ [][Next]_vars /\ WF_vars(System) + => WF_TD!vars(TD!DetectTermination) + <2>. SUFFICES /\ []TypeOK /\ []Inv /\ [][Next]_vars /\ WF_vars(System) + /\ []ENABLED <>_TD!vars + => FALSE + BY PTL + <2>1. TypeOK /\ ENABLED <>_TD!vars + => terminated /\ ~terminationDetected + BY ExpandENABLED + DEF TypeOK, TD!DetectTermination, TD!vars, terminated, TD!terminated, terminationDetected + <2>. QED BY <2>1, Live, PTL DEF Liveness +<1>. QED + BY <1>1, <1>2, <1>3, TypeCorrect, Invariant, PTL DEF Spec, TD!Spec ============================================================================= \* Modification History -\* Last modified Thu Jan 21 16:13:02 CET 2021 by merz \* Created Mon Sep 09 11:33:10 CEST 2013 by merz diff --git a/specifications/ewd840/SyncTerminationDetection.cfg b/specifications/ewd840/SyncTerminationDetection.cfg index 5c0a0d0a..2533b4cf 100644 --- a/specifications/ewd840/SyncTerminationDetection.cfg +++ b/specifications/ewd840/SyncTerminationDetection.cfg @@ -4,12 +4,10 @@ CONSTANTS SPECIFICATION Spec -PROPERTY - Stable - -INVARIANT +INVARIANTS TypeOK + TDCorrect PROPERTIES - Stable - Live + Quiescence + Liveness diff --git a/specifications/ewd840/SyncTerminationDetection.tla b/specifications/ewd840/SyncTerminationDetection.tla index 8e2beb64..86c3dd6a 100644 --- a/specifications/ewd840/SyncTerminationDetection.tla +++ b/specifications/ewd840/SyncTerminationDetection.tla @@ -1,7 +1,8 @@ ---------------------- MODULE SyncTerminationDetection ---------------------- (***************************************************************************) -(* An abstract specification of the termination detection problem in a *) -(* ring with synchronous communication. *) +(* This module contains an abstract specification of the termination *) +(* detection problem in a ring with synchronous communication. We will *) +(* prove that the EWD840 algorithm refines this specification. *) (***************************************************************************) EXTENDS Naturals CONSTANT N @@ -51,11 +52,15 @@ Next == vars == <> Spec == Init /\ [][Next]_vars /\ WF_vars(DetectTermination) -Stable == [](terminationDetected => []terminated) +------------------------------------------------------------------------------ +(* Correctness properties *) -Live == terminated ~> terminationDetected +TDCorrect == terminationDetected => terminated + +Quiescence == [](terminated => []terminated) + +Liveness == terminated ~> terminationDetected ============================================================================= \* Modification History -\* Last modified Thu Jan 21 16:08:09 CET 2021 by merz \* Created Sun Jan 10 15:19:20 CET 2021 by merz diff --git a/specifications/ewd840/SyncTerminationDetection_proof.tla b/specifications/ewd840/SyncTerminationDetection_proof.tla new file mode 100644 index 00000000..008616e0 --- /dev/null +++ b/specifications/ewd840/SyncTerminationDetection_proof.tla @@ -0,0 +1,57 @@ +------------------- MODULE SyncTerminationDetection_proof ------------------- +(***************************************************************************) +(* Proofs of the properties asserted in module SyncTerminationDetection. *) +(***************************************************************************) +EXTENDS SyncTerminationDetection, TLAPS + +(* Proofs of safety properties *) + +THEOREM TypeCorrect == Spec => []TypeOK +<1>1. Init => TypeOK + BY DEF Init, TypeOK, terminated +<1>2. TypeOK /\ [Next]_vars => TypeOK' + BY DEF Next, Terminate, Wakeup, DetectTermination, vars, terminated, TypeOK +<1>. QED BY <1>1, <1>2, PTL DEF Spec + +THEOREM CorrectDetection == Spec => TDCorrect +<1>1. Init => TDCorrect + BY DEF Init, TDCorrect +<1>2. TypeOK /\ TDCorrect /\ [Next]_vars => TDCorrect' + BY DEF TDCorrect, Next, Terminate, Wakeup, + DetectTermination, vars, terminated, TypeOK +<1>. QED BY <1>1, <1>2, TypeCorrect, PTL DEF Spec + +THEOREM Quiescent == Spec => Quiescence +<1>. TypeOK /\ [Next]_vars => (terminated => terminated') + BY DEF TypeOK, terminated, Next, Terminate, Wakeup, + DetectTermination, vars +<1>. QED BY TypeCorrect, PTL DEF Spec, Quiescence + +------------------------------------------------------------------------------ +(* Proof of liveness *) + +(****************************************************************************) +(* The following lemma reduces the enabledness condition underlying the *) +(* fairness condition to a simple state predicate. *) +(****************************************************************************) +LEMMA Enabled_ST == + ASSUME TypeOK + PROVE (ENABLED <>_vars) <=> terminated /\ ~terminationDetected +BY ExpandENABLED DEF TypeOK, DetectTermination, terminated, vars + +(****************************************************************************) +(* Proving liveness is easy since a single occurrence of the helpful action *) +(* DetectTermination leads to the desired state. *) +(****************************************************************************) +THEOREM Live == Spec => Liveness +<1>. DEFINE P == terminated /\ ~terminationDetected + Q == terminationDetected +<1>1. TypeOK /\ P /\ [Next]_vars => P' \/ Q' + BY DEF TypeOK, Next, Terminate, Wakeup, DetectTermination, vars, terminated +<1>2. TypeOK /\ P /\ <>_vars => Q' + BY DEF TypeOK, DetectTermination +<1>3. TypeOK /\ P => ENABLED <>_vars + BY Enabled_ST +<1>. QED BY <1>1, <1>2, <1>3, TypeCorrect, PTL DEF Spec, Liveness + +============================================================================= diff --git a/specifications/ewd840/TLAPS.tla b/specifications/ewd840/TLAPS.tla deleted file mode 100644 index 3abf4b1b..00000000 --- a/specifications/ewd840/TLAPS.tla +++ /dev/null @@ -1,411 +0,0 @@ -------------------------------- MODULE TLAPS -------------------------------- - -(* Backend pragmas. *) - - -(***************************************************************************) -(* Each of these pragmas can be cited with a BY or a USE. The pragma that *) -(* is added to the context of an obligation most recently is the one whose *) -(* effects are triggered. *) -(***************************************************************************) - -(***************************************************************************) -(* The following pragmas should be used only as a last resource. They are *) -(* dependent upon the particular backend provers, and are unlikely to have *) -(* any effect if the set of backend provers changes. Moreover, they are *) -(* meaningless to a reader of the proof. *) -(***************************************************************************) - - -(**************************************************************************) -(* Backend pragma: use the SMT solver for arithmetic. *) -(* *) -(* This method exists under this name for historical reasons. *) -(**************************************************************************) - -SimpleArithmetic == TRUE (*{ by (prover:"smt3") }*) - - -(**************************************************************************) -(* Backend pragma: SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2. The supported *) -(* fragment includes first-order logic, set theory, functions and *) -(* records. *) -(* SMT calls the smt-solver with the default timeout of 5 seconds *) -(* while SMTT(n) calls the smt-solver with a timeout of n seconds. *) -(**************************************************************************) - -SMT == TRUE (*{ by (prover:"smt3") }*) -SMTT(X) == TRUE (*{ by (prover:"smt3"; timeout:@) }*) - - -(**************************************************************************) -(* Backend pragma: CVC3 SMT solver *) -(* *) -(* CVC3 is used by default but you can also explicitly call it. *) -(**************************************************************************) - -CVC3 == TRUE (*{ by (prover: "cvc33") }*) -CVC3T(X) == TRUE (*{ by (prover:"cvc33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Yices SMT solver *) -(* *) -(* This method translates the proof obligation to Yices native language. *) -(**************************************************************************) - -Yices == TRUE (*{ by (prover: "yices3") }*) -YicesT(X) == TRUE (*{ by (prover:"yices3"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: veriT SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls veriT.*) -(**************************************************************************) - -veriT == TRUE (*{ by (prover: "verit") }*) -veriTT(X) == TRUE (*{ by (prover:"verit"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Z3 SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls Z3. *) -(**************************************************************************) - -Z3 == TRUE (*{ by (prover: "z33") }*) -Z3T(X) == TRUE (*{ by (prover:"z33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: SPASS superposition prover *) -(* *) -(* This method translates the proof obligation to the DFG format language *) -(* supported by the ATP SPASS. The translation is based on the SMT one. *) -(**************************************************************************) - -Spass == TRUE (*{ by (prover: "spass") }*) -SpassT(X) == TRUE (*{ by (prover:"spass"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: The PTL propositional linear time temporal logic *) -(* prover. It currently is the LS4 backend. *) -(* *) -(* This method translates the negetation of the proof obligation to *) -(* Seperated Normal Form (TRP++ format) and checks for unsatisfiability *) -(**************************************************************************) - -LS4 == TRUE (*{ by (prover: "ls4") }*) -PTL == TRUE (*{ by (prover: "ls4") }*) - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -Zenon == TRUE (*{ by (prover:"zenon") }*) -ZenonT(X) == TRUE (*{ by (prover:"zenon"; timeout:@) }*) - -(********************************************************************) -(* Backend pragma: Isabelle with different timeouts and tactics *) -(* (default is 30 seconds/auto) *) -(********************************************************************) - -Isa == TRUE (*{ by (prover:"isabelle") }*) -IsaT(X) == TRUE (*{ by (prover:"isabelle"; timeout:@) }*) -IsaM(X) == TRUE (*{ by (prover:"isabelle"; tactic:@) }*) -IsaMT(X,Y) == TRUE (*{ by (prover:"isabelle"; tactic:@; timeout:@) }*) - -(***************************************************************************) -(* The following theorem expresses the (useful implication of the) law of *) -(* set extensionality, which can be written as *) -(* *) -(* THEOREM \A S, T : (S = T) <=> (\A x : (x \in S) <=> (x \in T)) *) -(* *) -(* Theorem SetExtensionality is sometimes required by the SMT backend for *) -(* reasoning about sets. It is usually counterproductive to include *) -(* theorem SetExtensionality in a BY clause for the Zenon or Isabelle *) -(* backends. Instead, use the pragma IsaWithSetExtensionality to instruct *) -(* the Isabelle backend to use the rule of set extensionality. *) -(***************************************************************************) -IsaWithSetExtensionality == TRUE - (*{ by (prover:"isabelle"; tactic:"(auto intro: setEqualI)")}*) - -THEOREM SetExtensionality == \A S,T : (\A x : x \in S <=> x \in T) => S = T -OBVIOUS - -(***************************************************************************) -(* The following theorem is needed to deduce NotInSetS \notin SetS from *) -(* the definition *) -(* *) -(* NotInSetS == CHOOSE v : v \notin SetS *) -(***************************************************************************) -THEOREM NoSetContainsEverything == \A S : \E x : x \notin S -OBVIOUS (*{by (isabelle "(auto intro: inIrrefl)")}*) ------------------------------------------------------------------------------ - - - -(********************************************************************) -(********************************************************************) -(********************************************************************) - - -(********************************************************************) -(* Old versions of Zenon and Isabelle pragmas below *) -(* (kept for compatibility) *) -(********************************************************************) - - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -SlowZenon == TRUE (*{ by (prover:"zenon"; timeout:20) }*) -SlowerZenon == TRUE (*{ by (prover:"zenon"; timeout:40) }*) -VerySlowZenon == TRUE (*{ by (prover:"zenon"; timeout:80) }*) -SlowestZenon == TRUE (*{ by (prover:"zenon"; timeout:160) }*) - - - -(********************************************************************) -(* Backend pragma: Isabelle's automatic search ("auto") *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* essentially simplification and equational reasoning. *) -(* Default imeout for all isabelle tactics is 30 seconds. *) -(********************************************************************) -Auto == TRUE (*{ by (prover:"isabelle"; tactic:"auto") }*) -SlowAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:120) }*) -SlowerAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:480) }*) -SlowestAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:960) }*) - -(********************************************************************) -(* Backend pragma: Isabelle's "force" tactic *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* quantifier reasoning. *) -(********************************************************************) -Force == TRUE (*{ by (prover:"isabelle"; tactic:"force") }*) -SlowForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:120) }*) -SlowerForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:480) }*) -SlowestForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:960) }*) - -(***********************************************************************) -(* Backend pragma: Isabelle's "simplification" tactics *) -(* *) -(* These tactics simplify the goal before running one of the automated *) -(* tactics. They are often necessary for obligations involving record *) -(* or tuple projections. Use the SimplfyAndSolve tactic unless you're *) -(* sure you can get away with just Simplification *) -(***********************************************************************) -SimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?") }*) -SlowSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:120) }*) -SlowerSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:480) }*) -SlowestSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:960) }*) - -Simplification == TRUE (*{ by (prover:"isabelle"; tactic:"clarsimp") }*) -SlowSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:120) }*) -SlowerSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:480) }*) -SlowestSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:960) }*) - -(**************************************************************************) -(* Backend pragma: Isabelle's tableau prover ("blast") *) -(* *) -(* This pragma bypasses Zenon and uses Isabelle's built-in theorem *) -(* prover, Blast. It is almost never better than Zenon by itself, but *) -(* becomes very useful in combination with the Auto pragma above. The *) -(* AutoBlast pragma first attempts Auto and then uses Blast to prove what *) -(* Auto could not prove. (There is currently no way to use Zenon on the *) -(* results left over from Auto.) *) -(**************************************************************************) -Blast == TRUE (*{ by (prover:"isabelle"; tactic:"blast") }*) -SlowBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:120) }*) -SlowerBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:480) }*) -SlowestBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:960) }*) - -AutoBlast == TRUE (*{ by (prover:"isabelle"; tactic:"auto, blast") }*) - - -(**************************************************************************) -(* Backend pragmas: multi-back-ends *) -(* *) -(* These pragmas just run a bunch of back-ends one after the other in the *) -(* hope that one will succeed. This saves time and effort for the user at *) -(* the expense of computation time. *) -(**************************************************************************) - -(* CVC3 goes first because it's bundled with TLAPS, then the other SMT - solvers are unlikely to succeed if CVC3 fails, so we run zenon and - Isabelle before them. *) -AllProvers == TRUE (*{ - by (prover:"cvc33") - by (prover:"zenon") - by (prover:"isabelle"; tactic:"auto") - by (prover:"spass") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllProversT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"zenon"; timeout:@) - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"spass"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - -AllSMT == TRUE (*{ - by (prover:"cvc33") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - }*) -AllSMTT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - }*) - -AllIsa == TRUE (*{ - by (prover:"isabelle"; tactic:"auto") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllIsaT(X) == TRUE (*{ - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - ----------------------------------------------------------------------------- -(***************************************************************************) -(* TEMPORAL LOGIC *) -(* *) -(* The following rules are intended to be used when TLAPS handles temporal *) -(* logic. They will not work now. Moreover when temporal reasoning is *) -(* implemented, these rules may be changed or omitted, and additional *) -(* rules will probably be added. However, they are included mainly so *) -(* their names will be defined, preventing the use of identifiers that are *) -(* likely to produce name clashes with future versions of this module. *) -(***************************************************************************) - - -(***************************************************************************) -(* The following proof rules (and their names) are from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleTLA1 == ASSUME STATE P, STATE f, - P /\ (f' = f) => P' - PROVE []P <=> P /\ [][P => P']_f - -THEOREM RuleTLA2 == ASSUME STATE P, STATE Q, STATE f, STATE g, - ACTION A, ACTION B, - P /\ [A]_f => Q /\ [B]_g - PROVE []P /\ [][A]_f => []Q /\ [][B]_g - -THEOREM RuleINV1 == ASSUME STATE I, STATE F, ACTION N, - I /\ [N]_F => I' - PROVE I /\ [][N]_F => []I - -THEOREM RuleINV2 == ASSUME STATE I, STATE f, ACTION N - PROVE []I => ([][N]_f <=> [][N /\ I /\ I']_f) - -THEOREM RuleWF1 == ASSUME STATE P, STATE Q, STATE f, ACTION N, ACTION A, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - P => ENABLED <>_f - PROVE [][N]_f /\ WF_f(A) => (P ~> Q) - -THEOREM RuleSF1 == ASSUME STATE P, STATE Q, STATE f, - ACTION N, ACTION A, TEMPORAL F, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - []P /\ [][N]_f /\ []F => <> ENABLED <>_f - PROVE [][N]_f /\ SF_f(A) /\ []F => (P ~> Q) - -(***************************************************************************) -(* The rules WF2 and SF2 in "The Temporal Logic of Actions" are obtained *) -(* from the following two rules by the following substitutions: `. *) -(* *) -(* ___ ___ _______________ *) -(* M <- M , g <- g , EM <- ENABLED <>_g .' *) -(***************************************************************************) -THEOREM RuleWF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ WF_f(A) /\ []F /\ <>[]EM => <>[]P - PROVE [][N]_f /\ WF_f(A) /\ []F => []<><>_g \/ []<>(~EM) - -THEOREM RuleSF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ SF_f(A) /\ []F /\ []<>EM => <>[]P - PROVE [][N]_f /\ SF_f(A) /\ []F => []<><>_g \/ <>[](~EM) - - -(***************************************************************************) -(* The following rule is a special case of the general temporal logic *) -(* proof rule STL4 from the paper "The Temporal Logic of Actions". The *) -(* general rule is for arbitrary temporal formulas F and G, but it cannot *) -(* yet be handled by TLAPS. *) -(***************************************************************************) -THEOREM RuleInvImplication == - ASSUME STATE F, STATE G, - F => G - PROVE []F => []G -PROOF OMITTED - -(***************************************************************************) -(* The following rule is a special case of rule TLA2 from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleStepSimulation == - ASSUME STATE I, STATE f, STATE g, - ACTION M, ACTION N, - I /\ I' /\ [M]_f => [N]_g - PROVE []I /\ [][M]_f => [][N]_g -PROOF OMITTED - -(***************************************************************************) -(* The following may be used to invoke a decision procedure for *) -(* propositional temporal logic. *) -(***************************************************************************) -PropositionalTemporalLogic == TRUE -============================================================================= diff --git a/specifications/ewd998/AsyncTerminationDetection_proof.tla b/specifications/ewd998/AsyncTerminationDetection_proof.tla index 2d2f5031..167da342 100644 --- a/specifications/ewd998/AsyncTerminationDetection_proof.tla +++ b/specifications/ewd998/AsyncTerminationDetection_proof.tla @@ -1,46 +1,16 @@ ---------------------- MODULE AsyncTerminationDetection_proof --------------------- (*********************************************************************************) (* Proofs about the high-level specification of termination detection. *) -(* *) -(* Please note that the liveness proof below requires building tlapm from source *) -(* using the branch available at *) -(* https://github.com/tlaplus/tlapm/tree/updated_enabled_cdot. *) -(* Running the standard distribution of TLAPS on this module will result in an *) -(* error message about an unknown proof directive. *) (*********************************************************************************) EXTENDS AsyncTerminationDetection, TLAPS LEMMA TypeCorrect == Init /\ [][Next]_vars => []TypeOK -<1>. USE NAssumption DEF Node, TypeOK +<1>. USE NAssumption DEF Node, TypeOK, terminated <1>1. Init => TypeOK - BY Isa DEF Init, terminated + BY DEF Init, terminated <1>2. TypeOK /\ [Next]_vars => TypeOK' - <2> SUFFICES ASSUME TypeOK, - [Next]_vars - PROVE TypeOK' - OBVIOUS - <2>1. CASE DetectTermination - BY <2>1 DEF DetectTermination - <2>2. ASSUME NEW i \in Node, - NEW j \in Node, - Terminate(i) - PROVE TypeOK' - BY <2>2, Zenon DEF Terminate, terminated - <2>3. ASSUME NEW i \in Node, - NEW j \in Node, - RcvMsg(i) - PROVE TypeOK' - BY <2>3 DEF RcvMsg - <2>4. ASSUME NEW i \in Node, - NEW j \in Node, - SendMsg(i, j) - PROVE TypeOK' - BY <2>4 DEF SendMsg - <2>5. CASE UNCHANGED vars - BY <2>5 DEF vars - <2>6. QED - BY <2>1, <2>2, <2>3, <2>4, <2>5 DEF Next + BY DEF Next, vars, DetectTermination, Terminate, RcvMsg, SendMsg <1>. QED BY <1>1, <1>2, PTL (***************************************************************************) @@ -49,33 +19,16 @@ LEMMA TypeCorrect == Init /\ [][Next]_vars => []TypeOK THEOREM Safety == Init /\ [][Next]_vars => []Safe <1>. USE DEF terminated, TypeOK, Safe <1>1. Init => Safe - BY Zenon DEF Init + BY DEF Init <1>2. TypeOK /\ Safe /\ [Next]_vars => Safe' - <2> SUFFICES ASSUME TypeOK, Safe, [Next]_vars - PROVE Safe' - OBVIOUS - <2>1. CASE DetectTermination - BY <2>1 DEF DetectTermination - <2>2. ASSUME NEW i \in Node, Terminate(i) - PROVE Safe' - BY <2>2, Zenon DEF Terminate - <2>3. ASSUME NEW i \in Node, RcvMsg(i) - PROVE Safe' - BY <2>3 DEF RcvMsg - <2>4. ASSUME NEW i \in Node, NEW j \in Node, SendMsg(i, j) - PROVE Safe' - BY <2>4 DEF SendMsg - <2>5. CASE UNCHANGED vars - BY <2>5 DEF vars - <2>. QED - BY <2>1, <2>2, <2>3, <2>4, <2>5 DEF Next + BY DEF Next, vars, DetectTermination, Terminate, RcvMsg, SendMsg <1>. QED BY <1>1, <1>2, TypeCorrect, PTL THEOREM Stability == Init /\ [][Next]_vars => Quiescence -<1>1. TypeOK /\ terminated /\ [Next]_vars => terminated' - BY Isa DEF TypeOK, terminated, Next, DetectTermination, Terminate, RcvMsg, SendMsg, vars -<1>. QED BY <1>1, TypeCorrect, PTL DEF Quiescence +<1>. TypeOK /\ terminated /\ [Next]_vars => terminated' + BY DEF TypeOK, terminated, Next, DetectTermination, Terminate, RcvMsg, SendMsg, vars +<1>. QED BY TypeCorrect, PTL DEF Quiescence (***************************************************************************) (* Proofs of liveness. *) @@ -88,36 +41,19 @@ THEOREM Stability == Init /\ [][Next]_vars => Quiescence LEMMA EnabledDT == ASSUME TypeOK PROVE (ENABLED <>_vars) <=> (terminated /\ ~ terminationDetected) -<1>1. ASSUME terminated, ~ terminationDetected - PROVE ENABLED <>_vars - <2>1. <>_vars <=> DetectTermination - BY <1>1 DEF TypeOK, terminated, DetectTermination, vars - <2>2. (ENABLED <>_vars) <=> (ENABLED DetectTermination) - BY <2>1, ENABLEDrules - <2>3. ENABLED UNCHANGED <> - BY ExpandENABLED - <2>4. ENABLED DetectTermination - BY <1>1, <2>3, ENABLEDrewrites DEF DetectTermination - <2>. QED BY <2>2, <2>4 -<1>2. ASSUME ENABLED <>_vars - PROVE terminated /\ ~ terminationDetected - BY <1>2, ExpandENABLED, Zenon DEF DetectTermination, terminated, vars -<1>. QED BY <1>1, <1>2 +BY ExpandENABLED DEF TypeOK, DetectTermination, terminated, vars THEOREM Liveness == Spec => Live <1>. DEFINE P == terminated /\ ~ terminationDetected Q == terminationDetected <1>1. TypeOK /\ P /\ [Next]_vars => P' \/ Q' - BY Isa DEF TypeOK, terminated, Next, vars, Terminate, SendMsg, RcvMsg, DetectTermination + BY DEF TypeOK, terminated, Next, vars, Terminate, SendMsg, RcvMsg, DetectTermination <1>2. TypeOK /\ P /\ <>_vars => Q' BY DEF DetectTermination <1>3. TypeOK /\ P => ENABLED <>_vars BY EnabledDT <1>. QED BY <1>1, <1>2, <1>3, TypeCorrect, PTL DEF Spec, Live - ============================================================================= \* Modification History -\* Last modified Wed Jun 29 09:28:02 CEST 2022 by merz -\* Last modified Wed Jun 02 14:19:14 PDT 2021 by markus \* Created Sun Jan 10 15:19:20 CET 2021 by merz diff --git a/specifications/ewd998/EWD998.cfg b/specifications/ewd998/EWD998.cfg index c0caebdb..24776126 100644 --- a/specifications/ewd998/EWD998.cfg +++ b/specifications/ewd998/EWD998.cfg @@ -12,9 +12,9 @@ INVARIANT Inv TypeOK -\* PROPERTIES -\* \* Liveness -\* TDSpec +PROPERTIES + Liveness + TDSpec CHECK_DEADLOCK FALSE diff --git a/specifications/ewd998/EWD998.tla b/specifications/ewd998/EWD998.tla index 12523dc4..405bc724 100644 --- a/specifications/ewd998/EWD998.tla +++ b/specifications/ewd998/EWD998.tla @@ -5,7 +5,7 @@ (* Shmuel Safra's version of termination detection. *) (* https://www.cs.utexas.edu/users/EWD/ewd09xx/EWD998.PDF *) (***************************************************************************) -EXTENDS Integers, FiniteSets, Functions, SequencesExt, Randomization +EXTENDS Integers, FiniteSets, Functions, SequencesExt CONSTANT \* @type: Int; diff --git a/specifications/ewd998/EWD998_proof.tla b/specifications/ewd998/EWD998_proof.tla index 603b36ad..2bd8a15b 100644 --- a/specifications/ewd998/EWD998_proof.tla +++ b/specifications/ewd998/EWD998_proof.tla @@ -116,7 +116,7 @@ BY DEF IsAssociativeOn, IsCommutativeOn, IsIdentityOn LEMMA SumEmpty == ASSUME NEW fun PROVE Sum(fun, {}) = 0 -BY FoldFunctionOnSetEmpty DEF Sum +BY FoldFunctionOnSetEmpty, Zenon DEF Sum LEMMA SumIterate == ASSUME NEW fun \in [Node -> Int], @@ -151,7 +151,7 @@ LEMMA SumIsNat == ASSUME NEW fun \in [Node -> Nat], NEW inds \in SUBSET Node PROVE Sum(fun, inds) \in Nat -BY FoldFunctionOnSetType, NodeIsFinite, Isa DEF Sum +BY FoldFunctionOnSetType, NodeIsFinite, \A x,y \in Nat: x+y \in Nat, IsaM("blast") DEF Sum LEMMA SumZero == ASSUME NEW fun \in [Node -> Int], NEW inds \in SUBSET Node, @@ -164,7 +164,13 @@ LEMMA SumZero == BY SumEmpty <1>3. ASSUME NEW T, NEW x, IsFiniteSet(T), P(T), x \notin T PROVE P(T \cup {x}) - BY <1>3, SumIterate + <2>. HAVE T \cup {x} \in SUBSET inds + <2>1. Sum(fun, T \cup {x}) = fun[x] + Sum(fun, (T \cup {x}) \ {x}) + BY SumIterate + <2>2. /\ fun[x] = 0 + /\ (T \cup {x}) \ {x} = T + BY <1>3 + <2>. QED BY <1>3, <2>1, <2>2 <1>4. P(inds) <2>. HIDE DEF P <2>. QED BY <1>1, <1>2, <1>3, FS_Induction, IsaM("blast") @@ -209,7 +215,7 @@ THEOREM Invariance == Init /\ [][Next]_vars => []Inv BY <5>a, SumIsInt DEF TypeOK <5>3. token.q = Sum(counter, Rng(token.pos+1, N-1)) <6>1. CASE token.pos = N-1 - BY <4>1, <6>1, SumEmpty DEF Rng, Node + BY <4>1, <6>1, SumEmpty, Rng(token.pos+1, N-1) = {} DEF Rng, Node <6>2. CASE token.pos # N-1 BY <4>1, <6>2 <6>. QED BY <6>1, <6>2 @@ -257,7 +263,7 @@ THEOREM Invariance == Init /\ [][Next]_vars => []Inv <6>1. j \in Rng(0, token'.pos) BY <2>2, <5>3 DEF PassToken, TypeOK, Token, Node, Rng <6>2. color'[j] = color[j] - BY <2>2, <5>3 DEF PassToken + BY <2>2, <5>3 DEF PassToken, TypeOK, Node, Rng <6>. QED BY <5>1, <6>1, <6>2 <5>. QED BY <5>2, <5>3 <4>4. ASSUME Inv!P4 PROVE Inv!P4' @@ -275,6 +281,9 @@ THEOREM Invariance == Init /\ [][Next]_vars => []Inv BY <2>3, Zenon DEF SendMsg <3>2. B' = Sum(counter, Node)' <4>1. B' = B + 1 + <5>. /\ pending \in [Node -> Int] + /\ pending' \in [Node -> Int] + BY DEF TypeOK <5>1. /\ B = pending[j] + Sum(pending, Node \ {j}) /\ B' = pending'[j] + Sum(pending', Node \ {j}) BY SumIterate DEF B, TypeOK @@ -332,9 +341,12 @@ THEOREM Invariance == Init /\ [][Next]_vars => []Inv PROVE Inv' <3>1. B' = Sum(counter, Node)' <4>1. B' = B - 1 + <5>. /\ pending \in [Node -> Int] + /\ pending' \in [Node -> Int] + BY DEF TypeOK <5>1. /\ B = pending[i] + Sum(pending, Node \ {i}) /\ B' = pending'[i] + Sum(pending', Node \ {i}) - BY SumIterate DEF B, TypeOK + BY SumIterate DEF B <5>2. \A x \in Node \ {i} : pending'[x] = pending[x] BY <2>4 DEF TypeOK, RecvMsg <5>3. Sum(pending', Node \ {i}) = Sum(pending, Node \ {i}) @@ -363,8 +375,10 @@ THEOREM Invariance == Init /\ [][Next]_vars => []Inv BY <2>4 DEF RecvMsg, Rng <5>1. ASSUME Inv!P1 PROVE Inv!P2 \* then step <5>2 will show that P2 is preserved <6>1. B \in Nat \ {0} + <7>. pending \in [Node -> Int] + BY DEF TypeOK <7>. B = pending[i] + Sum(pending, Node \ {i}) - BY SumIterate DEF TypeOK, B + BY SumIterate DEF B <7>. QED BY <2>4, SumIsNat DEF RecvMsg, TypeOK <6>2. CASE token.pos = N-1 <7>1. token.q = 0 @@ -403,7 +417,7 @@ THEOREM Invariance == Init /\ [][Next]_vars => []Inv <2>5. ASSUME NEW i \in Node, Deactivate(i) PROVE Inv' - BY <2>5 DEF Deactivate, TypeOK, Token, Node, Range, Inv, B + BY <2>5, Zenon DEF Deactivate, TypeOK, Token, Node, Rng, Inv, B <2>6. CASE UNCHANGED vars BY <2>6 DEF vars, Inv, B <2>7. QED @@ -428,19 +442,25 @@ THEOREM Safety == <3>3. ~ Inv!P2 <4>1. Sum(counter, Rng(0,0)) = counter[0] + Sum(counter, Rng(0,0) \ {0}) BY SumIterate DEF TypeOK, Rng, Node - <4>2. Sum(counter, Rng(0,0)) = counter[0] - BY <4>1, SumEmpty DEF TypeOK, Rng, Node - <4>. QED BY <4>2 DEF terminationDetected, TypeOK, Token + <4>2. Rng(0,0) \ {0} = {} + BY DEF Rng, Node + <4>3. Sum(counter, Rng(0,0)) = counter[0] + BY <4>1, <4>2, SumEmpty DEF TypeOK, Node + <4>. QED BY <4>3 DEF terminationDetected, TypeOK, Token <3>. QED BY <3>1, <3>2, <3>3 DEF Inv <2>2. \A i \in Node : active[i] = FALSE - BY <2>1 DEF TypeOK, Token, Node, Rng, terminationDetected + <3>1. active[0] = FALSE + BY DEF TypeOK, Node, terminationDetected + <3>2. \A i \in Rng(1, N-1) : active[i] = FALSE + BY <2>1 DEF terminationDetected + <3>. QED BY <3>1, <3>2 DEF Rng, Node <2>3. Sum(counter, Node) = 0 <3>1. token.q = Sum(counter, Rng(1, N-1)) <4>1. CASE token.pos = N-1 <5>1. N = 1 BY <4>1 DEF terminationDetected <5>2. Sum(counter, Rng(1, N-1)) = 0 - BY <5>1, SumEmpty DEF Rng, Node + BY <5>1, SumEmpty, Isa DEF Rng, Node <5>3. Rng(token.pos+1, N-1) = {} BY <4>1, NAssumption DEF TypeOK, Token, Rng, Node <5>. QED BY <2>1, <4>1, <5>2, <5>3, SumEmpty @@ -448,7 +468,7 @@ THEOREM Safety == BY <2>1, <4>2 DEF terminationDetected <4>. QED BY <4>1, <4>2 <3>2. Sum(counter, Node) = counter[0] + Sum(counter, Rng(1, N-1)) - BY SumIterate DEF TypeOK, Node, Rng + BY SumIterate, Rng(1, N-1) = Node \ {0} DEF TypeOK, Node, Rng <3>. QED BY <3>1, <3>2 DEF TypeOK, Token, terminationDetected <2>. QED BY <2>2, <2>3 DEF Inv, Termination <1>2. TypeOK' /\ Inv' /\ terminationDetected' => Termination' @@ -465,8 +485,10 @@ LEMMA B0NoMessagePending == <2>. SUFFICES ASSUME TypeOK, B = 0, NEW i \in Node, pending[i] # 0 PROVE FALSE OBVIOUS + <2>. pending \in [Node -> Int] + BY DEF TypeOK <2>. B = pending[i] + Sum(pending, Node \ {i}) - BY SumIterate DEF TypeOK, B + BY SumIterate DEF B <2>. QED BY SumIsNat DEF TypeOK <1>2. (TypeOK /\ B=0 => \A i \in Node : pending[i] = 0)' BY <1>1, PTL @@ -489,16 +511,15 @@ LEMMA EnabledSystem == /\ token.color = "black" \/ color[0] = "black" \/ counter[0]+token.q > 0 \/ \E i \in Node \ {0} : ~ active[i] /\ token.pos = i <1>1. <>_vars <=> System - <2>1. InitiateProbe => <>_vars - BY DEF InitiateProbe, TypeOK, Token, vars, Node - <2>2. \A i \in Node \ {0} : PassToken(i) => <>_vars - BY DEF PassToken, TypeOK, Token, vars, Node - <2>. QED BY <2>1, <2>2 DEF System + BY DEF System, vars, InitiateProbe, PassToken, TypeOK, Node <1>2. (ENABLED <>_vars) <=> (ENABLED System) - BY <1>1, ENABLEDrules -<1>3. ENABLED UNCHANGED <> - BY ExpandENABLED -<1>. QED BY <1>2, <1>3, ENABLEDrewrites DEF System, InitiateProbe, PassToken + BY <1>1, ENABLEDaxioms +<1>3. (ENABLED System) + <=> \/ /\ token.pos = 0 + /\ token.color = "black" \/ color[0] = "black" \/ counter[0]+token.q > 0 + \/ \E i \in Node \ {0} : ~ active[i] /\ token.pos = i + BY ExpandENABLED DEF System, vars, InitiateProbe, PassToken +<1>. QED BY <1>2, <1>3 (***************************************************************************) (* In particular, a system transition is enabled when the token is at the *) @@ -513,13 +534,23 @@ COROLLARY EnabledAtMaster == <1>2. /\ token.pos = 0 /\ token.color = "black" \/ color[0] = "black" \/ counter[0]+token.q > 0 <2>1. CASE Inv!P1 + <3>0. Sum(counter, Node) = 0 + BY DEF Inv <3>1. Sum(counter, Node) = counter[0] + Sum(counter, Rng(token.pos+1, N-1)) - BY SumIterate DEF Rng + BY SumIterate, Rng(token.pos+1, N-1) = Node \ {0} DEF Rng + <3>3. token.q = Sum(counter, Rng(token.pos+1, N-1)) + <4>1. CASE N = 1 + <5>. Rng(token.pos+1, N-1) = {} + BY <4>1 DEF Rng + <5>. QED BY <2>1, <4>1, SumEmpty + <4>2. CASE N # 1 + BY <2>1, <4>2 + <4>. QED BY <4>1, <4>2 <3>2. counter[0] + token.q = 0 - BY <2>1, <3>1 DEF Inv + BY <3>0, <3>1, <3>3 <3>. QED BY <3>2, B0NoMessagePending DEF terminationDetected, Color <2>2. CASE Inv!P2 - BY <2>2, SumSingleton DEF Rng + BY <2>2, SumSingleton, Rng(0, token.pos) = {0} DEF Rng <2>3. CASE Inv!P3 BY <2>3 DEF Rng <2>4. CASE Inv!P4 @@ -693,7 +724,7 @@ LEMMA Round3 == BSpec => (Termination /\ atMaster /\ allWhite <4>2. ASSUME TypeOK, Pn1, NEW i \in Node \ {0}, PassToken(i) PROVE Pn' <5>. Sum(counter, Rng(i, N-1)) = counter[i] + Sum(counter, Rng(i+1, N-1)) - BY <4>2, SumIterate DEF Rng + BY <4>2, SumIterate, Rng(i+1, N-1) = Rng(i, N-1) \ {i} DEF Rng <5>. QED BY <4>2 DEF PassToken <4>. QED BY <4>1, <4>2 DEF System <3>1. TypeOK /\ Pn1 /\ [Next]_vars => Pn1' \/ Pn' @@ -732,7 +763,7 @@ LEMMA Detection == BY B0NoMessagePending DEF Termination, atMaster, allWhite, tknWhite, Node <1>2. token.q + counter[0] = 0 <2>1. Sum(counter, Node) = counter[0] + Sum(counter, Rng(1,N-1)) - BY SumIterate DEF Node, TypeOK, Rng + BY SumIterate, Rng(1, N-1) = Node \ {0} DEF Node, TypeOK, Rng <2>2. Sum(counter, Node) = token.q + counter[0] BY <2>1 DEF tknCount, TypeOK, Token, Node <2>3. Sum(counter, Node) = 0 @@ -776,15 +807,13 @@ THEOREM Refinement == Spec => TD!Spec (* but then terminated must also be TRUE. *) (***********************************************************************) <3>4. CASE terminationDetected' = TRUE - <4>1. /\ token'.pos = 0 - /\ ~ active[0] - /\ pending[0] = 0 - BY <3>2, <3>4 DEF terminationDetected - <4>2. N = 1 - BY <2>1, <4>1 DEF InitiateProbe, TypeOK, Token, Node + <4>1. Termination' + BY <3>4, Safety + <4>2. \A i \in Node : pending'[i] = 0 + BY <4>1, B0NoMessagePending DEF Termination <4>3. TD!terminated - BY <4>1, <4>2 DEF Node, TD!terminated - <4>. QED BY <3>2, <3>4, <4>3 DEF TD!Next, TD!DetectTermination + BY <3>2, <4>1, <4>2 DEF Termination, TD!terminated + <4>. QED BY <3>2, <3>4, <4>3 DEF TD!Next, TD!DetectTermination <3>. QED BY <3>3, <3>4 DEF terminationDetected <2>2. ASSUME NEW i \in Node \ {0}, PassToken(i) @@ -811,7 +840,7 @@ THEOREM Refinement == Spec => TD!Spec BY <2>3, Zenon DEF SendMsg <3>2. /\ terminationDetected = FALSE /\ terminationDetected' = FALSE - BY <3>1, Safety DEF Termination + BY <3>1, Safety DEF Termination, terminationDetected <3>. QED BY <3>1, <3>2, Zenon DEF TD!Next, TD!SendMsg <2>4. ASSUME NEW i \in Node, RecvMsg(i) @@ -824,7 +853,7 @@ THEOREM Refinement == Spec => TD!Spec Deactivate(i) PROVE [TD!Next]_(TD!vars) <3>1. terminationDetected = FALSE - BY <2>5, Safety DEF Termination, Deactivate + BY <2>5, Safety DEF Termination, Deactivate, terminationDetected <3>2. CASE terminationDetected' = FALSE BY <2>5, <3>1, <3>2, Zenon DEF Deactivate, TD!Terminate, TD!Next <3>3. CASE terminationDetected' = TRUE @@ -851,7 +880,7 @@ THEOREM Refinement == Spec => TD!Spec <3>2. \A n \in Node : ~ active[n] /\ pending[n] = 0 BY <3>1 DEF TD!terminated <3>3. B = 0 - BY <3>2, SumZero DEF TypeOK, B + BY <3>2, SumZero, pending \in [Node -> Int] DEF TypeOK, B <3>. QED BY <3>1, <3>2, <3>3 DEF Termination <2>. QED BY <2>2, Live, TypeCorrect, Invariance, PTL DEF Liveness <1>. QED BY <1>1, <1>2, <1>4, TypeCorrect, Invariance, PTL DEF Spec, TD!Spec diff --git a/specifications/ewd998/Folds.tla b/specifications/ewd998/Folds.tla new file mode 100644 index 00000000..d98ad132 --- /dev/null +++ b/specifications/ewd998/Folds.tla @@ -0,0 +1,30 @@ +------------------------------- MODULE Folds ------------------------------- + +MapThenFoldSet(op(_,_), base, f(_), choose(_), S) == +(******************************************************************************) +(* Starting from base, apply op to f(x), for all x \in S, by choosing the set *) +(* elements with `choose`. If there are multiple ways for choosing an element,*) +(* op should be associative and commutative. Otherwise, the result may depend *) +(* on the concrete implementation of `choose`. *) +(* *) +(* FoldSet, a simpler version for sets is contained in FiniteSetsEx. *) +(* FoldFunction, a simpler version for functions is contained in Functions. *) +(* FoldSequence, a simpler version for sequences is contained in SequencesExt.*) +(* *) +(* Example: *) +(* *) +(* MapThenFoldSet(LAMBDA x,y: x \cup y, *) +(* {}, *) +(* LAMBDA x: {{x}}, *) +(* LAMBDA set: CHOOSE x \in set: TRUE, *) +(* {1,2}) *) +(* = {{1},{2}} *) +(******************************************************************************) + LET iter[s \in SUBSET S] == + IF s = {} THEN base + ELSE LET x == choose(s) + IN op(f(x), iter[s \ {x}]) + IN iter[S] + + +============================================================================= diff --git a/specifications/ewd998/Functions.tla b/specifications/ewd998/Functions.tla new file mode 100644 index 00000000..4b0652b0 --- /dev/null +++ b/specifications/ewd998/Functions.tla @@ -0,0 +1,176 @@ +------------------------------ MODULE Functions ----------------------------- +(***************************************************************************) +(* `^{\large\bf \vspace{12pt} *) +(* Notions about functions including injection, surjection, and bijection.*) +(* Originally contributed by Tom Rodeheffer, MSR. *) +(* \vspace{12pt}}^' *) +(***************************************************************************) + +LOCAL INSTANCE Folds + +(***************************************************************************) +(* Restriction of a function to a set (should be a subset of the domain). *) +(***************************************************************************) +Restrict(f,S) == [ x \in S |-> f[x] ] + +(***************************************************************************) +(* Restriction of a function to the subset of its domain satisfying a *) +(* test predicate. *) +(* *) +(* Example: *) +(* (LET f == (0 :> "a" @@ 1 :> "b" @@ 2 :> "c") *) +(* IN RestrictDomain(f, LAMBDA x : x \in {0,2})) *) +(* = (0 :> "a" @@ 2 :> "c") *) +(***************************************************************************) +RestrictDomain(f, Test(_)) == Restrict(f, {x \in DOMAIN f : Test(x)}) + +(***************************************************************************) +(* Restriction of a function to the subset of its domain for which the *) +(* function values satisfy a test predicate. *) +(* *) +(* Example: *) +(* (LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* IN RestrictValues(f, LAMBDA y : y \in {0,2})) *) +(* = ("a" :> 0 @@ "b" :> 2) *) +(* *) +(* This is similar to the operator SelectSeq from the standard Sequences *) +(* module and related to standard "filter" functions in functional *) +(* programming. However, SelectSeq produces sequences, whereas *) +(* RestrictValues will in general not. For example, *) +(* *) +(* RestrictValues([0,1,2], LAMBDA y : y \in {0,2}) *) +(* = (1 :> 0 @@ 3 :> 2) *) +(***************************************************************************) +RestrictValues(f, Test(_)) == + LET S == {x \in DOMAIN f : Test(f[x])} + IN Restrict(f, S) + +(***************************************************************************) +(* Check if a function narrow is a restriction of a function wide, i.e. *) +(* Is the domain of narrow a subset of that of wide, and does the *) +(* projection of wide on the domain of narrow have the same image as *) +(* narrow does. *) +(* *) +(* Examples: *) +(* IsRestriction([one |-> 1], [one |-> 1, two |-> 2]) *) +(* IsRestriction([one |-> 1], [one |-> 1]) *) +(* ~IsRestriction([one |-> 1, two |-> 2], [one |-> 1, two |-> 3]) *) +(* ~IsRestriction([one |-> 1], [2 |-> two]) *) +(* ~IsRestriction([one |-> 1, two |-> 2], [two |-> 2]) *) +(***************************************************************************) +IsRestriction(narrow, wide) == + /\ DOMAIN narrow \subseteq DOMAIN wide + /\ \A x \in DOMAIN narrow \intersect DOMAIN wide: narrow[x] = wide[x] + +(***************************************************************************) +(* Range of a function. *) +(* Note: The image of a set under function f can be defined as *) +(* Range(Restrict(f,S)). *) +(***************************************************************************) +Range(f) == { f[x] : x \in DOMAIN f } + +(***************************************************************************) +(* Assuming DOMAIN f \subseteq DOMAIN g, apply the binary operation T to *) +(* the corresponding elements of the two functions f and g. *) +(* *) +(* Example: *) +(* LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* g == ("a" :> 1 @@ "b" :> 1 @@ "c" :> 3) *) +(* IN Pointwise(f,g,+) = ("a" :> 1 @@ "b" :> 2 @@ "c" :> 5 ) *) +(***************************************************************************) +Pointwise(f, g, T(_,_)) == [ e \in DOMAIN f |-> T(f[e], g[e]) ] + +(***************************************************************************) +(* The inverse of a function. *) +(* Example: *) +(* LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* IN Inverse(f, DOMAIN f, Range(f)) = *) +(* (0 :> "a" @@ 1 :> "b" @@ 2 :> "c") *) +(* Example: *) +(* LET f == ("a" :> 0 @@ "b" :> 1 @@ "c" :> 2) *) +(* IN Inverse(f, DOMAIN f, {1,3}) = *) +(* 1 :> "b" @@ 3 :> "a") *) +(***************************************************************************) +Inverse(f,S,T) == [t \in T |-> CHOOSE s \in S : t \in Range(f) => f[s] = t] + +(***************************************************************************) +(* The inverse of a function. *) +(***************************************************************************) +AntiFunction(f) == Inverse(f, DOMAIN f, Range(f)) + +(***************************************************************************) +(* A function is injective iff it maps each element in its domain to a *) +(* distinct element. *) +(* *) +(* This definition is overridden by TLC in the Java class Functions.java *) +(* The operator is overridden by the Java method with the same name. *) +(***************************************************************************) +IsInjective(f) == \A a,b \in DOMAIN f : f[a] = f[b] => a = b + +(***************************************************************************) +(* Set of injections between two sets. *) +(***************************************************************************) +Injection(S,T) == { M \in [S -> T] : IsInjective(M) } + + +(***************************************************************************) +(* A map is a surjection iff for each element in the range there is some *) +(* element in the domain that maps to it. *) +(***************************************************************************) +Surjection(S,T) == { M \in [S -> T] : \A t \in T : \E s \in S : M[s] = t } + + +(***************************************************************************) +(* A map is a bijection iff it is both an injection and a surjection. *) +(***************************************************************************) +Bijection(S,T) == Injection(S,T) \cap Surjection(S,T) + + +(***************************************************************************) +(* An injection, surjection, or bijection exists if the corresponding set *) +(* is nonempty. *) +(***************************************************************************) +ExistsInjection(S,T) == Injection(S,T) # {} +ExistsSurjection(S,T) == Surjection(S,T) # {} +ExistsBijection(S,T) == Bijection(S,T) # {} + +-------------------------------------------------------------------------------- + +FoldFunction(op(_,_), base, fun) == + (***************************************************************************) + (* Applies the binary function op on all elements of fun in arbitrary *) + (* order starting with op(f[k], base). The resulting function is: *) + (* op(f[i],op(f[j], ..., op(f[k],base) ...)) *) + (* *) + (* op must be associative and commutative, because we can not assume a *) + (* particular ordering of i, j, and k *) + (* *) + (* Example: *) + (* FoldFunction(LAMBDA x,y: {x} \cup y, {}, <<1,2,1>>) = {1,2} *) + (***************************************************************************) + MapThenFoldSet(op, base, LAMBDA i : fun[i], LAMBDA s: CHOOSE x \in s : TRUE, DOMAIN fun) + + +FoldFunctionOnSet(op(_,_), base, fun, indices) == + (***************************************************************************) + (* Applies the binary function op on the given indices of fun in arbitrary *) + (* order starting with op(f[k], base). The resulting function is: *) + (* op(f[i],op(f[j], ..., op(f[k],base) ...)) *) + (* *) + (* op must be associative and commutative, because we can not assume a *) + (* particular ordering of i, j, and k *) + (* *) + (* indices must be a subset of DOMAIN(fun) *) + (* *) + (* Example: *) + (* FoldFunctionOnSet(LAMBDA x,y: {x} \cup y, {}, <<1,2>>, {}) = {} *) + (***************************************************************************) + MapThenFoldSet(op, base, LAMBDA i : fun[i], LAMBDA s: CHOOSE x \in s : TRUE, indices) + +============================================================================= +\* Modification History +\* Last modified Tue Nov 01 08:46:11 CET 2022 by merz +\* Last modified Mon Apr 05 03:25:53 CEST 2021 by marty +\* Last modified Wed Jun 05 12:14:19 CEST 2013 by bhargav +\* Last modified Fri May 03 12:55:35 PDT 2013 by tomr +\* Created Thu Apr 11 10:30:48 PDT 2013 by tomr diff --git a/specifications/ewd998/README.md b/specifications/ewd998/README.md index 0884c588..47554f06 100644 --- a/specifications/ewd998/README.md +++ b/specifications/ewd998/README.md @@ -67,7 +67,7 @@ of a set of behaviors; not a single behavior. If random simulation is good enough in practice to predict statistical properties, it could help short-circuit modeling of an algorithm that currently requires empirical analysis of an algorithm’s implementation. In other words, traditionally -we would model EWD998 in TLA+ and check safey and liveness properties up +we would model EWD998 in TLA+ and check safety and liveness properties up to proving correctness. Then, we would implement EWD998 in a suitable programming language and analyze its statistical properties by running the implementation. If the statistical properties are unsatisfactory, we diff --git a/specifications/ewd998/TLAPS.tla b/specifications/ewd998/TLAPS.tla deleted file mode 100644 index e83bb97d..00000000 --- a/specifications/ewd998/TLAPS.tla +++ /dev/null @@ -1,468 +0,0 @@ -------------------------------- MODULE TLAPS -------------------------------- - -(* Backend pragmas. *) - - -(***************************************************************************) -(* Each of these pragmas can be cited with a BY or a USE. The pragma that *) -(* is added to the context of an obligation most recently is the one whose *) -(* effects are triggered. *) -(***************************************************************************) - -(***************************************************************************) -(* The following pragmas should be used only as a last resource. They are *) -(* dependent upon the particular backend provers, and are unlikely to have *) -(* any effect if the set of backend provers changes. Moreover, they are *) -(* meaningless to a reader of the proof. *) -(***************************************************************************) - - -(**************************************************************************) -(* Backend pragma: use the SMT solver for arithmetic. *) -(* *) -(* This method exists under this name for historical reasons. *) -(**************************************************************************) - -SimpleArithmetic == TRUE (*{ by (prover:"smt3") }*) - - -(**************************************************************************) -(* Backend pragma: SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2. The supported *) -(* fragment includes first-order logic, set theory, functions and *) -(* records. *) -(* SMT calls the smt-solver with the default timeout of 5 seconds *) -(* while SMTT(n) calls the smt-solver with a timeout of n seconds. *) -(**************************************************************************) - -SMT == TRUE (*{ by (prover:"smt3") }*) -SMTT(X) == TRUE (*{ by (prover:"smt3"; timeout:@) }*) - - -(**************************************************************************) -(* Backend pragma: CVC4 SMT solver *) -(* *) -(* These methods translate the proof obligation to SMTLIB2 and call CVC4. *) -(**************************************************************************) - -(* The CVC3* methods are here for backward compatibility. They call CVC4. *) -CVC3 == TRUE (*{ by (prover: "cvc33") }*) -CVC3T(X) == TRUE (*{ by (prover:"cvc33"; timeout:@) }*) - -CVC4 == TRUE (*{ by (prover: "cvc33") }*) -CVC4T(X) == TRUE (*{ by (prover:"cvc33"; timeout:@) }*) - - -(**************************************************************************) -(* Backend pragma: Yices SMT solver *) -(* *) -(* This method translates the proof obligation to Yices native language. *) -(**************************************************************************) - -Yices == TRUE (*{ by (prover: "yices3") }*) -YicesT(X) == TRUE (*{ by (prover:"yices3"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: veriT SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls veriT.*) -(**************************************************************************) - -veriT == TRUE (*{ by (prover: "verit") }*) -veriTT(X) == TRUE (*{ by (prover:"verit"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Z3 SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls Z3. *) -(* Z3 is used by default but you can also explicitly call it. *) -(**************************************************************************) - -Z3 == TRUE (*{ by (prover: "z33") }*) -Z3T(X) == TRUE (*{ by (prover:"z33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: SPASS superposition prover *) -(* *) -(* This method translates the proof obligation to the DFG format language *) -(* supported by the ATP SPASS. The translation is based on the SMT one. *) -(**************************************************************************) - -Spass == TRUE (*{ by (prover: "spass") }*) -SpassT(X) == TRUE (*{ by (prover:"spass"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: The PTL propositional linear time temporal logic *) -(* prover. It currently is the LS4 backend. *) -(* *) -(* This method translates the negetation of the proof obligation to *) -(* Seperated Normal Form (TRP++ format) and checks for unsatisfiability *) -(**************************************************************************) - -LS4 == TRUE (*{ by (prover: "ls4") }*) -LS4T(X) == TRUE (*{ by (prover: "ls4"; timeout:@) }*) -PTL == TRUE (*{ by (prover: "ls4") }*) - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -Zenon == TRUE (*{ by (prover:"zenon") }*) -ZenonT(X) == TRUE (*{ by (prover:"zenon"; timeout:@) }*) - -(********************************************************************) -(* Backend pragma: Isabelle with different timeouts and tactics *) -(* (default is 30 seconds/auto) *) -(********************************************************************) - -Isa == TRUE (*{ by (prover:"isabelle") }*) -IsaT(X) == TRUE (*{ by (prover:"isabelle"; timeout:@) }*) -IsaM(X) == TRUE (*{ by (prover:"isabelle"; tactic:@) }*) -IsaMT(X,Y) == TRUE (*{ by (prover:"isabelle"; tactic:@; timeout:@) }*) - -(***************************************************************************) -(* The following theorem expresses the (useful implication of the) law of *) -(* set extensionality, which can be written as *) -(* *) -(* THEOREM \A S, T : (S = T) <=> (\A x : (x \in S) <=> (x \in T)) *) -(* *) -(* Theorem SetExtensionality is sometimes required by the SMT backend for *) -(* reasoning about sets. It is usually counterproductive to include *) -(* theorem SetExtensionality in a BY clause for the Zenon or Isabelle *) -(* backends. Instead, use the pragma IsaWithSetExtensionality to instruct *) -(* the Isabelle backend to use the rule of set extensionality. *) -(***************************************************************************) -IsaWithSetExtensionality == TRUE - (*{ by (prover:"isabelle"; tactic:"(auto intro: setEqualI)")}*) - -THEOREM SetExtensionality == \A S,T : (\A x : x \in S <=> x \in T) => S = T -OBVIOUS - -(***************************************************************************) -(* The following theorem is needed to deduce NotInSetS \notin SetS from *) -(* the definition *) -(* *) -(* NotInSetS == CHOOSE v : v \notin SetS *) -(***************************************************************************) -THEOREM NoSetContainsEverything == \A S : \E x : x \notin S -OBVIOUS (*{by (isabelle "(auto intro: inIrrefl)")}*) ------------------------------------------------------------------------------ - - - -(********************************************************************) -(********************************************************************) -(********************************************************************) - - -(********************************************************************) -(* Old versions of Zenon and Isabelle pragmas below *) -(* (kept for compatibility) *) -(********************************************************************) - - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -SlowZenon == TRUE (*{ by (prover:"zenon"; timeout:20) }*) -SlowerZenon == TRUE (*{ by (prover:"zenon"; timeout:40) }*) -VerySlowZenon == TRUE (*{ by (prover:"zenon"; timeout:80) }*) -SlowestZenon == TRUE (*{ by (prover:"zenon"; timeout:160) }*) - - - -(********************************************************************) -(* Backend pragma: Isabelle's automatic search ("auto") *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* essentially simplification and equational reasoning. *) -(* Default imeout for all isabelle tactics is 30 seconds. *) -(********************************************************************) -Auto == TRUE (*{ by (prover:"isabelle"; tactic:"auto") }*) -SlowAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:120) }*) -SlowerAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:480) }*) -SlowestAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:960) }*) - -(********************************************************************) -(* Backend pragma: Isabelle's "force" tactic *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* quantifier reasoning. *) -(********************************************************************) -Force == TRUE (*{ by (prover:"isabelle"; tactic:"force") }*) -SlowForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:120) }*) -SlowerForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:480) }*) -SlowestForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:960) }*) - -(***********************************************************************) -(* Backend pragma: Isabelle's "simplification" tactics *) -(* *) -(* These tactics simplify the goal before running one of the automated *) -(* tactics. They are often necessary for obligations involving record *) -(* or tuple projections. Use the SimplfyAndSolve tactic unless you're *) -(* sure you can get away with just Simplification *) -(***********************************************************************) -SimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?") }*) -SlowSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:120) }*) -SlowerSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:480) }*) -SlowestSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:960) }*) - -Simplification == TRUE (*{ by (prover:"isabelle"; tactic:"clarsimp") }*) -SlowSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:120) }*) -SlowerSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:480) }*) -SlowestSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:960) }*) - -(**************************************************************************) -(* Backend pragma: Isabelle's tableau prover ("blast") *) -(* *) -(* This pragma bypasses Zenon and uses Isabelle's built-in theorem *) -(* prover, Blast. It is almost never better than Zenon by itself, but *) -(* becomes very useful in combination with the Auto pragma above. The *) -(* AutoBlast pragma first attempts Auto and then uses Blast to prove what *) -(* Auto could not prove. (There is currently no way to use Zenon on the *) -(* results left over from Auto.) *) -(**************************************************************************) -Blast == TRUE (*{ by (prover:"isabelle"; tactic:"blast") }*) -SlowBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:120) }*) -SlowerBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:480) }*) -SlowestBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:960) }*) - -AutoBlast == TRUE (*{ by (prover:"isabelle"; tactic:"auto, blast") }*) - - -(**************************************************************************) -(* Backend pragmas: multi-back-ends *) -(* *) -(* These pragmas just run a bunch of back-ends one after the other in the *) -(* hope that one will succeed. This saves time and effort for the user at *) -(* the expense of computation time. *) -(**************************************************************************) - -(* CVC3 goes first because it's bundled with TLAPS, then the other SMT - solvers are unlikely to succeed if CVC3 fails, so we run zenon and - Isabelle before them. *) -AllProvers == TRUE (*{ - by (prover:"cvc33") - by (prover:"zenon") - by (prover:"isabelle"; tactic:"auto") - by (prover:"spass") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllProversT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"zenon"; timeout:@) - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"spass"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - -AllSMT == TRUE (*{ - by (prover:"cvc33") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - }*) -AllSMTT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - }*) - -AllIsa == TRUE (*{ - by (prover:"isabelle"; tactic:"auto") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllIsaT(X) == TRUE (*{ - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - - -(**************************************************************************) -(* The pragma ExpandEnabled invokes expansion of the operator ENABLED. *) -(* *) -(* The pragma ExpandCdot invokes expansion of the operator \cdot. *) -(* *) -(* The pragma AutoUSE invokes automated expansion of definitions, *) -(* for both of ExpandEnabled and ExpandCdot, when each is present. *) -(* *) -(* The pragma Lambdify invokes expansion of the operators *) -(* ENABLED and \cdot to an intermediate form with bound VARIABLES, *) -(* which is a form before introducing rigid quantifiers. *) -(* The pragma Lambdify is sound for occurrences of ENABLED and \cdot *) -(* that are not nested. *) -(* *) -(* The pragma ENABLEDaxioms invokes axioms about the operator ENABLED. *) -(* *) -(* The pragma ENABLEDrules invokes two proof rules about the operator *) -(* ENABLED. *) -(* *) -(* The pragma LevelComparison allows proofs that change only the levels *) -(* of declared operators, or rename declared operators. *) -(**************************************************************************) -ExpandENABLED == TRUE (*{ by (prover:"expandenabled") }*) -ExpandCdot == TRUE (*{ by (prover:"expandcdot") }*) -AutoUSE == TRUE (*{ by (prover:"autouse") }*) -Lambdify == TRUE (*{ by (prover:"lambdify") }*) -ENABLEDaxioms == TRUE (*{ by (prover:"enabledaxioms") }*) -ENABLEDrewrites == TRUE (*{ by (prover:"enabledrewrites") }*) -ENABLEDrules == TRUE (*{ by (prover:"enabledrules") }*) -LevelComparison == TRUE (*{ by (prover:"levelcomparison") }*) - -(* The operators EnabledWrapper and CdotWrapper occur in an intermediate *) -(* representation within TLAPM. *) -EnabledWrapper(Op(_)) == FALSE -CdotWrapper(Op(_)) == FALSE - -(***************************************************************************) -(* The following may be used in a `BY ONLY ThmName` for unit testing the *) -(* triviality checks in TLAPM. *) -(***************************************************************************) -Trivial == TRUE (*{ by (prover:"trivial") }*) - - -============================================================================= - -The material below is obsolete: the TLA proof rules below are superseded by -the PTL decision procedure, and their formulation is unsound for the semantics -of temporal reasoning that TLAPS adopts. - ----------------------------------------------------------------------------- -(***************************************************************************) -(* TEMPORAL LOGIC *) -(* *) -(* The following rules are intended to be used when TLAPS handles temporal *) -(* logic. They will not work now. Moreover when temporal reasoning is *) -(* implemented, these rules may be changed or omitted, and additional *) -(* rules will probably be added. However, they are included mainly so *) -(* their names will be defined, preventing the use of identifiers that are *) -(* likely to produce name clashes with future versions of this module. *) -(***************************************************************************) - - -(***************************************************************************) -(* The following proof rules (and their names) are from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleTLA1 == ASSUME STATE P, STATE f, - P /\ (f' = f) => P' - PROVE []P <=> P /\ [][P => P']_f - -THEOREM RuleTLA2 == ASSUME STATE P, STATE Q, STATE f, STATE g, - ACTION A, ACTION B, - P /\ [A]_f => Q /\ [B]_g - PROVE []P /\ [][A]_f => []Q /\ [][B]_g - -THEOREM RuleINV1 == ASSUME STATE I, STATE F, ACTION N, - I /\ [N]_F => I' - PROVE I /\ [][N]_F => []I - -THEOREM RuleINV2 == ASSUME STATE I, STATE f, ACTION N - PROVE []I => ([][N]_f <=> [][N /\ I /\ I']_f) - -THEOREM RuleWF1 == ASSUME STATE P, STATE Q, STATE f, ACTION N, ACTION A, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - P => ENABLED <>_f - PROVE [][N]_f /\ WF_f(A) => (P ~> Q) - -THEOREM RuleSF1 == ASSUME STATE P, STATE Q, STATE f, - ACTION N, ACTION A, TEMPORAL F, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - []P /\ [][N]_f /\ []F => <> ENABLED <>_f - PROVE [][N]_f /\ SF_f(A) /\ []F => (P ~> Q) - -(***************************************************************************) -(* The rules WF2 and SF2 in "The Temporal Logic of Actions" are obtained *) -(* from the following two rules by the following substitutions: `. *) -(* *) -(* ___ ___ _______________ *) -(* M <- M , g <- g , EM <- ENABLED <>_g .' *) -(***************************************************************************) -THEOREM RuleWF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ WF_f(A) /\ []F /\ <>[]EM => <>[]P - PROVE [][N]_f /\ WF_f(A) /\ []F => []<><>_g \/ []<>(~EM) - -THEOREM RuleSF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ SF_f(A) /\ []F /\ []<>EM => <>[]P - PROVE [][N]_f /\ SF_f(A) /\ []F => []<><>_g \/ <>[](~EM) - - -(***************************************************************************) -(* The following rule is a special case of the general temporal logic *) -(* proof rule STL4 from the paper "The Temporal Logic of Actions". The *) -(* general rule is for arbitrary temporal formulas F and G, but it cannot *) -(* yet be handled by TLAPS. *) -(***************************************************************************) -THEOREM RuleInvImplication == - ASSUME STATE F, STATE G, - F => G - PROVE []F => []G -PROOF OMITTED - -(***************************************************************************) -(* The following rule is a special case of rule TLA2 from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleStepSimulation == - ASSUME STATE I, STATE f, STATE g, - ACTION M, ACTION N, - I /\ I' /\ [M]_f => [N]_g - PROVE []I /\ [][M]_f => [][N]_g -PROOF OMITTED - -(***************************************************************************) -(* The following may be used to invoke a decision procedure for *) -(* propositional temporal logic. *) -(***************************************************************************) -PropositionalTemporalLogic == TRUE -============================================================================= diff --git a/specifications/lamport_mutex/Functions.tla b/specifications/lamport_mutex/Functions.tla deleted file mode 100644 index a96195ac..00000000 --- a/specifications/lamport_mutex/Functions.tla +++ /dev/null @@ -1,63 +0,0 @@ ------------------------------- MODULE Functions ----------------------------- -(***************************************************************************) -(* `^{\large\bf \vspace{12pt} *) -(* Notions about functions including injection, surjection, and bijection.*) -(* Originally contributed by Tom Rodeheffer, MSR. *) -(* \vspace{12pt}}^' *) -(***************************************************************************) - - -(***************************************************************************) -(* Restriction of a function to a set (should be a subset of the domain). *) -(***************************************************************************) -Restrict(f,S) == [ x \in S |-> f[x] ] - -(***************************************************************************) -(* Range of a function. *) -(* Note: The image of a set under function f can be defined as *) -(* Range(Restrict(f,S)). *) -(***************************************************************************) -Range(f) == { f[x] : x \in DOMAIN f } - - -(***************************************************************************) -(* The inverse of a function. *) -(***************************************************************************) -Inverse(f,S,T) == [t \in T |-> CHOOSE s \in S : t \in Range(f) => f[s] = t] - - -(***************************************************************************) -(* A map is an injection iff each element in the domain maps to a distinct *) -(* element in the range. *) -(***************************************************************************) -Injection(S,T) == { M \in [S -> T] : \A a,b \in S : M[a] = M[b] => a = b } - - -(***************************************************************************) -(* A map is a surjection iff for each element in the range there is some *) -(* element in the domain that maps to it. *) -(***************************************************************************) -Surjection(S,T) == { M \in [S -> T] : \A t \in T : \E s \in S : M[s] = t } - - -(***************************************************************************) -(* A map is a bijection iff it is both an injection and a surjection. *) -(***************************************************************************) -Bijection(S,T) == Injection(S,T) \cap Surjection(S,T) - - -(***************************************************************************) -(* An injection, surjection, or bijection exists if the corresponding set *) -(* is nonempty. *) -(***************************************************************************) -ExistsInjection(S,T) == Injection(S,T) # {} -ExistsSurjection(S,T) == Surjection(S,T) # {} -ExistsBijection(S,T) == Bijection(S,T) # {} - - -============================================================================= -\* Modification History -\* Last modified Wed Jul 10 20:32:37 CEST 2013 by merz -\* Last modified Wed Jun 05 12:14:19 CEST 2013 by bhargav -\* Last modified Fri May 03 12:55:35 PDT 2013 by tomr -\* Created Thu Apr 11 10:30:48 PDT 2013 by tomr diff --git a/specifications/lamport_mutex/LamportMutex_proofs.tla b/specifications/lamport_mutex/LamportMutex_proofs.tla index ef9157ef..39ef80b4 100644 --- a/specifications/lamport_mutex/LamportMutex_proofs.tla +++ b/specifications/lamport_mutex/LamportMutex_proofs.tla @@ -14,7 +14,7 @@ LEMMA BroadcastType == ASSUME network \in [Proc -> [Proc -> Seq(Message)]], NEW s \in Proc, NEW m \in Message PROVE Broadcast(s,m) \in [Proc -> Seq(Message)] -BY AppendProperties DEF Broadcast +BY DEF Broadcast LEMMA TypeCorrect == Spec => []TypeOK <1>1. Init => TypeOK @@ -59,15 +59,7 @@ LEMMA TypeCorrect == Spec => []TypeOK /\ req' \in [Proc -> [Proc -> Nat]] BY <3>1, <3>3 DEF ReqMessage <3>5. network' \in [Proc -> [Proc -> Seq(Message)]] - <4>. DEFINE nw == [network EXCEPT ![q][p] = Tail(@)] - <4>1. nw \in [Proc -> [Proc -> Seq(Message)]] - BY <3>1 - <4>. HIDE DEF nw - <4>2. AckMessage \in Message - BY DEF Message - <4>3. [nw EXCEPT ![p][q] = Append(@, AckMessage)] \in [Proc -> [Proc -> Seq(Message)]] - BY <4>1, <4>2 - <4>. QED BY <3>1, <4>3, Zenon DEF nw + BY <3>1 DEF Message <3>6. /\ ack' \in [Proc -> SUBSET Proc] /\ crit' \in SUBSET Proc BY <3>1 @@ -81,7 +73,13 @@ LEMMA TypeCorrect == Spec => []TypeOK NEW q \in Proc \ {p}, ReceiveRelease(p,q) PROVE TypeOK' - BY <2>6 DEF ReceiveRelease + \* works -- BY <2>6, SMTT(30) DEF ReceiveRelease + <3>1. /\ network[q][p] # << >> + /\ req' = [req EXCEPT ![p][q] = 0] + /\ network' = [network EXCEPT ![q][p] = Tail(@)] + /\ UNCHANGED <> + BY <2>6 DEF ReceiveRelease + <3>. QED BY <3>1 <2>7. CASE UNCHANGED vars BY <2>7 DEF vars <2>8. QED BY <2>1, <2>2, <2>3, <2>4, <2>5, <2>6, <2>7 DEF Next @@ -122,7 +120,13 @@ LEMMA PrecedesHead == s # << >>, Precedes(s,mt1,mt2), Head(s).type = mt2 PROVE ~ Contains(s,mt1) -BY DEF Precedes, Contains +<1>. SUFFICES ASSUME Contains(s, mt1) PROVE FALSE + OBVIOUS +<1>1. PICK i \in 1 .. Len(s) : s[i].type = mt1 + BY DEF Contains +<1>2. i < 1 + BY <1>1 DEF Precedes +<1>. QED BY <1>1, <1>2 LEMMA AtMostOneTail == ASSUME NEW s \in Seq(Message), NEW mtype, @@ -134,16 +138,19 @@ LEMMA ContainsTail == ASSUME NEW s \in Seq(Message), s # << >>, NEW mtype, AtMostOne(s, mtype) PROVE Contains(Tail(s), mtype) <=> Contains(s, mtype) /\ Head(s).type # mtype -BY DEF Contains, AtMostOne +<1>1. ASSUME Contains(Tail(s), mtype) + PROVE Contains(s, mtype) /\ Head(s).type # mtype + BY <1>1 DEF Contains, AtMostOne +<1>2. ASSUME Contains(s, mtype), Head(s).type # mtype + PROVE Contains(Tail(s), mtype) + BY <1>2 DEF Contains, AtMostOne +<1>. QED BY <1>1, <1>2 LEMMA AtMostOneHead == ASSUME NEW s \in Seq(Message), NEW mtype, AtMostOne(s,mtype), s # << >>, Head(s).type = mtype PROVE ~ Contains(Tail(s), mtype) -<1>. SUFFICES ASSUME NEW i \in 1 .. Len(Tail(s)), Tail(s)[i].type = mtype - PROVE FALSE - BY Tail(s) \in Seq(Message), Isa DEF Contains -<1>. QED BY HeadTailProperties DEF AtMostOne +BY DEF AtMostOne, Contains LEMMA ContainsSend == ASSUME NEW s \in Seq(Message), NEW mtype, NEW m \in Message @@ -166,12 +173,29 @@ LEMMA PrecedesSend == ASSUME NEW s \in Seq(Message), NEW mt1, NEW mt2, NEW m \in Message, m.type # mt1 PROVE Precedes(Append(s,m), mt1, mt2) <=> Precedes(s, mt1, mt2) -BY DEF Precedes +<1>1. ASSUME Precedes(Append(s,m), mt1, mt2) + PROVE Precedes(s, mt1, mt2) + BY <1>1 DEF Precedes +<1>2. ASSUME Precedes(s, mt1, mt2) + PROVE Precedes(Append(s,m), mt1, mt2) + BY <1>2 DEF Precedes +<1>. QED BY <1>1, <1>2 LEMMA PrecedesTail == - ASSUME NEW s \in Seq(Message), NEW mt1, NEW mt2, Precedes(s, mt1, mt2) + ASSUME NEW s \in Seq(Message), s # << >>, + NEW mt1, NEW mt2, Precedes(s, mt1, mt2) PROVE Precedes(Tail(s), mt1, mt2) -BY DEF Precedes +<1>. SUFFICES + ASSUME NEW i \in 1 .. Len(Tail(s)), NEW j \in 1 .. Len(Tail(s)), + Tail(s)[i].type = mt1, Tail(s)[j].type = mt2 + PROVE i < j + BY DEF Precedes +<1>1. /\ i+1 \in 1 .. Len(s) /\ s[i+1].type = mt1 + /\ j+1 \in 1 .. Len(s) /\ s[j+1].type = mt2 + OBVIOUS +<1>2. i+1 < j+1 + BY <1>1 DEF Precedes +<1>. QED BY <1>2 LEMMA PrecedesInTail == ASSUME NEW s \in Seq(Message), s # << >>, @@ -179,7 +203,21 @@ LEMMA PrecedesInTail == Head(s).type = mt1 \/ Head(s).type \notin {mt1, mt2}, Precedes(Tail(s), mt1, mt2) PROVE Precedes(s, mt1, mt2) -BY SMTT(30) DEF Precedes +<1>. SUFFICES + ASSUME NEW i \in 1 .. Len(s), NEW j \in 1 .. Len(s), + s[i].type = mt1, s[j].type = mt2 + PROVE i < j + BY DEF Precedes +<1>1. CASE i = 1 + BY <1>1 +<1>2. CASE i > 1 + <2>1. /\ i-1 \in 1 .. Len(Tail(s)) + /\ Tail(s)[i-1].type = mt1 + /\ j-1 \in 1 .. Len(Tail(s)) + /\ Tail(s)[j-1].type = mt2 + BY <1>2 + <2>. QED BY <2>1 DEF Precedes +<1>. QED BY <1>1, <1>2 ----------------------------------------------------------------------------- (***************************************************************************) @@ -273,8 +311,9 @@ THEOREM BasicInvariant == Spec => []BasicInv BY <3>1, <4>2 <5>. \A q \in Proc : UNCHANGED network[p][q] BY <3>1, <4>2 - <5>. /\ \A q \in Proc \ {n} : UNCHANGED network[q][p] - /\ p = n => UNCHANGED network[n][p] + <5>. \A q \in Proc \ {n} : UNCHANGED network[q][p] + BY <3>1 + <5>. p = n => UNCHANGED network[n][p] BY <3>1, <4>2 DEF Broadcast <5>. n # p => Contains(network'[n][p], "ack") <=> Contains(network[n][p], "ack") BY <3>1, <4>2, ContainsSend DEF Broadcast @@ -315,10 +354,7 @@ THEOREM BasicInvariant == Spec => []BasicInv BY <3>1, <4>1 DEF BasicInv, NetworkInv <5>. QED BY DEF NetworkInv <4>2. CASE p # n - <5>. /\ network'[p][p] = network[p][p] - /\ network'[p][q] = network[p][q] - BY <3>1, <4>2 - <5>. QED BY DEF BasicInv, NetworkInv + BY <3>1, <4>2 DEF BasicInv, NetworkInv <4>. QED BY <4>1, <4>2 <3>3. ASSUME NEW p \in Proc PROVE CommInv(p)' @@ -333,9 +369,7 @@ THEOREM BasicInvariant == Spec => []BasicInv <5>. ASSUME NEW q \in Proc PROVE Contains(network'[q][p], "ack") <=> Contains(network[q][p], "ack") <6>1. CASE n = q - <7>. network'[q][p] = Append(network[q][p], RelMessage) - BY <3>1, <4>2, <6>1 - <7>. QED BY ContainsSend + BY <3>1, <4>2, <6>1, ContainsSend <6>2. CASE n # q BY <3>1, <6>2 <6>. QED BY <6>1, <6>2 @@ -368,14 +402,16 @@ THEOREM BasicInvariant == Spec => []BasicInv BY <3>1, AtMostOneTail, AtMostOneSend, Zenon DEF BasicInv, NetworkInv <4>2. AtMostOne(network'[p][q], "ack") <5>. DEFINE nw == [network EXCEPT ![k][n] = Tail(network[k][n])] - <5>1. /\ nw \in [Proc -> [Proc -> Seq(Message)]] - /\ AtMostOne(nw[p][q], "ack") - /\ ~ Contains(nw[n][k], "ack") - BY <3>1, <3>3, AtMostOneTail DEF BasicInv, NetworkInv + <5>1. nw \in [Proc -> [Proc -> Seq(Message)]] + BY <3>1 + <5>2. AtMostOne(nw[p][q], "ack") + BY <3>1, AtMostOneTail DEF BasicInv, NetworkInv + <5>3. ~ Contains(nw[n][k], "ack") + BY <3>1, <3>3 DEF BasicInv, NetworkInv <5>. HIDE DEF nw <5>. DEFINE nw2 == [nw EXCEPT ![n][k] = Append(network[n][k], AckMessage)] <5>5. AtMostOne(nw2[p][q], "ack") - BY <3>3, <5>1, NotContainsSend + BY <3>3, <5>1, <5>2, <5>3, NotContainsSend <5>. QED BY <3>1, <5>5 DEF nw <4>3. AtMostOne(network'[p][q], "rel") BY <3>1, AtMostOneTail, AtMostOneSend, Zenon DEF BasicInv, NetworkInv @@ -556,7 +592,9 @@ THEOREM ClockInvariant == Spec => []ClockInv <4>1. CASE p = n <5>1. ASSUME NEW i \in 1 .. Len(network'[p][q]), network'[p][q][i].type = "req" PROVE network'[p][q][i].clock = req'[p][p] - BY <3>1, <4>1, <5>1 DEF Broadcast, Contains + <6>. network'[p][q] = Append(network[p][q], ReqMessage(clock[n])) + BY <3>1, <4>1 DEF Broadcast + <6>. QED BY <3>1, <4>1, <5>1 DEF Contains <5>2. ~ Contains(network'[q][p], "ack") /\ q \notin ack'[p] BY <3>1, <4>1 DEF Broadcast <5>3. p \notin crit' @@ -569,14 +607,23 @@ THEOREM ClockInvariant == Spec => []ClockInv BY <3>1, <4>2 <5>. DEFINE qp == network[q][p] <5>3. ASSUME Contains(qp', "ack") \/ q \in ack'[p] - PROVE /\ req'[q][p] = req[p][p] + PROVE /\ req'[q][p] = req'[p][p] /\ clock'[q] > req'[p][p] - /\ Precedes(qp', "ack", "req") => - \A i \in 1 .. Len(qp') : qp'[i].type = "req" => qp'[i].clock > req'[p][p] - <6>. Contains(qp, "ack") \/ q \in ack[p] + /\ \A i \in 1 .. Len(qp') : qp'[i].type = "req" => qp'[i].clock > req'[p][p] + <6>1. Contains(qp, "ack") \/ q \in ack[p] BY <3>1, <4>2, <5>3, ContainsSend DEF Broadcast - <6>. QED - BY <3>1, <4>2, <5>1 DEF ClockInvInner, Broadcast, Contains + <6>3. /\ req'[q][p] = req'[p][p] + /\ clock'[q] > req'[p][p] + BY <3>1, <4>2, <5>1, <6>1 DEF ClockInvInner \* <3>1, <4>2, <6>2 + <6>4. SUFFICES + ASSUME NEW i \in 1 .. Len(qp'), qp'[i].type = "req" + PROVE qp'[i].clock > req'[p][p] + BY <6>3 + <6>5. qp' = Append(qp, ReqMessage(clock[n])) + BY <3>1, <4>2 DEF Broadcast + <6>7. qp'[i] = ReqMessage(clock[n]) + BY <3>1, <4>2, <6>4, <6>5 DEF Contains + <6>. QED BY <3>1, <4>2, <6>3, <6>7 DEF ReqMessage <5>. QED BY <5>1, <5>2, <5>3 DEF ClockInvInner, beats <4>3. CASE n \notin {p,q} \* all relevant variables unchanged BY <3>1, <4>3 DEF ClockInv, ClockInvInner, beats @@ -607,8 +654,17 @@ THEOREM ClockInvariant == Spec => []ClockInv BY DEF RelMessage, Message <3>2. ASSUME NEW p \in Proc, NEW q \in Proc \ {p} PROVE ClockInvInner(p,q)' - <4>1. CASE n = p - BY <3>1, <4>1 DEF Broadcast, ClockInvInner, Contains + <4>. DEFINE pq == network[p][q] qp == network[q][p] + <4>1. CASE p = n + \* BY <3>1, <4>1 DEF ClockInvInner, Broadcast, Contains, RelMessage -- works + <5>1. ASSUME NEW i \in 1 .. Len(pq'), pq'[i].type = "req" + PROVE pq'[i].clock = req'[p][p] + BY <3>1, <4>1, <5>1 DEF Broadcast, Contains + <5>2. ~(Contains(qp, "ack")' \/ q \in ack'[p]) + BY <3>1, <4>1 DEF Broadcast, Contains, RelMessage + <5>3. p \in crit' => beats(p,q)' + BY <3>1, <4>1 + <5>. QED BY <5>1, <5>2, <5>3 DEF ClockInvInner <4>2. CASE n # p <5>1. /\ UNCHANGED << network[p][q], req[p][p], req[q][p], req[p][q], ack[p], clock >> /\ p \in crit' <=> p \in crit @@ -619,7 +675,7 @@ THEOREM ClockInvariant == Spec => []ClockInv /\ Precedes(network'[n][p], "ack", "req") <=> Precedes(network[n][p], "ack", "req") BY <3>1, <4>2, ContainsSend, PrecedesSend DEF Broadcast <5>4. \A i \in 1 .. Len(network'[n][p]) : network'[n][p][i].type # "req" - BY <3>1 DEF Broadcast, Contains + BY <3>1 DEF Broadcast, Contains, RelMessage <5>. QED BY <5>1, <5>2, <5>3, <5>4 DEF ClockInv, ClockInvInner, beats <4>. QED BY <4>1, <4>2 <3>. QED BY <3>2 DEF ClockInv @@ -636,8 +692,10 @@ THEOREM ClockInvariant == Spec => []ClockInv /\ UNCHANGED <> /\ Contains(network[k][n], "req") BY <2>4 DEF ReceiveRequest, ClockInv, ClockInvInner, Contains + <3>a. ClockInvInner(k,n) + BY DEF ClockInv <3>2. m.clock = req[k][k] - BY <3>1 DEF ClockInv, ClockInvInner, Contains + BY <3>1, <3>a DEF ClockInv, ClockInvInner <3>3. /\ req[k][k] > 0 /\ n \notin ack[k] /\ k \notin crit BY <3>1 DEF BasicInv, CommInv @@ -661,19 +719,25 @@ THEOREM ClockInvariant == Spec => []ClockInv /\ q \notin ack'[p] /\ p \notin crit' BY <3>1, <3>2, <3>3, <4>1 - <5>5. ASSUME Precedes(qp', "ack", "req"), + <5>5. ASSUME Precedes(qp', "ack", "req"), NEW i \in 1 .. Len(qp'), qp'[i].type = "req" PROVE FALSE - BY <3>1, <4>1, <5>5 DEF Precedes + <6>1. ~(Len(qp') < i) + BY <3>1, <4>1, <5>5 + <6>2. /\ Len(qp') \in 1 .. Len(qp') + /\ qp'[Len(qp')].type = "ack" + BY <3>1, <4>1 + <6>. QED BY <5>5, <6>1, <6>2 DEF Precedes <5>. QED BY <5>2, <5>3, <5>4, <5>5 DEF ClockInvInner, Contains <4>2. CASE p = k /\ q # n BY <3>1, <4>2 DEF ClockInvInner, beats <4>3. CASE p = n /\ q = k - <5>1. UNCHANGED << req[q][p], clock[q], ack >> + <5>1. /\ pq' = Append(pq, AckMessage) + /\ UNCHANGED << req[q][p], clock[q], ack >> BY <3>1, <4>3 <5>2. ASSUME NEW i \in 1 .. Len(pq'), pq'[i].type = "req" PROVE i \in 1 .. Len(pq) /\ pq'[i] = pq[i] - BY <3>1, <4>3, <5>2 + BY <5>1, <5>2 <5>3. qp' = Tail(qp) /\ Head(qp).type = "req" /\ qp # << >> BY <3>1, <4>3, Zenon <5>4. Contains(qp', "ack") <=> Contains(qp, "ack") @@ -750,7 +814,7 @@ THEOREM ClockInvariant == Spec => []ClockInv /\ network' = [network EXCEPT ![k][n] = Tail(@)] /\ UNCHANGED << clock, ack, crit >> /\ Contains(network[k][n], "rel") - BY <2>6 DEF ReceiveRelease, Contains\*, BasicInv, CommInv, Contains + BY <2>6 DEF ReceiveRelease, Contains <3>2. /\ ~ Contains(network[n][k], "ack") /\ n \notin ack[k] BY <3>1, Zenon DEF BasicInv, CommInv diff --git a/specifications/lamport_mutex/NaturalsInduction.tla b/specifications/lamport_mutex/NaturalsInduction.tla deleted file mode 100644 index 21985347..00000000 --- a/specifications/lamport_mutex/NaturalsInduction.tla +++ /dev/null @@ -1,210 +0,0 @@ -------------------------- MODULE NaturalsInduction ------------------------- -(***************************************************************************) -(* This module contains useful theorems for inductive proofs and recursive *) -(* definitions over the naturals. *) -(* *) -(* Some of the statements of the theorems are decomposed in terms of *) -(* definitions. This is done for two reasons: *) -(* *) -(* - It makes it easier for the backends to instantiate the theorems *) -(* when those definitions are not expanded. *) -(* *) -(* - It can be convenient when writing proofs to use those definitions *) -(* rather than having to write out their expansions. *) -(* *) -(* The proofs of these theorems appear in module NaturalsInduction\_proofs.*) -(***************************************************************************) -EXTENDS Integers, TLAPS - -(***************************************************************************) -(* The following is the simple statement of inductions over the naturals. *) -(* For predicates P defined by a moderately complex operator, it is often *) -(* useful to hide the operator definition before using this theorem. That *) -(* is, you first define a suitable operator P (not necessarily by that *) -(* name), prove the two hypotheses of the theorem, and then hide the *) -(* definition of P when using the theorem. *) -(***************************************************************************) -THEOREM NatInduction == - ASSUME NEW P(_), - P(0), - \A n \in Nat : P(n) => P(n+1) - PROVE \A n \in Nat : P(n) - -(***************************************************************************) -(* A useful corollary of NatInduction *) -(***************************************************************************) -THEOREM DownwardNatInduction == - ASSUME NEW P(_), NEW m \in Nat, P(m), - \A n \in 1 .. m : P(n) => P(n-1) - PROVE P(0) - -(***************************************************************************) -(* The following theorem expresses a stronger induction principle, *) -(* also known as course-of-values induction, where the induction *) -(* hypothesis is available for all strictly smaller natural numbers. *) -(***************************************************************************) -THEOREM GeneralNatInduction == - ASSUME NEW P(_), - \A n \in Nat : (\A m \in 0..(n-1) : P(m)) => P(n) - PROVE \A n \in Nat : P(n) - -(***************************************************************************) -(* The following theorem expresses the ``least-number principle'': *) -(* if P(n) is true for some natural number n then there is a *) -(* smallest natural number for which P is true. It could be derived in *) -(* module WellFoundedInduction as a corollary of the fact that the natural *) -(* numbers are well ordered, but we give a direct proof. *) -(***************************************************************************) -THEOREM SmallestNatural == - ASSUME NEW P(_), NEW n \in Nat, P(n) - PROVE \E m \in Nat : /\ P(m) - /\ \A k \in 0 .. m-1 : ~ P(k) - -(***************************************************************************) -(* The following theorem says that a recursively defined function f over *) -(* the natural numbers is well-defined if for every n \in Nat the *) -(* definition of f[n] depends only on arguments smaller than n. *) -(***************************************************************************) -THEOREM RecursiveFcnOfNat == - ASSUME NEW Def(_,_), - ASSUME NEW n \in Nat, NEW g, NEW h, - \A i \in 0..(n-1) : g[i] = h[i] - PROVE Def(g, n) = Def(h, n) - PROVE LET f[n \in Nat] == Def(f, n) - IN f = [n \in Nat |-> Def(f, n)] - - -(***************************************************************************) -(* The following theorem NatInductiveDef is what you use to justify a *) -(* function defined by primitive recursion over the naturals. *) -(***************************************************************************) -NatInductiveDefHypothesis(f, f0, Def(_,_)) == - (f = CHOOSE g : g = [i \in Nat |-> IF i = 0 THEN f0 ELSE Def(g[i-1], i)]) -NatInductiveDefConclusion(f, f0, Def(_,_)) == - f = [i \in Nat |-> IF i = 0 THEN f0 ELSE Def(f[i-1], i)] - -THEOREM NatInductiveDef == - ASSUME NEW Def(_,_), NEW f, NEW f0, - NatInductiveDefHypothesis(f, f0, Def) - PROVE NatInductiveDefConclusion(f, f0, Def) - - -(***************************************************************************) -(* The following two theorems allow you to prove the type of a recursively *) -(* defined function over the natural numbers. *) -(***************************************************************************) -THEOREM RecursiveFcnOfNatType == - ASSUME NEW f, NEW S, NEW Def(_,_), f = [n \in Nat |-> Def(f,n)], - ASSUME NEW n \in Nat, NEW g, \A i \in 0 .. n-1 : g[i] \in S - PROVE Def(g,n) \in S - PROVE f \in [Nat -> S] - -THEOREM NatInductiveDefType == - ASSUME NEW Def(_,_), NEW S, NEW f, NEW f0 \in S, - NatInductiveDefConclusion(f, f0, Def), - f0 \in S, - \A v \in S, n \in Nat \ {0} : Def(v, n) \in S - PROVE f \in [Nat -> S] - -(***************************************************************************) -(* The following theorems show uniqueness of functions recursively defined *) -(* over Nat. *) -(***************************************************************************) -THEOREM RecursiveFcnOfNatUnique == - ASSUME NEW Def(_,_), NEW f, NEW g, - f = [n \in Nat |-> Def(f,n)], - g = [n \in Nat |-> Def(g,n)], - ASSUME NEW n \in Nat, NEW ff, NEW gg, - \A i \in 0..(n-1) : ff[i] = gg[i] - PROVE Def(ff, n) = Def(gg, n) - PROVE f = g - -THEOREM NatInductiveUnique == - ASSUME NEW Def(_,_), NEW f, NEW g, NEW f0, - NatInductiveDefConclusion(f, f0, Def), - NatInductiveDefConclusion(g, f0, Def) - PROVE f = g - -(***************************************************************************) -(* The following theorems are analogous to the preceding ones but for *) -(* functions defined over intervals of natural numbers. *) -(***************************************************************************) - -FiniteNatInductiveDefHypothesis(f, c, Def(_,_), m, n) == - (f = CHOOSE g : g = [i \in m..n |-> IF i = m THEN c ELSE Def(g[i-1], i)]) -FiniteNatInductiveDefConclusion(f, c, Def(_,_), m, n) == - f = [i \in m..n |-> IF i = m THEN c ELSE Def(f[i-1], i)] - -THEOREM FiniteNatInductiveDef == - ASSUME NEW Def(_,_), NEW f, NEW c, NEW m \in Nat, NEW n \in Nat, - FiniteNatInductiveDefHypothesis(f, c, Def, m, n) - PROVE FiniteNatInductiveDefConclusion(f, c, Def, m, n) - -THEOREM FiniteNatInductiveDefType == - ASSUME NEW S, NEW Def(_,_), NEW f, NEW c \in S, NEW m \in Nat, NEW n \in Nat, - FiniteNatInductiveDefConclusion(f, c, Def, m, n), - \A v \in S, i \in (m+1) .. n : Def(v,i) \in S - PROVE f \in [m..n -> S] - -THEOREM FiniteNatInductiveUnique == - ASSUME NEW Def(_,_), NEW f, NEW g, NEW c, NEW m \in Nat, NEW n \in Nat, - FiniteNatInductiveDefConclusion(f, c, Def, m, n), - FiniteNatInductiveDefConclusion(g, c, Def, m, n) - PROVE f = g - -============================================================================= -(***************************************************************************) -(* The following theorems are analogous to the preceding ones but for *) -(* functions defined over intervals of natural numbers. *) -(***************************************************************************) - -FiniteNatInductiveDefHypothesis(f, c, Def(_,_), m, n) == - (f = CHOOSE g : g = [i \in m..n |-> IF i = m THEN c ELSE Def(g[i-1], i)]) -FiniteNatInductiveDefConclusion(f, c, Def(_,_), m, n) == - f = [i \in m..n |-> IF i = m THEN c ELSE Def(f[i-1], i)] - -THEOREM FiniteNatInductiveDef == - ASSUME NEW Def(_,_), NEW f, NEW c, NEW m \in Nat, NEW n \in Nat, - FiniteNatInductiveDefHypothesis(f, c, Def, m, n) - PROVE FiniteNatInductiveDefConclusion(f, c, Def, m, n) - -THEOREM FiniteNatInductiveDefType == - ASSUME NEW S, NEW Def(_,_), NEW f, NEW c \in S, NEW m \in Nat, NEW n \in Nat, - FiniteNatInductiveDefConclusion(f, c, Def, m, n), - \A v \in S, i \in (m+1) .. n : Def(v,i) \in S - PROVE f \in [m..n -> S] - -THEOREM FiniteNatInductiveUnique == - ASSUME NEW Def(_,_), NEW f, NEW g, NEW c, NEW m \in Nat, NEW n \in Nat, - FiniteNatInductiveDefConclusion(f, c, Def, m, n), - FiniteNatInductiveDefConclusion(g, c, Def, m, n) - PROVE f = g - -(***************************************************************************) -(* The following example shows how this module is used. *) -(***************************************************************************) - -factorial[n \in Nat] == IF n = 0 THEN 1 ELSE n * factorial[n-1] - -THEOREM FactorialDefConclusion == NatInductiveDefConclusion(factorial, 1, LAMBDA v,n : n*v) -<1>1. NatInductiveDefHypothesis(factorial, 1, LAMBDA v,n : n*v) - BY DEF NatInductiveDefHypothesis, factorial -<1>2. QED - BY <1>1, NatInductiveDef - -THEOREM FactorialDef == \A n \in Nat : factorial[n] = IF n = 0 THEN 1 ELSE n * factorial[n-1] -BY FactorialDefConclusion DEFS NatInductiveDefConclusion - -THEOREM FactorialType == factorial \in [Nat -> Nat] -<1>1. \A v \in Nat, n \in Nat \ {0} : n * v \in Nat - OBVIOUS -<1>2. QED - BY <1>1, 1 \in Nat, NatInductiveDefType, FactorialDefConclusion, Isa - -============================================================================= -\* Modification History -\* Last modified Thu May 08 12:29:46 CEST 2014 by merz -\* Last modified Tue Oct 15 12:06:48 CEST 2013 by shaolin -\* Last modified Sat Nov 26 08:49:59 CET 2011 by merz -\* Last modified Mon Nov 07 08:58:05 PST 2011 by lamport -\* Created Mon Oct 31 02:52:05 PDT 2011 by lamport diff --git a/specifications/lamport_mutex/SequenceTheorems.tla b/specifications/lamport_mutex/SequenceTheorems.tla deleted file mode 100644 index 889e2536..00000000 --- a/specifications/lamport_mutex/SequenceTheorems.tla +++ /dev/null @@ -1,655 +0,0 @@ ------------------------ MODULE SequenceTheorems ----------------------------- -(***************************************************************************) -(* This module contains a library of theorems about sequences and the *) -(* corresponding operations. *) -(***************************************************************************) -EXTENDS Sequences, Integers, WellFoundedInduction, Functions, TLAPS - - -(***************************************************************************) -(* Elementary properties about Seq(S) *) -(***************************************************************************) - -LEMMA SeqDef == \A S : Seq(S) = UNION {[1..n -> S] : n \in Nat} - -THEOREM ElementOfSeq == - ASSUME NEW S, NEW seq \in Seq(S), - NEW n \in 1..Len(seq) - PROVE seq[n] \in S - -THEOREM EmptySeq == - ASSUME NEW S - PROVE /\ << >> \in Seq(S) - /\ \A seq \in Seq(S) : (seq = << >>) <=> (Len(seq) = 0) - -THEOREM LenProperties == - ASSUME NEW S, NEW seq \in Seq(S) - PROVE /\ Len(seq) \in Nat - /\ seq \in [1..Len(seq) -> S] - /\ DOMAIN seq = 1 .. Len(seq) - -THEOREM ExceptSeq == - ASSUME NEW S, NEW seq \in Seq(S), NEW i \in 1 .. Len(seq), NEW e \in S - PROVE /\ [seq EXCEPT ![i] = e] \in Seq(S) - /\ Len([seq EXCEPT ![i] = e]) = Len(seq) - /\ \A j \in 1 .. Len(seq) : [seq EXCEPT ![i] = e][j] = IF j=i THEN e ELSE seq[j] - -THEOREM IsASeq == - ASSUME NEW n \in Nat, NEW e(_), NEW S, - \A i \in 1..n : e(i) \in S - PROVE [i \in 1..n |-> e(i)] \in Seq(S) - -THEOREM SeqEqual == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), - Len(s) = Len(t), \A i \in 1 .. Len(s) : s[i] = t[i] - PROVE s = t - -(*************************************************************************** - Concatenation (\o) And Properties -***************************************************************************) - -THEOREM ConcatProperties == - ASSUME NEW S, NEW s1 \in Seq(S), NEW s2 \in Seq(S) - PROVE /\ s1 \o s2 \in Seq(S) - /\ Len(s1 \o s2) = Len(s1) + Len(s2) - /\ \A i \in 1 .. Len(s1) + Len(s2) : (s1 \o s2)[i] = - IF i <= Len(s1) THEN s1[i] ELSE s2[i - Len(s1)] - -THEOREM ConcatEmptySeq == - ASSUME NEW S, NEW seq \in Seq(S) - PROVE /\ seq \o << >> = seq - /\ << >> \o seq = seq - -THEOREM ConcatAssociative == - ASSUME NEW S, NEW s1 \in Seq(S), NEW s2 \in Seq(S), NEW s3 \in Seq(S) - PROVE (s1 \o s2) \o s3 = s1 \o (s2 \o s3) - -THEOREM ConcatSimplifications == - ASSUME NEW S - PROVE /\ \A s,t \in Seq(S) : s \o t = s <=> t = <<>> - /\ \A s,t \in Seq(S) : s \o t = t <=> s = <<>> - /\ \A s,t \in Seq(S) : s \o t = <<>> <=> s = <<>> /\ t = <<>> - /\ \A s,t,u \in Seq(S) : s \o t = s \o u <=> t = u - /\ \A s,t,u \in Seq(S) : s \o u = t \o u <=> s = t - -(***************************************************************************) -(* SubSeq, Head and Tail *) -(***************************************************************************) - -THEOREM SubSeqProperties == - ASSUME NEW S, - NEW s \in Seq(S), - NEW m \in 1 .. Len(s)+1, - NEW n \in m-1 .. Len(s) - PROVE /\ SubSeq(s,m,n) \in Seq(S) - /\ Len(SubSeq(s, m, n)) = n-m+1 - /\ \A i \in 1 .. n-m+1 : SubSeq(s,m,n)[i] = s[m+i-1] - -THEOREM SubSeqEmpty == - ASSUME NEW s, NEW m \in Int, NEW n \in Int, n < m - PROVE SubSeq(s,m,n) = << >> - -THEOREM HeadTailProperties == - ASSUME NEW S, - NEW seq \in Seq(S), seq # << >> - PROVE /\ Head(seq) \in S - /\ Tail(seq) \in Seq(S) - /\ Len(Tail(seq)) = Len(seq)-1 - /\ \A i \in 1 .. Len(Tail(seq)) : Tail(seq)[i] = seq[i+1] - -THEOREM TailIsSubSeq == - ASSUME NEW S, - NEW seq \in Seq(S), seq # << >> - PROVE Tail(seq) = SubSeq(seq, 2, Len(seq)) - -THEOREM SubSeqRestrict == - ASSUME NEW S, NEW seq \in Seq(S), NEW n \in 0 .. Len(seq) - PROVE SubSeq(seq, 1, n) = Restrict(seq, 1 .. n) - -THEOREM HeadTailOfSubSeq == - ASSUME NEW S, NEW seq \in Seq(S), - NEW m \in 1 .. Len(seq), NEW n \in m .. Len(seq) - PROVE /\ Head(SubSeq(seq,m,n)) = seq[m] - /\ Tail(SubSeq(seq,m,n)) = SubSeq(seq, m+1, n) - -THEOREM SubSeqRecursiveFirst == - ASSUME NEW S, NEW seq \in Seq(S), - NEW m \in 1 .. Len(seq), NEW n \in m .. Len(seq) - PROVE SubSeq(seq, m, n) = << seq[m] >> \o SubSeq(seq, m+1, n) - -THEOREM SubSeqRecursiveSecond == - ASSUME NEW S, NEW seq \in Seq(S), - NEW m \in 1 .. Len(seq), NEW n \in m .. Len(seq) - PROVE SubSeq(seq, m, n) = SubSeq(seq, m, n-1) \o << seq[n] >> - -LEMMA SubSeqOfSubSeq == - ASSUME NEW S, NEW s \in Seq(S), - NEW m \in 1 .. Len(s)+1, - NEW n \in m-1 .. Len(s), - NEW i \in 1 .. n-m+2, - NEW j \in i-1 .. n-m+1 - PROVE SubSeq( SubSeq(s,m,n), i, j ) = SubSeq(s, m+i-1, m+j-1) - -THEOREM SubSeqFull == - ASSUME NEW S, NEW seq \in Seq(S) - PROVE SubSeq(seq, 1, Len(seq)) = seq - -(*****************************************************************************) -(* Adjacent subsequences can be concatenated to obtain a longer subsequence. *) -(*****************************************************************************) -THEOREM ConcatAdjacentSubSeq == - ASSUME NEW S, NEW seq \in Seq(S), - NEW m \in 1 .. Len(seq)+1, - NEW k \in m-1 .. Len(seq), - NEW n \in k .. Len(seq) - PROVE SubSeq(seq, m, k) \o SubSeq(seq, k+1, n) = SubSeq(seq, m, n) - -(***************************************************************************) -(* Append, InsertAt, Cons & RemoveAt *) -(* Append(seq, elt) appends element elt at the end of sequence seq *) -(* Cons(elt, seq) prepends element elt at the beginning of sequence seq *) -(* InsertAt(seq, i, elt) inserts element elt in the position i and pushes *) -(* the *) -(* original element at i to i+1 and so on *) -(* RemoveAt(seq, i) removes the element at position i *) -(***************************************************************************) - -THEOREM AppendProperties == - ASSUME NEW S, NEW seq \in Seq(S), NEW elt \in S - PROVE /\ Append(seq, elt) \in Seq(S) - /\ Append(seq, elt) # << >> - /\ Len(Append(seq, elt)) = Len(seq)+1 - /\ \A i \in 1.. Len(seq) : Append(seq, elt)[i] = seq[i] - /\ Append(seq, elt)[Len(seq)+1] = elt - -THEOREM AppendIsConcat == - ASSUME NEW S, NEW seq \in Seq(S), NEW elt \in S - PROVE Append(seq, elt) = seq \o <> - -THEOREM HeadTailAppend == - ASSUME NEW S, NEW seq \in Seq(S), NEW elt - PROVE /\ Head(Append(seq, elt)) = IF seq = <<>> THEN elt ELSE Head(seq) - /\ Tail(Append(seq, elt)) = IF seq = <<>> THEN <<>> ELSE Append(Tail(seq), elt) - -Cons(elt, seq) == <> \o seq - -THEOREM ConsProperties == - ASSUME NEW S, NEW seq \in Seq(S), NEW elt \in S - PROVE /\ Cons(elt, seq) \in Seq(S) - /\ Cons(elt, seq) # <<>> - /\ Len(Cons(elt, seq)) = Len(seq)+1 - /\ Head(Cons(elt, seq)) = elt - /\ Tail(Cons(elt, seq)) = seq - /\ Cons(elt, seq)[1] = elt - /\ \A i \in 1 .. Len(seq) : Cons(elt, seq)[i+1] = seq[i] - -THEOREM ConsEmpty == - \A x : Cons(x, << >>) = << x >> - -THEOREM ConsHeadTail == - ASSUME NEW S, NEW seq \in Seq(S), seq # << >> - PROVE Cons(Head(seq), Tail(seq)) = seq - -THEOREM ConsAppend == - ASSUME NEW S, NEW seq \in Seq(S), NEW x \in S, NEW y \in S - PROVE Cons(x, Append(seq, y)) = Append(Cons(x,seq), y) - -THEOREM ConsInjective == - ASSUME NEW S, NEW e \in S, NEW s \in Seq(S), NEW f \in S, NEW t \in Seq(S) - PROVE Cons(e,s) = Cons(f,t) <=> e = f /\ s = t - -InsertAt(seq,i,elt) == SubSeq(seq, 1, i-1) \o <> \o SubSeq(seq, i, Len(seq)) - -THEOREM InsertAtProperties == - ASSUME NEW S, NEW seq \in Seq(S), NEW i \in 1 .. Len(seq)+1, NEW elt \in S - PROVE /\ InsertAt(seq,i,elt) \in Seq(S) - /\ Len(InsertAt(seq,i,elt)) = Len(seq)+1 - /\ \A j \in 1 .. Len(seq)+1 : InsertAt(seq,i,elt)[j] = - IF j> THEN 0 ELSE Len(seq)-1 - /\ \A i \in 1 .. Len(seq)-1 : Front(seq)[i] = seq[i] - -THEOREM FrontOfEmpty == Front(<< >>) = << >> - -THEOREM LastProperties == - ASSUME NEW S, NEW seq \in Seq(S), seq # << >> - PROVE /\ Last(seq) \in S - /\ Append(Front(seq), Last(seq)) = seq - -THEOREM FrontLastOfSubSeq == - ASSUME NEW S, NEW seq \in Seq(S), - NEW m \in 1 .. Len(seq), NEW n \in m .. Len(seq) - PROVE /\ Front(SubSeq(seq,m,n)) = SubSeq(seq, m, n-1) - /\ Last(SubSeq(seq,m,n)) = seq[n] - -THEOREM FrontLastAppend == - ASSUME NEW S, NEW seq \in Seq(S), NEW e \in S - PROVE /\ Front(Append(seq, e)) = seq - /\ Last(Append(seq, e)) = e - -THEOREM AppendInjective == - ASSUME NEW S, NEW e \in S, NEW s \in Seq(S), NEW f \in S, NEW t \in Seq(S) - PROVE Append(s,e) = Append(t,f) <=> s = t /\ e = f - -(***************************************************************************) -(* As a corollary of the previous theorems it follows that a sequence is *) -(* either empty or can be obtained by appending an element to a sequence. *) -(***************************************************************************) -THEOREM SequenceEmptyOrAppend == - ASSUME NEW S, NEW seq \in Seq(S), seq # << >> - PROVE \E s \in Seq(S), elt \in S : seq = Append(s, elt) - -(***************************************************************************) -(* REVERSE SEQUENCE And Properties *) -(* Reverse(seq) --> Reverses the sequence seq *) -(***************************************************************************) - -Reverse(seq) == [j \in 1 .. Len(seq) |-> seq[Len(seq)-j+1] ] - -THEOREM ReverseProperties == - ASSUME NEW S, NEW seq \in Seq(S) - PROVE /\ Reverse(seq) \in Seq(S) - /\ Len(Reverse(seq)) = Len(seq) - /\ Reverse(Reverse(seq)) = seq - -THEOREM ReverseEmpty == Reverse(<< >>) = << >> - -THEOREM ReverseEqual == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), Reverse(s) = Reverse(t) - PROVE s = t - -THEOREM ReverseEmptyIffEmpty == - ASSUME NEW S, NEW seq \in Seq(S), Reverse(seq) = <<>> - PROVE seq = <<>> - -THEOREM ReverseConcat == - ASSUME NEW S, NEW s1 \in Seq(S), NEW s2 \in Seq(S) - PROVE Reverse(s1 \o s2) = Reverse(s2) \o Reverse(s1) - -THEOREM ReverseAppend == - ASSUME NEW S, NEW seq \in Seq(S), NEW e \in S - PROVE Reverse(Append(seq,e)) = Cons(e, Reverse(seq)) - -THEOREM ReverseCons == - ASSUME NEW S, NEW seq \in Seq(S), NEW e \in S - PROVE Reverse(Cons(e,seq)) = Append(Reverse(seq), e) - -THEOREM ReverseSingleton == \A x : Reverse(<< x >>) = << x >> - -THEOREM ReverseSubSeq == - ASSUME NEW S, NEW seq \in Seq(S), - NEW m \in 1..Len(seq), NEW n \in 1..Len(seq) - PROVE Reverse(SubSeq(seq, m , n)) = SubSeq(Reverse(seq), Len(seq)-n+1, Len(seq)-m+1) - -THEOREM ReversePalindrome == - ASSUME NEW S, NEW seq \in Seq(S), - Reverse(seq) = seq - PROVE Reverse(seq \o seq) = seq \o seq - -THEOREM LastEqualsHeadReverse == - ASSUME NEW S, NEW seq \in Seq(S), seq # << >> - PROVE Last(seq) = Head(Reverse(seq)) - -THEOREM ReverseFrontEqualsTailReverse == - ASSUME NEW S, NEW seq \in Seq(S), seq # << >> - PROVE Reverse(Front(seq)) = Tail(Reverse(seq)) - -(***************************************************************************) -(* Induction principles for sequences *) -(***************************************************************************) - -THEOREM SequencesInductionAppend == - ASSUME NEW P(_), NEW S, - P(<< >>), - \A s \in Seq(S), e \in S : P(s) => P(Append(s,e)) - PROVE \A seq \in Seq(S) : P(seq) - -THEOREM SequencesInductionCons == - ASSUME NEW P(_), NEW S, - P(<< >>), - \A s \in Seq(S), e \in S : P(s) => P(Cons(e,s)) - PROVE \A seq \in Seq(S) : P(seq) - -(***************************************************************************) -(* RANGE OF SEQUENCE *) -(***************************************************************************) - -THEOREM RangeOfSeq == - ASSUME NEW S, NEW seq \in Seq(S) - PROVE Range(seq) \in SUBSET S - -THEOREM RangeEquality == - ASSUME NEW S, NEW seq \in Seq(S) - PROVE Range(seq) = { seq[i] : i \in 1 .. Len(seq) } - -(* The range of the reverse sequence equals that of the original one. *) -THEOREM RangeReverse == - ASSUME NEW S, NEW seq \in Seq(S) - PROVE Range(Reverse(seq)) = Range(seq) - -(* Range of concatenation of sequences is the union of the ranges *) -THEOREM RangeConcatenation == - ASSUME NEW S, NEW s1 \in Seq(S), NEW s2 \in Seq(S) - PROVE Range(s1 \o s2) = Range(s1) \cup Range(s2) - -(***************************************************************************) -(* Prefixes and suffixes of sequences. *) -(***************************************************************************) - -IsPrefix(s,t) == \E u \in Seq(Range(t)) : t = s \o u -IsStrictPrefix(s,t) == IsPrefix(s,t) /\ s # t - -IsSuffix(s,t) == \E u \in Seq(Range(t)) : t = u \o s -IsStrictSuffix(s,t) == IsSuffix(s,t) /\ s # t - -(***************************************************************************) -(* The following theorem gives three alternative characterizations of *) -(* prefixes. It also implies that any prefix of a sequence t is at most *) -(* as long as t. *) -(***************************************************************************) -THEOREM IsPrefixProperties == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE /\ IsPrefix(s,t) <=> \E u \in Seq(S) : t = s \o u - /\ IsPrefix(s,t) <=> Len(s) <= Len(t) /\ s = SubSeq(t, 1, Len(s)) - /\ IsPrefix(s,t) <=> Len(s) <= Len(t) /\ s = Restrict(t, DOMAIN s) - -THEOREM IsStrictPrefixProperties == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE /\ IsStrictPrefix(s,t) <=> \E u \in Seq(S) : u # << >> /\ t = s \o u - /\ IsStrictPrefix(s,t) <=> Len(s) < Len(t) /\ s = SubSeq(t, 1, Len(s)) - /\ IsStrictPrefix(s,t) <=> Len(s) < Len(t) /\ s = Restrict(t, DOMAIN s) - /\ IsStrictPrefix(s,t) <=> IsPrefix(s,t) /\ Len(s) < Len(t) - -THEOREM IsPrefixElts == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), NEW i \in 1 .. Len(s), - IsPrefix(s,t) - PROVE s[i] = t[i] - -THEOREM EmptyIsPrefix == - ASSUME NEW S, NEW s \in Seq(S) - PROVE /\ IsPrefix(<<>>, s) - /\ IsPrefix(s, <<>>) <=> s = <<>> - /\ IsStrictPrefix(<<>>, s) <=> s # <<>> - /\ ~ IsStrictPrefix(s, <<>>) - -THEOREM IsPrefixConcat == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE IsPrefix(s, s \o t) - -THEOREM IsPrefixAppend == - ASSUME NEW S, NEW s \in Seq(S), NEW e \in S - PROVE IsPrefix(s, Append(s,e)) - -THEOREM FrontIsPrefix == - ASSUME NEW S, NEW s \in Seq(S) - PROVE /\ IsPrefix(Front(s), s) - /\ s # <<>> => IsStrictPrefix(Front(s), s) - -LEMMA RangeIsPrefix == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), - IsPrefix(s,t) - PROVE Range(s) \subseteq Range(t) - -LEMMA IsPrefixMap == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), IsPrefix(s,t), - NEW Op(_) - PROVE IsPrefix([i \in DOMAIN s |-> Op(s[i])], - [i \in DOMAIN t |-> Op(t[i])]) - -(***************************************************************************) -(* (Strict) prefixes on sequences form a (strict) partial order, and *) -(* the strict ordering is well-founded. *) -(***************************************************************************) -THEOREM IsPrefixPartialOrder == - ASSUME NEW S - PROVE /\ \A s \in Seq(S) : IsPrefix(s,s) - /\ \A s,t \in Seq(S) : IsPrefix(s,t) /\ IsPrefix(t,s) => s = t - /\ \A s,t,u \in Seq(S) : IsPrefix(s,t) /\ IsPrefix(t,u) => IsPrefix(s,u) - -THEOREM ConcatIsPrefix == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), NEW u \in Seq(S), - IsPrefix(s \o t, u) - PROVE IsPrefix(s, u) - -THEOREM ConcatIsPrefixCancel == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), NEW u \in Seq(S) - PROVE IsPrefix(s \o t, s \o u) <=> IsPrefix(t, u) - -THEOREM ConsIsPrefixCancel == - ASSUME NEW S, NEW e \in S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE IsPrefix(Cons(e,s), Cons(e,t)) <=> IsPrefix(s,t) - -THEOREM ConsIsPrefix == - ASSUME NEW S, NEW e \in S, NEW s \in Seq(S), NEW u \in Seq(S), - IsPrefix(Cons(e,s), u) - PROVE /\ e = Head(u) - /\ IsPrefix(s, Tail(u)) - -THEOREM IsStrictPrefixStrictPartialOrder == - ASSUME NEW S - PROVE /\ \A s \in Seq(S) : ~ IsStrictPrefix(s,s) - /\ \A s,t \in Seq(S) : IsStrictPrefix(s,t) => ~ IsStrictPrefix(t,s) - /\ \A s,t,u \in Seq(S) : IsStrictPrefix(s,t) /\ IsStrictPrefix(t,u) => IsStrictPrefix(s,u) - -THEOREM IsStrictPrefixWellFounded == - ASSUME NEW S - PROVE IsWellFoundedOn(OpToRel(IsStrictPrefix, Seq(S)), Seq(S)) - -THEOREM SeqStrictPrefixInduction == - ASSUME NEW P(_), NEW S, - \A t \in Seq(S) : (\A s \in Seq(S) : IsStrictPrefix(s,t) => P(s)) => P(t) - PROVE \A s \in Seq(S) : P(s) - -(***************************************************************************) -(* Similar theorems about suffixes. *) -(***************************************************************************) - -THEOREM IsSuffixProperties == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE /\ IsSuffix(s,t) <=> \E u \in Seq(S) : t = u \o s - /\ IsSuffix(s,t) <=> Len(s) <= Len(t) /\ s = SubSeq(t, Len(t)-Len(s)+1, Len(t)) - /\ IsSuffix(s,t) <=> IsPrefix(Reverse(s), Reverse(t)) - -THEOREM IsStrictSuffixProperties == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE /\ IsStrictSuffix(s,t) <=> \E u \in Seq(S) : u # << >> /\ t = u \o s - /\ IsStrictSuffix(s,t) <=> Len(s) < Len(t) /\ IsSuffix(s,t) - /\ IsStrictSuffix(s,t) <=> Len(s) < Len(t) /\ s = SubSeq(t, Len(t)-Len(s)+1, Len(t)) - /\ IsStrictSuffix(s,t) <=> IsStrictPrefix(Reverse(s), Reverse(t)) - -THEOREM IsSuffixElts == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), NEW i \in 1 .. Len(s), - IsSuffix(s,t) - PROVE s[i] = t[Len(t) - Len(s) + i] - -THEOREM EmptyIsSuffix == - ASSUME NEW S, NEW s \in Seq(S) - PROVE /\ IsSuffix(<<>>, s) - /\ IsSuffix(s, <<>>) <=> s = <<>> - /\ IsStrictSuffix(<<>>, s) <=> s # <<>> - /\ ~ IsStrictSuffix(s, <<>>) - -THEOREM IsSuffixConcat == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE IsSuffix(s, t \o s) - -THEOREM IsStrictSuffixCons == - ASSUME NEW S, NEW s \in Seq(S), NEW e \in S - PROVE IsStrictSuffix(s, Cons(e,s)) - -THEOREM TailIsSuffix == - ASSUME NEW S, NEW s \in Seq(S) - PROVE /\ IsSuffix(Tail(s), s) - /\ s # <<>> => IsStrictSuffix(Tail(s), s) - -THEOREM IsSuffixPartialOrder == - ASSUME NEW S - PROVE /\ \A s \in Seq(S) : IsSuffix(s,s) - /\ \A s,t \in Seq(S) : IsSuffix(s,t) /\ IsSuffix(t,s) => s = t - /\ \A s,t,u \in Seq(S) : IsSuffix(s,t) /\ IsSuffix(t,u) => IsSuffix(s,u) - -THEOREM ConcatIsSuffix == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), NEW u \in Seq(S), - IsSuffix(s \o t, u) - PROVE IsSuffix(t, u) - -THEOREM ConcatIsSuffixCancel == - ASSUME NEW S, NEW s \in Seq(S), NEW t \in Seq(S), NEW u \in Seq(S) - PROVE IsSuffix(s \o t, u \o t) <=> IsSuffix(s, u) - -THEOREM AppendIsSuffixCancel == - ASSUME NEW S, NEW e \in S, NEW s \in Seq(S), NEW t \in Seq(S) - PROVE IsSuffix(Append(s,e), Append(t,e)) <=> IsSuffix(s,t) - -THEOREM AppendIsSuffix == - ASSUME NEW S, NEW e \in S, NEW s \in Seq(S), NEW u \in Seq(S), - IsSuffix(Append(s,e), u) - PROVE /\ e = Last(u) - /\ IsSuffix(s, Front(u)) - -THEOREM IsStrictSuffixStrictPartialOrder == - ASSUME NEW S - PROVE /\ \A s \in Seq(S) : ~ IsStrictSuffix(s,s) - /\ \A s,t \in Seq(S) : IsStrictSuffix(s,t) => ~ IsStrictSuffix(t,s) - /\ \A s,t,u \in Seq(S) : IsStrictSuffix(s,t) /\ IsStrictSuffix(t,u) => IsStrictSuffix(s,u) - -THEOREM IsStrictSuffixWellFounded == - ASSUME NEW S - PROVE IsWellFoundedOn(OpToRel(IsStrictSuffix, Seq(S)), Seq(S)) - -THEOREM SeqStrictSuffixInduction == - ASSUME NEW P(_), NEW S, - \A t \in Seq(S) : (\A s \in Seq(S) : IsStrictSuffix(s,t) => P(s)) => P(t) - PROVE \A s \in Seq(S) : P(s) - -(***************************************************************************) -(* Since the (strict) prefix and suffix orderings on sequences are *) -(* well-founded, they can be used for defining recursive functions. *) -(* The operators OpDefinesFcn, WFInductiveDefines, and WFInductiveUnique *) -(* are defined in module WellFoundedInduction. *) -(***************************************************************************) - -StrictPrefixesDetermineDef(S, Def(_,_)) == - \A g,h : \A seq \in Seq(S) : - (\A pre \in Seq(S) : IsStrictPrefix(pre,seq) => g[pre] = h[pre]) - => Def(g, seq) = Def(h, seq) - -LEMMA StrictPrefixesDetermineDef_WFDefOn == - ASSUME NEW S, NEW Def(_,_), StrictPrefixesDetermineDef(S, Def) - PROVE WFDefOn(OpToRel(IsStrictPrefix, Seq(S)), Seq(S), Def) - -THEOREM PrefixRecursiveSequenceFunctionUnique == - ASSUME NEW S, NEW Def(_,_), StrictPrefixesDetermineDef(S, Def) - PROVE WFInductiveUnique(Seq(S), Def) - -THEOREM PrefixRecursiveSequenceFunctionDef == - ASSUME NEW S, NEW Def(_,_), NEW f, - StrictPrefixesDetermineDef(S, Def), - OpDefinesFcn(f, Seq(S), Def) - PROVE WFInductiveDefines(f, Seq(S), Def) - -THEOREM PrefixRecursiveSequenceFunctionType == - ASSUME NEW S, NEW T, NEW Def(_,_), NEW f, - T # {}, - StrictPrefixesDetermineDef(S, Def), - WFInductiveDefines(f, Seq(S), Def), - \A g \in [Seq(S) -> T], s \in Seq(S) : Def(g,s) \in T - PROVE f \in [Seq(S) -> T] - -StrictSuffixesDetermineDef(S, Def(_,_)) == - \A g,h : \A seq \in Seq(S) : - (\A suf \in Seq(S) : IsStrictSuffix(suf,seq) => g[suf] = h[suf]) - => Def(g, seq) = Def(h, seq) - -LEMMA StrictSuffixesDetermineDef_WFDefOn == - ASSUME NEW S, NEW Def(_,_), StrictSuffixesDetermineDef(S, Def) - PROVE WFDefOn(OpToRel(IsStrictSuffix, Seq(S)), Seq(S), Def) - -THEOREM SuffixRecursiveSequenceFunctionUnique == - ASSUME NEW S, NEW Def(_,_), StrictSuffixesDetermineDef(S, Def) - PROVE WFInductiveUnique(Seq(S), Def) - -THEOREM SuffixRecursiveSequenceFunctionDef == - ASSUME NEW S, NEW Def(_,_), NEW f, - StrictSuffixesDetermineDef(S, Def), - OpDefinesFcn(f, Seq(S), Def) - PROVE WFInductiveDefines(f, Seq(S), Def) - -THEOREM SuffixRecursiveSequenceFunctionType == - ASSUME NEW S, NEW T, NEW Def(_,_), NEW f, - T # {}, - StrictSuffixesDetermineDef(S, Def), - WFInductiveDefines(f, Seq(S), Def), - \A g \in [Seq(S) -> T], s \in Seq(S) : Def(g,s) \in T - PROVE f \in [Seq(S) -> T] - -(***************************************************************************) -(* The following theorems justify ``primitive recursive'' functions over *) -(* sequences, with a base case for the empty sequence and recursion along *) -(* either the Tail or the Front of a non-empty sequence. *) -(***************************************************************************) - -TailInductiveDefHypothesis(f, S, f0, Def(_,_)) == - f = CHOOSE g : g = [s \in Seq(S) |-> IF s = <<>> THEN f0 ELSE Def(g[Tail(s)], s)] - -TailInductiveDefConclusion(f, S, f0, Def(_,_)) == - f = [s \in Seq(S) |-> IF s = <<>> THEN f0 ELSE Def(f[Tail(s)], s)] - -THEOREM TailInductiveDef == - ASSUME NEW S, NEW Def(_,_), NEW f, NEW f0, - TailInductiveDefHypothesis(f, S, f0, Def) - PROVE TailInductiveDefConclusion(f, S, f0, Def) - -THEOREM TailInductiveDefType == - ASSUME NEW S, NEW Def(_,_), NEW f, NEW f0, NEW T, - TailInductiveDefConclusion(f, S, f0, Def), - f0 \in T, - \A v \in T, s \in Seq(S) : s # <<>> => Def(v,s) \in T - PROVE f \in [Seq(S) -> T] - -FrontInductiveDefHypothesis(f, S, f0, Def(_,_)) == - f = CHOOSE g : g = [s \in Seq(S) |-> IF s = <<>> THEN f0 ELSE Def(g[Front(s)], s)] - -FrontInductiveDefConclusion(f, S, f0, Def(_,_)) == - f = [s \in Seq(S) |-> IF s = <<>> THEN f0 ELSE Def(f[Front(s)], s)] - -THEOREM FrontInductiveDef == - ASSUME NEW S, NEW Def(_,_), NEW f, NEW f0, - FrontInductiveDefHypothesis(f, S, f0, Def) - PROVE FrontInductiveDefConclusion(f, S, f0, Def) - -THEOREM FrontInductiveDefType == - ASSUME NEW S, NEW Def(_,_), NEW f, NEW f0, NEW T, - FrontInductiveDefConclusion(f, S, f0, Def), - f0 \in T, - \A v \in T, s \in Seq(S) : s # <<>> => Def(v,s) \in T - PROVE f \in [Seq(S) -> T] - -============================================================================= diff --git a/specifications/lamport_mutex/TLAPS.tla b/specifications/lamport_mutex/TLAPS.tla deleted file mode 100644 index 3abf4b1b..00000000 --- a/specifications/lamport_mutex/TLAPS.tla +++ /dev/null @@ -1,411 +0,0 @@ -------------------------------- MODULE TLAPS -------------------------------- - -(* Backend pragmas. *) - - -(***************************************************************************) -(* Each of these pragmas can be cited with a BY or a USE. The pragma that *) -(* is added to the context of an obligation most recently is the one whose *) -(* effects are triggered. *) -(***************************************************************************) - -(***************************************************************************) -(* The following pragmas should be used only as a last resource. They are *) -(* dependent upon the particular backend provers, and are unlikely to have *) -(* any effect if the set of backend provers changes. Moreover, they are *) -(* meaningless to a reader of the proof. *) -(***************************************************************************) - - -(**************************************************************************) -(* Backend pragma: use the SMT solver for arithmetic. *) -(* *) -(* This method exists under this name for historical reasons. *) -(**************************************************************************) - -SimpleArithmetic == TRUE (*{ by (prover:"smt3") }*) - - -(**************************************************************************) -(* Backend pragma: SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2. The supported *) -(* fragment includes first-order logic, set theory, functions and *) -(* records. *) -(* SMT calls the smt-solver with the default timeout of 5 seconds *) -(* while SMTT(n) calls the smt-solver with a timeout of n seconds. *) -(**************************************************************************) - -SMT == TRUE (*{ by (prover:"smt3") }*) -SMTT(X) == TRUE (*{ by (prover:"smt3"; timeout:@) }*) - - -(**************************************************************************) -(* Backend pragma: CVC3 SMT solver *) -(* *) -(* CVC3 is used by default but you can also explicitly call it. *) -(**************************************************************************) - -CVC3 == TRUE (*{ by (prover: "cvc33") }*) -CVC3T(X) == TRUE (*{ by (prover:"cvc33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Yices SMT solver *) -(* *) -(* This method translates the proof obligation to Yices native language. *) -(**************************************************************************) - -Yices == TRUE (*{ by (prover: "yices3") }*) -YicesT(X) == TRUE (*{ by (prover:"yices3"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: veriT SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls veriT.*) -(**************************************************************************) - -veriT == TRUE (*{ by (prover: "verit") }*) -veriTT(X) == TRUE (*{ by (prover:"verit"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Z3 SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls Z3. *) -(**************************************************************************) - -Z3 == TRUE (*{ by (prover: "z33") }*) -Z3T(X) == TRUE (*{ by (prover:"z33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: SPASS superposition prover *) -(* *) -(* This method translates the proof obligation to the DFG format language *) -(* supported by the ATP SPASS. The translation is based on the SMT one. *) -(**************************************************************************) - -Spass == TRUE (*{ by (prover: "spass") }*) -SpassT(X) == TRUE (*{ by (prover:"spass"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: The PTL propositional linear time temporal logic *) -(* prover. It currently is the LS4 backend. *) -(* *) -(* This method translates the negetation of the proof obligation to *) -(* Seperated Normal Form (TRP++ format) and checks for unsatisfiability *) -(**************************************************************************) - -LS4 == TRUE (*{ by (prover: "ls4") }*) -PTL == TRUE (*{ by (prover: "ls4") }*) - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -Zenon == TRUE (*{ by (prover:"zenon") }*) -ZenonT(X) == TRUE (*{ by (prover:"zenon"; timeout:@) }*) - -(********************************************************************) -(* Backend pragma: Isabelle with different timeouts and tactics *) -(* (default is 30 seconds/auto) *) -(********************************************************************) - -Isa == TRUE (*{ by (prover:"isabelle") }*) -IsaT(X) == TRUE (*{ by (prover:"isabelle"; timeout:@) }*) -IsaM(X) == TRUE (*{ by (prover:"isabelle"; tactic:@) }*) -IsaMT(X,Y) == TRUE (*{ by (prover:"isabelle"; tactic:@; timeout:@) }*) - -(***************************************************************************) -(* The following theorem expresses the (useful implication of the) law of *) -(* set extensionality, which can be written as *) -(* *) -(* THEOREM \A S, T : (S = T) <=> (\A x : (x \in S) <=> (x \in T)) *) -(* *) -(* Theorem SetExtensionality is sometimes required by the SMT backend for *) -(* reasoning about sets. It is usually counterproductive to include *) -(* theorem SetExtensionality in a BY clause for the Zenon or Isabelle *) -(* backends. Instead, use the pragma IsaWithSetExtensionality to instruct *) -(* the Isabelle backend to use the rule of set extensionality. *) -(***************************************************************************) -IsaWithSetExtensionality == TRUE - (*{ by (prover:"isabelle"; tactic:"(auto intro: setEqualI)")}*) - -THEOREM SetExtensionality == \A S,T : (\A x : x \in S <=> x \in T) => S = T -OBVIOUS - -(***************************************************************************) -(* The following theorem is needed to deduce NotInSetS \notin SetS from *) -(* the definition *) -(* *) -(* NotInSetS == CHOOSE v : v \notin SetS *) -(***************************************************************************) -THEOREM NoSetContainsEverything == \A S : \E x : x \notin S -OBVIOUS (*{by (isabelle "(auto intro: inIrrefl)")}*) ------------------------------------------------------------------------------ - - - -(********************************************************************) -(********************************************************************) -(********************************************************************) - - -(********************************************************************) -(* Old versions of Zenon and Isabelle pragmas below *) -(* (kept for compatibility) *) -(********************************************************************) - - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -SlowZenon == TRUE (*{ by (prover:"zenon"; timeout:20) }*) -SlowerZenon == TRUE (*{ by (prover:"zenon"; timeout:40) }*) -VerySlowZenon == TRUE (*{ by (prover:"zenon"; timeout:80) }*) -SlowestZenon == TRUE (*{ by (prover:"zenon"; timeout:160) }*) - - - -(********************************************************************) -(* Backend pragma: Isabelle's automatic search ("auto") *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* essentially simplification and equational reasoning. *) -(* Default imeout for all isabelle tactics is 30 seconds. *) -(********************************************************************) -Auto == TRUE (*{ by (prover:"isabelle"; tactic:"auto") }*) -SlowAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:120) }*) -SlowerAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:480) }*) -SlowestAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:960) }*) - -(********************************************************************) -(* Backend pragma: Isabelle's "force" tactic *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* quantifier reasoning. *) -(********************************************************************) -Force == TRUE (*{ by (prover:"isabelle"; tactic:"force") }*) -SlowForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:120) }*) -SlowerForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:480) }*) -SlowestForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:960) }*) - -(***********************************************************************) -(* Backend pragma: Isabelle's "simplification" tactics *) -(* *) -(* These tactics simplify the goal before running one of the automated *) -(* tactics. They are often necessary for obligations involving record *) -(* or tuple projections. Use the SimplfyAndSolve tactic unless you're *) -(* sure you can get away with just Simplification *) -(***********************************************************************) -SimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?") }*) -SlowSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:120) }*) -SlowerSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:480) }*) -SlowestSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:960) }*) - -Simplification == TRUE (*{ by (prover:"isabelle"; tactic:"clarsimp") }*) -SlowSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:120) }*) -SlowerSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:480) }*) -SlowestSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:960) }*) - -(**************************************************************************) -(* Backend pragma: Isabelle's tableau prover ("blast") *) -(* *) -(* This pragma bypasses Zenon and uses Isabelle's built-in theorem *) -(* prover, Blast. It is almost never better than Zenon by itself, but *) -(* becomes very useful in combination with the Auto pragma above. The *) -(* AutoBlast pragma first attempts Auto and then uses Blast to prove what *) -(* Auto could not prove. (There is currently no way to use Zenon on the *) -(* results left over from Auto.) *) -(**************************************************************************) -Blast == TRUE (*{ by (prover:"isabelle"; tactic:"blast") }*) -SlowBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:120) }*) -SlowerBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:480) }*) -SlowestBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:960) }*) - -AutoBlast == TRUE (*{ by (prover:"isabelle"; tactic:"auto, blast") }*) - - -(**************************************************************************) -(* Backend pragmas: multi-back-ends *) -(* *) -(* These pragmas just run a bunch of back-ends one after the other in the *) -(* hope that one will succeed. This saves time and effort for the user at *) -(* the expense of computation time. *) -(**************************************************************************) - -(* CVC3 goes first because it's bundled with TLAPS, then the other SMT - solvers are unlikely to succeed if CVC3 fails, so we run zenon and - Isabelle before them. *) -AllProvers == TRUE (*{ - by (prover:"cvc33") - by (prover:"zenon") - by (prover:"isabelle"; tactic:"auto") - by (prover:"spass") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllProversT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"zenon"; timeout:@) - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"spass"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - -AllSMT == TRUE (*{ - by (prover:"cvc33") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - }*) -AllSMTT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - }*) - -AllIsa == TRUE (*{ - by (prover:"isabelle"; tactic:"auto") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllIsaT(X) == TRUE (*{ - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - ----------------------------------------------------------------------------- -(***************************************************************************) -(* TEMPORAL LOGIC *) -(* *) -(* The following rules are intended to be used when TLAPS handles temporal *) -(* logic. They will not work now. Moreover when temporal reasoning is *) -(* implemented, these rules may be changed or omitted, and additional *) -(* rules will probably be added. However, they are included mainly so *) -(* their names will be defined, preventing the use of identifiers that are *) -(* likely to produce name clashes with future versions of this module. *) -(***************************************************************************) - - -(***************************************************************************) -(* The following proof rules (and their names) are from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleTLA1 == ASSUME STATE P, STATE f, - P /\ (f' = f) => P' - PROVE []P <=> P /\ [][P => P']_f - -THEOREM RuleTLA2 == ASSUME STATE P, STATE Q, STATE f, STATE g, - ACTION A, ACTION B, - P /\ [A]_f => Q /\ [B]_g - PROVE []P /\ [][A]_f => []Q /\ [][B]_g - -THEOREM RuleINV1 == ASSUME STATE I, STATE F, ACTION N, - I /\ [N]_F => I' - PROVE I /\ [][N]_F => []I - -THEOREM RuleINV2 == ASSUME STATE I, STATE f, ACTION N - PROVE []I => ([][N]_f <=> [][N /\ I /\ I']_f) - -THEOREM RuleWF1 == ASSUME STATE P, STATE Q, STATE f, ACTION N, ACTION A, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - P => ENABLED <>_f - PROVE [][N]_f /\ WF_f(A) => (P ~> Q) - -THEOREM RuleSF1 == ASSUME STATE P, STATE Q, STATE f, - ACTION N, ACTION A, TEMPORAL F, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - []P /\ [][N]_f /\ []F => <> ENABLED <>_f - PROVE [][N]_f /\ SF_f(A) /\ []F => (P ~> Q) - -(***************************************************************************) -(* The rules WF2 and SF2 in "The Temporal Logic of Actions" are obtained *) -(* from the following two rules by the following substitutions: `. *) -(* *) -(* ___ ___ _______________ *) -(* M <- M , g <- g , EM <- ENABLED <>_g .' *) -(***************************************************************************) -THEOREM RuleWF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ WF_f(A) /\ []F /\ <>[]EM => <>[]P - PROVE [][N]_f /\ WF_f(A) /\ []F => []<><>_g \/ []<>(~EM) - -THEOREM RuleSF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ SF_f(A) /\ []F /\ []<>EM => <>[]P - PROVE [][N]_f /\ SF_f(A) /\ []F => []<><>_g \/ <>[](~EM) - - -(***************************************************************************) -(* The following rule is a special case of the general temporal logic *) -(* proof rule STL4 from the paper "The Temporal Logic of Actions". The *) -(* general rule is for arbitrary temporal formulas F and G, but it cannot *) -(* yet be handled by TLAPS. *) -(***************************************************************************) -THEOREM RuleInvImplication == - ASSUME STATE F, STATE G, - F => G - PROVE []F => []G -PROOF OMITTED - -(***************************************************************************) -(* The following rule is a special case of rule TLA2 from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleStepSimulation == - ASSUME STATE I, STATE f, STATE g, - ACTION M, ACTION N, - I /\ I' /\ [M]_f => [N]_g - PROVE []I /\ [][M]_f => [][N]_g -PROOF OMITTED - -(***************************************************************************) -(* The following may be used to invoke a decision procedure for *) -(* propositional temporal logic. *) -(***************************************************************************) -PropositionalTemporalLogic == TRUE -============================================================================= diff --git a/specifications/lamport_mutex/WellFoundedInduction.tla b/specifications/lamport_mutex/WellFoundedInduction.tla deleted file mode 100644 index 5a726b69..00000000 --- a/specifications/lamport_mutex/WellFoundedInduction.tla +++ /dev/null @@ -1,328 +0,0 @@ ------------------------- MODULE WellFoundedInduction ------------------------ -(***************************************************************************) -(* This module contains useful theorems for inductive proofs and recursive *) -(* definitions based on a well-founded ordering. *) -(* *) -(* Most of the statements of the theorems are decomposed in terms of *) -(* definitions. This is done for two reasons: *) -(* *) -(* - It makes it easier for the backends to instantiate the theorems *) -(* when those definitions are not expanded. In fact, at the moment *) -(* the provers can't prove any of those theorems from the theorem *) -(* itself if the definitions are made usable. *) -(* *) -(* - It can be convenient when writing proofs to use those definitions *) -(* rather than having to write out their expansions. *) -(* *) -(* A relation is represented as a set of ordered pairs, where we write *) -(* <> \in R instead of x R y. It is more convenient to represent *) -(* relations this way rather than as operators such as < . *) -(* *) -(* Proofs of these theorems appear in module WellFoundedInduction_proofs. *) -(***************************************************************************) -EXTENDS NaturalsInduction - -(***************************************************************************) -(* The following defines what it means for a relation R to be transitively *) -(* closed on a set S. In this and other definitions, we think of R as a *) -(* relation on S, meaning that it is a subset of S \X S. However, this is *) -(* not necessary. Our results do not require this as a hypothesis, and it *) -(* is often convenient to apply them when R is a relation on a set *) -(* containing S as a subset. They're even true (though uninteresting) if *) -(* R and S \X S are disjoint sets. *) -(***************************************************************************) -IsTransitivelyClosedOn(R, S) == - \A i, j, k \in S : (<> \in R) /\ (<> \in R) - => (<> \in R) -(***************************************************************************) -(* If we think of R as a less-than relation, then R is well founded on S *) -(* iff there is no "infinitely descending" sequence of elements of S. The *) -(* canonical example of a well founded relation is the ordinary less-than *) -(* relation on the natural numbers. *) -(* *) -(* A S with a well-founded ordering is often called well-ordered. *) -(***************************************************************************) -IsWellFoundedOn(R, S) == - ~ \E f \in [Nat -> S] : \A n \in Nat : <> \in R - -LEMMA EmptyIsWellFounded == \A S : IsWellFoundedOn({}, S) - - -LEMMA IsWellFoundedOnSubset == - ASSUME NEW R, NEW S, NEW T \in SUBSET S, - IsWellFoundedOn(R,S) - PROVE IsWellFoundedOn(R,T) - - -LEMMA IsWellFoundedOnSubrelation == - ASSUME NEW S, NEW R, NEW RR, RR \cap (S \X S) \subseteq R, - IsWellFoundedOn(R,S) - PROVE IsWellFoundedOn(RR,S) - - -(***************************************************************************) -(* If we think of R as a less-than relation on S, then the following is *) -(* the set of elements of S that are less than x. *) -(***************************************************************************) -SetLessThan(x, R, S) == {y \in S : <> \in R} - -(***************************************************************************) -(* If we think of R as a less-than relation on S, then R is well-founded *) -(* iff every non-empty subset of S has a minimal element. *) -(***************************************************************************) - -THEOREM WFMin == - ASSUME NEW R, NEW S, - IsWellFoundedOn(R, S), - NEW T, T \subseteq S, T # {} - PROVE \E x \in T : \A y \in T : ~ (<> \in R) - - -THEOREM MinWF == - ASSUME NEW R, NEW S, - \A T \in SUBSET S : T # {} => \E x \in T : \A y \in T : ~ (<> \in R) - PROVE IsWellFoundedOn(R,S) - - -(***************************************************************************) -(* The two following lemmas are simple consequences of theorem WFMin. *) -(***************************************************************************) -LEMMA WellFoundedIsIrreflexive == - ASSUME NEW R, NEW S, NEW x \in S, - IsWellFoundedOn(R, S) - PROVE <> \notin R - - -LEMMA WellFoundedIsAsymmetric == - ASSUME NEW R, NEW S, NEW x \in S, NEW y \in S, - IsWellFoundedOn(R,S), - <> \in R, <> \in R - PROVE FALSE - - -(***************************************************************************) -(* The following lemmas are simple facts about operator SetLessThan. *) -(***************************************************************************) -LEMMA WFSetLessThanIrreflexive == - ASSUME NEW R, NEW S, NEW x \in S, - IsWellFoundedOn(R,S) - PROVE x \notin SetLessThan(x,R,S) - - -LEMMA SetLessTransitive == - ASSUME NEW R, NEW S, NEW x \in S, NEW y \in SetLessThan(x,R,S), - IsTransitivelyClosedOn(R, S) - PROVE SetLessThan(y, R, S) \subseteq SetLessThan(x, R, S) - - ----------------------------------------------------------------------------- -(***************************************************************************) -(* The following theorem is the basis for proof by induction over a *) -(* well-founded set. It generalizes theorem GeneralNatInduction of module *) -(* NaturalsInduction. *) -(***************************************************************************) -THEOREM WFInduction == - ASSUME NEW P(_), NEW R, NEW S, - IsWellFoundedOn(R, S), - \A x \in S : (\A y \in SetLessThan(x, R, S) : P(y)) - => P(x) - PROVE \A x \in S : P(x) - - -(***************************************************************************) -(* Theorem WFInductiveDef below justifies recursive definitions based on a *) -(* well-founded ordering. We first prove it with the hypothesis that the *) -(* ordering is transitively closed. We prove the theorem for an arbitrary *) -(* well-founded relation by applying the special case to its transitive *) -(* closure. *) -(***************************************************************************) -WFDefOn(R, S, Def(_,_)) == - \A g, h : - \A x \in S : - (\A y \in SetLessThan(x, R, S) : g[y] = h[y]) - => (Def(g,x) = Def(h,x)) - -OpDefinesFcn(f, S, Def(_,_)) == - f = CHOOSE g : g = [x \in S |-> Def(g, x)] - -WFInductiveDefines(f, S, Def(_,_)) == - f = [x \in S |-> Def(f, x)] - -WFInductiveUnique(S, Def(_,_)) == - \A g, h : /\ WFInductiveDefines(g, S, Def) - /\ WFInductiveDefines(h, S, Def) - => (g = h) - -THEOREM WFDefOnUnique == - ASSUME NEW Def(_,_), NEW R, NEW S, - IsWellFoundedOn(R, S), WFDefOn(R, S, Def) - PROVE WFInductiveUnique(S, Def) - - -LEMMA WFInductiveDefLemma == - ASSUME NEW Def(_,_), NEW R, NEW S, NEW f, - IsWellFoundedOn(R, S), - IsTransitivelyClosedOn(R, S), - WFDefOn(R, S, Def), - OpDefinesFcn(f, S, Def) - PROVE WFInductiveDefines(f, S, Def) - - -(***************************************************************************) -(* The following defines the transitive closure of the relation R on S. *) -(* More precisely, it is the transitive closure of the restriction of R *) -(* to S. We give an abstract definition of transitive closure as the *) -(* smallest relation that contains R (restricted to S \X S) and that is *) -(* transitively closed, then prove some relevant properties. *) -(***************************************************************************) -TransitiveClosureOn(R,S) == - { ss \in S \X S : - \A U \in SUBSET (S \X S) : - /\ R \cap S \X S \subseteq U - /\ IsTransitivelyClosedOn(U, S) - => ss \in U } - -LEMMA TransitiveClosureThm == - \A R, S : - /\ R \cap S \X S \subseteq TransitiveClosureOn(R, S) - /\ IsTransitivelyClosedOn(TransitiveClosureOn(R, S), S) - - -LEMMA TransitiveClosureMinimal == - ASSUME NEW R, NEW S, NEW U \in SUBSET (S \X S), - R \cap S \X S \subseteq U, - IsTransitivelyClosedOn(U,S) - PROVE TransitiveClosureOn(R,S) \subseteq U - - -(***************************************************************************) -(* The following lemmas are consequences of the two previous ones. The *) -(* first three state closure properties of transitive closure, the fourth *) -(* lemma allows one to chop off a step in the underlying relation for any *) -(* pair in the transitive closure. *) -(***************************************************************************) - -LEMMA TCTCTC == - ASSUME NEW R, NEW S, NEW i \in S, NEW j \in S, NEW k \in S, - <> \in TransitiveClosureOn(R,S), - <> \in TransitiveClosureOn(R,S) - PROVE <> \in TransitiveClosureOn(R,S) - - -LEMMA TCRTC == - ASSUME NEW R, NEW S, NEW i \in S, NEW j \in S, NEW k \in S, - <> \in TransitiveClosureOn(R,S), <> \in R - PROVE <> \in TransitiveClosureOn(R,S) - - -LEMMA RTCTC == - ASSUME NEW R, NEW S, NEW i \in S, NEW j \in S, NEW k \in S, - <> \in R, <> \in TransitiveClosureOn(R,S) - PROVE <> \in TransitiveClosureOn(R,S) - - -LEMMA TransitiveClosureChopLast == - ASSUME NEW R, NEW S, NEW i \in S, NEW k \in S, <> \in TransitiveClosureOn(R,S) - PROVE \E j \in S : /\ <> \in R - /\ i = j \/ <> \in TransitiveClosureOn(R,S) - - -THEOREM TransitiveClosureWF == - ASSUME NEW R, NEW S, IsWellFoundedOn(R,S) - PROVE IsWellFoundedOn(TransitiveClosureOn(R, S), S) - - -THEOREM WFInductiveDef == - ASSUME NEW Def(_,_), NEW R, NEW S, NEW f, - IsWellFoundedOn(R, S), - WFDefOn(R, S, Def), - OpDefinesFcn(f, S, Def) - PROVE WFInductiveDefines(f, S, Def) - - -(***************************************************************************) -(* Theorem WFInductiveDef allows us to conclude that a recursively defined *) -(* function satisfies its recursion equation. The following result allows *) -(* us to deduce the range of this function. *) -(***************************************************************************) -THEOREM WFInductiveDefType == - ASSUME NEW Def(_,_), NEW f, NEW R, NEW S, NEW T, - T # {}, - IsWellFoundedOn(R, S), - WFDefOn(R, S, Def), - WFInductiveDefines(f, S, Def), - \A g \in [S -> T], s \in S : Def(g, s) \in T - PROVE f \in [S -> T] - - - ---------------------------------------------------------------------------- -(***************************************************************************) -(* Below are some theorems that allow us to derive some useful *) -(* well-founded relations from a given well-founded relation. First, we *) -(* define the operator OpToRel that constructs a relation (a set of *) -(* ordered pairs) from a relation expressed as an operator. *) -(***************************************************************************) -OpToRel(_\prec_, S) == {ss \in S \X S : ss[1] \prec ss[2]} - -(***************************************************************************) -(* To construct well-founded relations from the less-than relation on the *) -(* natural numbers, we first prove that it is well-founded. *) -(***************************************************************************) -THEOREM NatLessThanWellFounded == IsWellFoundedOn(OpToRel(<,Nat), Nat) - - -(***************************************************************************) -(* The next definition would be easier to read if we used the TLA+ *) -(* construct {<> \in T : ... }. However, TLAPS does not support *) -(* that notation. (It's meaning is rather complicated in the general case *) -(* when T is not a Cartesian product of sets.) *) -(***************************************************************************) -PreImage(f(_), S, R) == {ss \in S \X S : <> \in R} - -THEOREM PreImageWellFounded == - ASSUME NEW S, NEW T, NEW R, NEW f(_), - \A s \in S : f(s) \in T, - IsWellFoundedOn(R, T) - PROVE IsWellFoundedOn(PreImage(f, S, R), S) - - -(***************************************************************************) -(* We now prove that the lexicographical ordering on the Cartesian product *) -(* of two well-ordered sets is well-ordered. *) -(***************************************************************************) -LexPairOrdering(R1, R2, S1, S2) == - {ss \in (S1 \X S2) \X (S1 \X S2) : - \/ <> \in R1 - \/ /\ ss[1][1] = ss[2][1] - /\ <> \in R2} - -THEOREM WFLexPairOrdering == - ASSUME NEW R1, NEW R2, NEW S1, NEW S2, - IsWellFoundedOn(R1, S1), - IsWellFoundedOn(R2, S2) - PROVE IsWellFoundedOn(LexPairOrdering(R1, R2, S1, S2), S1 \X S2) - - -(***************************************************************************) -(* The preceding theorem generalizes in the obvious way to the Cartesian *) -(* product of a finite number of well-ordered sets. However, the *) -(* statement of the general theorem is rather complicated, so we state it *) -(* for the most useful case: the Cartesian product of n copies of the same *) -(* set. *) -(***************************************************************************) -LexProductOrdering(R, S, n) == - { ff \in [1..n -> S] \X [1..n -> S] : - \E j \in 1..n : - /\ \A i \in 1..(j-1) : ff[1][i] = ff[2][i] - /\ <> \in R } - -THEOREM WFLexProductOrdering == - ASSUME NEW R, NEW S, NEW n \in Nat, - IsWellFoundedOn(R, S) - PROVE IsWellFoundedOn(LexProductOrdering(R, S, n), [1..n -> S]) - -============================================================================= -\* Modification History -\* Last modified Thu Feb 13 18:14:56 GMT-03:00 2014 by merz -\* Last modified Sun Jan 01 18:39:23 CET 2012 by merz -\* Last modified Wed Nov 23 10:13:18 PST 2011 by lamport diff --git a/specifications/sums_even/TLAPS.tla b/specifications/sums_even/TLAPS.tla deleted file mode 100644 index 3abf4b1b..00000000 --- a/specifications/sums_even/TLAPS.tla +++ /dev/null @@ -1,411 +0,0 @@ -------------------------------- MODULE TLAPS -------------------------------- - -(* Backend pragmas. *) - - -(***************************************************************************) -(* Each of these pragmas can be cited with a BY or a USE. The pragma that *) -(* is added to the context of an obligation most recently is the one whose *) -(* effects are triggered. *) -(***************************************************************************) - -(***************************************************************************) -(* The following pragmas should be used only as a last resource. They are *) -(* dependent upon the particular backend provers, and are unlikely to have *) -(* any effect if the set of backend provers changes. Moreover, they are *) -(* meaningless to a reader of the proof. *) -(***************************************************************************) - - -(**************************************************************************) -(* Backend pragma: use the SMT solver for arithmetic. *) -(* *) -(* This method exists under this name for historical reasons. *) -(**************************************************************************) - -SimpleArithmetic == TRUE (*{ by (prover:"smt3") }*) - - -(**************************************************************************) -(* Backend pragma: SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2. The supported *) -(* fragment includes first-order logic, set theory, functions and *) -(* records. *) -(* SMT calls the smt-solver with the default timeout of 5 seconds *) -(* while SMTT(n) calls the smt-solver with a timeout of n seconds. *) -(**************************************************************************) - -SMT == TRUE (*{ by (prover:"smt3") }*) -SMTT(X) == TRUE (*{ by (prover:"smt3"; timeout:@) }*) - - -(**************************************************************************) -(* Backend pragma: CVC3 SMT solver *) -(* *) -(* CVC3 is used by default but you can also explicitly call it. *) -(**************************************************************************) - -CVC3 == TRUE (*{ by (prover: "cvc33") }*) -CVC3T(X) == TRUE (*{ by (prover:"cvc33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Yices SMT solver *) -(* *) -(* This method translates the proof obligation to Yices native language. *) -(**************************************************************************) - -Yices == TRUE (*{ by (prover: "yices3") }*) -YicesT(X) == TRUE (*{ by (prover:"yices3"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: veriT SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls veriT.*) -(**************************************************************************) - -veriT == TRUE (*{ by (prover: "verit") }*) -veriTT(X) == TRUE (*{ by (prover:"verit"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: Z3 SMT solver *) -(* *) -(* This method translates the proof obligation to SMTLIB2 and calls Z3. *) -(**************************************************************************) - -Z3 == TRUE (*{ by (prover: "z33") }*) -Z3T(X) == TRUE (*{ by (prover:"z33"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: SPASS superposition prover *) -(* *) -(* This method translates the proof obligation to the DFG format language *) -(* supported by the ATP SPASS. The translation is based on the SMT one. *) -(**************************************************************************) - -Spass == TRUE (*{ by (prover: "spass") }*) -SpassT(X) == TRUE (*{ by (prover:"spass"; timeout:@) }*) - -(**************************************************************************) -(* Backend pragma: The PTL propositional linear time temporal logic *) -(* prover. It currently is the LS4 backend. *) -(* *) -(* This method translates the negetation of the proof obligation to *) -(* Seperated Normal Form (TRP++ format) and checks for unsatisfiability *) -(**************************************************************************) - -LS4 == TRUE (*{ by (prover: "ls4") }*) -PTL == TRUE (*{ by (prover: "ls4") }*) - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -Zenon == TRUE (*{ by (prover:"zenon") }*) -ZenonT(X) == TRUE (*{ by (prover:"zenon"; timeout:@) }*) - -(********************************************************************) -(* Backend pragma: Isabelle with different timeouts and tactics *) -(* (default is 30 seconds/auto) *) -(********************************************************************) - -Isa == TRUE (*{ by (prover:"isabelle") }*) -IsaT(X) == TRUE (*{ by (prover:"isabelle"; timeout:@) }*) -IsaM(X) == TRUE (*{ by (prover:"isabelle"; tactic:@) }*) -IsaMT(X,Y) == TRUE (*{ by (prover:"isabelle"; tactic:@; timeout:@) }*) - -(***************************************************************************) -(* The following theorem expresses the (useful implication of the) law of *) -(* set extensionality, which can be written as *) -(* *) -(* THEOREM \A S, T : (S = T) <=> (\A x : (x \in S) <=> (x \in T)) *) -(* *) -(* Theorem SetExtensionality is sometimes required by the SMT backend for *) -(* reasoning about sets. It is usually counterproductive to include *) -(* theorem SetExtensionality in a BY clause for the Zenon or Isabelle *) -(* backends. Instead, use the pragma IsaWithSetExtensionality to instruct *) -(* the Isabelle backend to use the rule of set extensionality. *) -(***************************************************************************) -IsaWithSetExtensionality == TRUE - (*{ by (prover:"isabelle"; tactic:"(auto intro: setEqualI)")}*) - -THEOREM SetExtensionality == \A S,T : (\A x : x \in S <=> x \in T) => S = T -OBVIOUS - -(***************************************************************************) -(* The following theorem is needed to deduce NotInSetS \notin SetS from *) -(* the definition *) -(* *) -(* NotInSetS == CHOOSE v : v \notin SetS *) -(***************************************************************************) -THEOREM NoSetContainsEverything == \A S : \E x : x \notin S -OBVIOUS (*{by (isabelle "(auto intro: inIrrefl)")}*) ------------------------------------------------------------------------------ - - - -(********************************************************************) -(********************************************************************) -(********************************************************************) - - -(********************************************************************) -(* Old versions of Zenon and Isabelle pragmas below *) -(* (kept for compatibility) *) -(********************************************************************) - - -(**************************************************************************) -(* Backend pragma: Zenon with different timeouts (default is 10 seconds) *) -(* *) -(**************************************************************************) - -SlowZenon == TRUE (*{ by (prover:"zenon"; timeout:20) }*) -SlowerZenon == TRUE (*{ by (prover:"zenon"; timeout:40) }*) -VerySlowZenon == TRUE (*{ by (prover:"zenon"; timeout:80) }*) -SlowestZenon == TRUE (*{ by (prover:"zenon"; timeout:160) }*) - - - -(********************************************************************) -(* Backend pragma: Isabelle's automatic search ("auto") *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* essentially simplification and equational reasoning. *) -(* Default imeout for all isabelle tactics is 30 seconds. *) -(********************************************************************) -Auto == TRUE (*{ by (prover:"isabelle"; tactic:"auto") }*) -SlowAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:120) }*) -SlowerAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:480) }*) -SlowestAuto == TRUE (*{ by (prover:"isabelle"; tactic:"auto"; timeout:960) }*) - -(********************************************************************) -(* Backend pragma: Isabelle's "force" tactic *) -(* *) -(* This pragma bypasses Zenon. It is useful in situations involving *) -(* quantifier reasoning. *) -(********************************************************************) -Force == TRUE (*{ by (prover:"isabelle"; tactic:"force") }*) -SlowForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:120) }*) -SlowerForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:480) }*) -SlowestForce == TRUE (*{ by (prover:"isabelle"; tactic:"force"; timeout:960) }*) - -(***********************************************************************) -(* Backend pragma: Isabelle's "simplification" tactics *) -(* *) -(* These tactics simplify the goal before running one of the automated *) -(* tactics. They are often necessary for obligations involving record *) -(* or tuple projections. Use the SimplfyAndSolve tactic unless you're *) -(* sure you can get away with just Simplification *) -(***********************************************************************) -SimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?") }*) -SlowSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:120) }*) -SlowerSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:480) }*) -SlowestSimplifyAndSolve == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:960) }*) - -Simplification == TRUE (*{ by (prover:"isabelle"; tactic:"clarsimp") }*) -SlowSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:120) }*) -SlowerSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:480) }*) -SlowestSimplification == TRUE - (*{ by (prover:"isabelle"; tactic:"clarsimp"; timeout:960) }*) - -(**************************************************************************) -(* Backend pragma: Isabelle's tableau prover ("blast") *) -(* *) -(* This pragma bypasses Zenon and uses Isabelle's built-in theorem *) -(* prover, Blast. It is almost never better than Zenon by itself, but *) -(* becomes very useful in combination with the Auto pragma above. The *) -(* AutoBlast pragma first attempts Auto and then uses Blast to prove what *) -(* Auto could not prove. (There is currently no way to use Zenon on the *) -(* results left over from Auto.) *) -(**************************************************************************) -Blast == TRUE (*{ by (prover:"isabelle"; tactic:"blast") }*) -SlowBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:120) }*) -SlowerBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:480) }*) -SlowestBlast == TRUE (*{ by (prover:"isabelle"; tactic:"blast"; timeout:960) }*) - -AutoBlast == TRUE (*{ by (prover:"isabelle"; tactic:"auto, blast") }*) - - -(**************************************************************************) -(* Backend pragmas: multi-back-ends *) -(* *) -(* These pragmas just run a bunch of back-ends one after the other in the *) -(* hope that one will succeed. This saves time and effort for the user at *) -(* the expense of computation time. *) -(**************************************************************************) - -(* CVC3 goes first because it's bundled with TLAPS, then the other SMT - solvers are unlikely to succeed if CVC3 fails, so we run zenon and - Isabelle before them. *) -AllProvers == TRUE (*{ - by (prover:"cvc33") - by (prover:"zenon") - by (prover:"isabelle"; tactic:"auto") - by (prover:"spass") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllProversT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"zenon"; timeout:@) - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"spass"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - -AllSMT == TRUE (*{ - by (prover:"cvc33") - by (prover:"smt3") - by (prover:"yices3") - by (prover:"verit") - by (prover:"z33") - }*) -AllSMTT(X) == TRUE (*{ - by (prover:"cvc33"; timeout:@) - by (prover:"smt3"; timeout:@) - by (prover:"yices3"; timeout:@) - by (prover:"verit"; timeout:@) - by (prover:"z33"; timeout:@) - }*) - -AllIsa == TRUE (*{ - by (prover:"isabelle"; tactic:"auto") - by (prover:"isabelle"; tactic:"force") - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)") - by (prover:"isabelle"; tactic:"clarsimp auto?") - by (prover:"isabelle"; tactic:"clarsimp") - by (prover:"isabelle"; tactic:"auto, blast") - }*) -AllIsaT(X) == TRUE (*{ - by (prover:"isabelle"; tactic:"auto"; timeout:@) - by (prover:"isabelle"; tactic:"force"; timeout:@) - by (prover:"isabelle"; tactic:"(auto intro: setEqualI)"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp auto?"; timeout:@) - by (prover:"isabelle"; tactic:"clarsimp"; timeout:@) - by (prover:"isabelle"; tactic:"auto, blast"; timeout:@) - }*) - ----------------------------------------------------------------------------- -(***************************************************************************) -(* TEMPORAL LOGIC *) -(* *) -(* The following rules are intended to be used when TLAPS handles temporal *) -(* logic. They will not work now. Moreover when temporal reasoning is *) -(* implemented, these rules may be changed or omitted, and additional *) -(* rules will probably be added. However, they are included mainly so *) -(* their names will be defined, preventing the use of identifiers that are *) -(* likely to produce name clashes with future versions of this module. *) -(***************************************************************************) - - -(***************************************************************************) -(* The following proof rules (and their names) are from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleTLA1 == ASSUME STATE P, STATE f, - P /\ (f' = f) => P' - PROVE []P <=> P /\ [][P => P']_f - -THEOREM RuleTLA2 == ASSUME STATE P, STATE Q, STATE f, STATE g, - ACTION A, ACTION B, - P /\ [A]_f => Q /\ [B]_g - PROVE []P /\ [][A]_f => []Q /\ [][B]_g - -THEOREM RuleINV1 == ASSUME STATE I, STATE F, ACTION N, - I /\ [N]_F => I' - PROVE I /\ [][N]_F => []I - -THEOREM RuleINV2 == ASSUME STATE I, STATE f, ACTION N - PROVE []I => ([][N]_f <=> [][N /\ I /\ I']_f) - -THEOREM RuleWF1 == ASSUME STATE P, STATE Q, STATE f, ACTION N, ACTION A, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - P => ENABLED <>_f - PROVE [][N]_f /\ WF_f(A) => (P ~> Q) - -THEOREM RuleSF1 == ASSUME STATE P, STATE Q, STATE f, - ACTION N, ACTION A, TEMPORAL F, - P /\ [N]_f => (P' \/ Q'), - P /\ <>_f => Q', - []P /\ [][N]_f /\ []F => <> ENABLED <>_f - PROVE [][N]_f /\ SF_f(A) /\ []F => (P ~> Q) - -(***************************************************************************) -(* The rules WF2 and SF2 in "The Temporal Logic of Actions" are obtained *) -(* from the following two rules by the following substitutions: `. *) -(* *) -(* ___ ___ _______________ *) -(* M <- M , g <- g , EM <- ENABLED <>_g .' *) -(***************************************************************************) -THEOREM RuleWF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ WF_f(A) /\ []F /\ <>[]EM => <>[]P - PROVE [][N]_f /\ WF_f(A) /\ []F => []<><>_g \/ []<>(~EM) - -THEOREM RuleSF2 == ASSUME STATE P, STATE f, STATE g, STATE EM, - ACTION A, ACTION B, ACTION N, ACTION M, - TEMPORAL F, - <>_f => <>_g, - P /\ P' /\ <>_f /\ EM => B, - P /\ EM => ENABLED A, - [][N /\ ~B]_f /\ SF_f(A) /\ []F /\ []<>EM => <>[]P - PROVE [][N]_f /\ SF_f(A) /\ []F => []<><>_g \/ <>[](~EM) - - -(***************************************************************************) -(* The following rule is a special case of the general temporal logic *) -(* proof rule STL4 from the paper "The Temporal Logic of Actions". The *) -(* general rule is for arbitrary temporal formulas F and G, but it cannot *) -(* yet be handled by TLAPS. *) -(***************************************************************************) -THEOREM RuleInvImplication == - ASSUME STATE F, STATE G, - F => G - PROVE []F => []G -PROOF OMITTED - -(***************************************************************************) -(* The following rule is a special case of rule TLA2 from the paper "The *) -(* Temporal Logic of Actions". *) -(***************************************************************************) -THEOREM RuleStepSimulation == - ASSUME STATE I, STATE f, STATE g, - ACTION M, ACTION N, - I /\ I' /\ [M]_f => [N]_g - PROVE []I /\ [][M]_f => [][N]_g -PROOF OMITTED - -(***************************************************************************) -(* The following may be used to invoke a decision procedure for *) -(* propositional temporal logic. *) -(***************************************************************************) -PropositionalTemporalLogic == TRUE -=============================================================================