├── state-machine
├── StateMachine
├── PlusCalDiagram.png
├── StateMachineDiagram.png
├── README.md
├── StateMachine.tla
└── StateMachine.toolbox
│ └── StateMachine___Model_1.launch
├── extends
├── ExtendsA.tla
├── README.md
├── ExtendsB.toolbox
│ └── ExtendsB___Model_1.launch
└── ExtendsB.tla
├── implements
├── ImplementsA.tla
├── README.md
├── ImplementsB.tla
└── ImplementsB.toolbox
│ └── ImplementsB___Model_1.launch
├── .gitignore
├── race-condition
├── README.md
├── RaceCondition.tla
└── RaceCondition.toolbox
│ └── RaceCondition___Model_1.launch
├── list-operations
├── README.md
├── ListOperations.toolbox
│ └── ListOperations___Model_1.launch
└── ListOperations.tla
├── deadlock
├── Deadlock.toolbox
│ └── Deadlock___Model_1.launch
├── README.md
└── Deadlock.tla
├── count-down
├── README.md
├── CountDown.tla
└── CountDown.toolbox
│ └── CountDown___Model_1.launch
├── linear-search
├── README.md
├── LinearSearch.tla
└── LinearSearch.toolbox
│ └── LinearSearch___Model_1.launch
├── secret-santa
├── README.md
├── SecretSanta.toolbox
│ └── SecretSanta___Model_1.launch
└── SecretSanta.tla
├── simple-logic
├── README.md
├── SimpleLogic.tla
└── SimpleLogic.toolbox
│ └── SimpleLogic___Model_1.launch
├── LICENSE
└── README.md
/state-machine/StateMachine:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/state-machine/PlusCalDiagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lostbearlabs/tiny-tlaplus-examples/HEAD/state-machine/PlusCalDiagram.png
--------------------------------------------------------------------------------
/state-machine/StateMachineDiagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lostbearlabs/tiny-tlaplus-examples/HEAD/state-machine/StateMachineDiagram.png
--------------------------------------------------------------------------------
/extends/ExtendsA.tla:
--------------------------------------------------------------------------------
1 |
2 | ---- MODULE ExtendsA ----
3 | EXTENDS Integers
4 |
5 | \* See README.md
6 |
7 | IsEven(x) == (x % 2) = 0
8 | IsOdd(x) == (x % 2) = 1
9 |
10 | ====
11 |
12 |
13 |
--------------------------------------------------------------------------------
/implements/ImplementsA.tla:
--------------------------------------------------------------------------------
1 |
2 | ---- MODULE ImplementsA ----
3 | LOCAL INSTANCE Integers
4 | CONSTANT A
5 | ASSUME A \in Int
6 |
7 | \* See README.md
8 |
9 | IsEven == (A % 2) = 0
10 | IsOdd == (A % 2) = 1
11 |
12 | ====
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X folder state
2 | .DS_Store
3 |
4 | # Exclude TLA+ Toolbox working state and snapshots
5 | **/*.toolbox/*
6 | # (but include model files)
7 | !**/*.toolbox/*.launch
8 | # (but don't include snapshots of model files)
9 | **/*.toolbox/*_Snapshot_*.launch
10 |
11 |
--------------------------------------------------------------------------------
/race-condition/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: Race Condition
3 |
4 | This is the simplest example I could think of that exhibits a race condition.
5 |
6 | We start with a variable, `count=0`.
7 |
8 | Two processes (`A` and `B`) each attempt to read count and increment it.
9 |
10 | If this were atomic, then we would end with `count=2`, but since the reads can overlap this sometimes fails.
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/list-operations/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: List Operations
3 |
4 | This specification just demonstrates how to perform basic list operations on sequences.
5 |
6 | In addition to using the operators `Append`, `Head`, `Tail`, and `\o` from the `Sequences` module, this example defines two versions of a `Reverse` operator, one in a declarative style and one in a functional style using a recursive operator definition.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/deadlock/Deadlock.toolbox/Deadlock___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/count-down/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: Count Down
3 |
4 | This is a trivial countdown timer that counts from 10 to 0. No rocket
5 | ship is included.
6 |
7 |
8 | To validate that the count decreases, we can either model check with the invariant `CountHasDecreased` or with the equivalent temporal property `CountDecreases`.
9 |
10 | To ensure that the count reaches zero, we can check the temporal property `CountReachesZero`.
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/extends/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: Extends
3 |
4 | This is a trivial example of having one module (`ExtendsB`) extend and use definitions
5 | from another (`ExtendsA`).
6 |
7 | `ExtendsA` just defines the two operators `IsEven` and `IsOdd`.
8 |
9 | `ExtendsB` EXTENDS `ExtendsA` and models a trivial program that exercises the operators.
10 |
11 | When creating a spec in the TLA+ explorer, use `ExtendsB` as the root-module file. The explorer will automatically load both modules into editor tabs.
12 |
13 |
--------------------------------------------------------------------------------
/extends/ExtendsB.toolbox/ExtendsB___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/implements/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: Implements
3 |
4 | This is a trivial example of having one module (`ImplementsB`) extend and use definitions
5 | from another (`ImplementsA`) with parameterization and namespacing.
6 |
7 | `ImplementsA` just defines the (local) variable `A`.
8 |
9 | `ImplementsB` creates two instances of `ImplementsA`, one named `X` and one named `Y`.
10 |
11 | When creating a spec in the TLA+ explorer, use `ImplementsB` as the root-module file. The explorer will automatically load both modules into editor tabs.
12 |
13 |
--------------------------------------------------------------------------------
/state-machine/README.md:
--------------------------------------------------------------------------------
1 | # Tiny TLA+ Example: State Machine
2 |
3 | This example models a trivial state machine that accepts the regular expression `X*Y` (i.e. zero or more X followed by a Y).
4 |
5 | The state diagram looks like this:
6 |
7 | 
8 |
9 | Since we have modelled the machine using PlusCal, the TLA+ model also includes a variable called `PC` (for "program counter") representing the current point of execution. The model checker therefore finds *4* states (instead of 3) with the following state diagram:
10 |
11 |
12 | 
13 |
--------------------------------------------------------------------------------
/linear-search/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: Linear Search
3 |
4 | This is an extremely simple example of using TLA+ to validate the behavior of a single-threaded algorithm.
5 |
6 | This is adapted from the the binary search example at:
7 | http://herbrete.vvv.enseirb-matmeca.fr/IF311/lecture01.xhtml
8 |
9 |
10 | To validate this algorithm, create a model with values like
11 |
12 | ```
13 | N = 3
14 | MAXINT = 5
15 | ```
16 |
17 | The model checker will examine all MAXINT^N possible input arrays for
18 | all MAXINT possible values of X and ensure the correct result is returned.
19 |
20 | To see the model checker FAIL, just break the final condition, for example
21 | by specifying `ar[j] = x-1`
22 |
23 |
24 |
--------------------------------------------------------------------------------
/deadlock/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: Deadlock
3 |
4 | This is the simplest example I could think of that exhibits deadlock.
5 |
6 | Two processes (`A` and `B`) compete for two resources (`Lock1` and `Lock2`).
7 |
8 | There are no invariants or properties to check here. Just create a default model and run it, and it will fail with a reported deadlock. A typical example looks like this in the stack trace:
9 |
10 |
11 | ```
12 | lock_holder: <<"A", "B">>
13 | pc: [A |-> "Lock2", B |-> "Lock1"]
14 | ```
15 |
16 | In this case, `Lock1` is held by `A` (the first element of `lock_holder`) and `Lock2` is held by `B`. `A` now wants to acquire `Lock2` and `B` wants to acquire `Lock1`, so nobody can proceed.
17 |
18 |
19 |
--------------------------------------------------------------------------------
/secret-santa/README.md:
--------------------------------------------------------------------------------
1 | # Tiny TLA+ Example: Secret Santa
2 |
3 | This is an extremely simple example of using TLA+ to model a concurrent system.
4 |
5 | In our system, we have N people participating in a "Secret Santa" exchange. Each person is assigned one other person to give a gift to. They can do this in any order. Once the exchange completes, we expect each person to have received a gift.
6 |
7 | There's no opportunity for deadlock here.
8 |
9 | To validate that the exchange succeeds, create a model with values like
10 |
11 | ```
12 | N = 3
13 | ```
14 |
15 | The model can also specify the invariants
16 |
17 | ```
18 | Termination
19 | EverybodyGetsAGift
20 | ```
21 |
22 | The model checker will run the gift exchange with every possible assignment
23 | of givers to receivers and confirm that they all succeed.
24 |
25 |
--------------------------------------------------------------------------------
/simple-logic/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Tiny TLA+ Example: Simple Logic
3 |
4 | This is a TLA+ module that asserts some simple logical formulas to
5 | be true. It is modeled on https://github.com/tlaplus/Examples/blob/master/specifications/SpecifyingSystems/SimpleMath/SimpleMath.tla
6 |
7 | Running model code like this is a good way to:
8 |
9 | * confirm your grasp of TLA+ mathematical syntax
10 | * check truth-tables if your 1st order logic is rusty
11 | * etc.
12 |
13 | You can run this model with the model checker specifying the invariant `Implication`.
14 |
15 |
16 | At the end of the TLA file there is also an `ASSUME` statement. This is checked as part of loading the model, and it covers exactly the same logical equation in a single statement. You can execute this test by running the model checker with **No behavior spec** selected. If you try this with a broken formula, for example by changing the last clause from `~F \/ G` to `~F \/ ~G` the model checking results will show you an error even though no state count or other model checking information is generated.
17 |
--------------------------------------------------------------------------------
/extends/ExtendsB.tla:
--------------------------------------------------------------------------------
1 |
2 | ---- MODULE ExtendsB ----
3 |
4 | EXTENDS ExtendsA, TLC
5 |
6 | \* see README.md
7 |
8 | (*--algorithm ExtendsB
9 | begin
10 |
11 | assert( IsEven(2) );
12 | assert( IsEven(-2) );
13 | assert( IsOdd(3) );
14 | assert( IsOdd(-3) );
15 |
16 | end algorithm;*)
17 | \* BEGIN TRANSLATION
18 | VARIABLE pc
19 |
20 | vars == << pc >>
21 |
22 | Init == /\ pc = "Lbl_1"
23 |
24 | Lbl_1 == /\ pc = "Lbl_1"
25 | /\ Assert(( IsEven(2) ),
26 | "Failure of assertion at line 11, column 1.")
27 | /\ Assert(( IsEven(-2) ),
28 | "Failure of assertion at line 12, column 1.")
29 | /\ Assert(( IsOdd(3) ),
30 | "Failure of assertion at line 13, column 1.")
31 | /\ Assert(( IsOdd(-3) ),
32 | "Failure of assertion at line 14, column 1.")
33 | /\ pc' = "Done"
34 |
35 | Next == Lbl_1
36 | \/ (* Disjunct to prevent deadlock on termination *)
37 | (pc = "Done" /\ UNCHANGED vars)
38 |
39 | Spec == Init /\ [][Next]_vars
40 |
41 | Termination == <>(pc = "Done")
42 |
43 | \* END TRANSLATION
44 |
45 | ====
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/linear-search/LinearSearch.tla:
--------------------------------------------------------------------------------
1 | ---------------------------- MODULE LinearSearch ----------------------------
2 |
3 | \* See README.md
4 |
5 | EXTENDS Naturals, TLC
6 |
7 | CONSTANT N (* Size of arrays *)
8 | CONSTANT MAXINT (* Max integer value *)
9 |
10 | (* PlusCal options (-termination) *)
11 |
12 | (*--algorithm LinearSearch
13 |
14 | variables
15 | ar \in [ 1..N -> 0..MAXINT ], (* Array of N integers in 0..MAXINT *)
16 | x \in 0..MAXINT, (* Value to find *)
17 | found = FALSE,
18 | i = 1;
19 |
20 | begin
21 |
22 | Loop:
23 | while i <= N /\ ~found do
24 | found := ar[i]=x;
25 | i := i + 1;
26 | end while;
27 |
28 | FinalCheck:
29 | assert( found <=> (\E j \in 1..N : ar[j] = x) )
30 |
31 | end algorithm;*)
32 | \* BEGIN TRANSLATION
33 | VARIABLES ar, x, found, i, pc
34 |
35 | vars == << ar, x, found, i, pc >>
36 |
37 | Init == (* Global variables *)
38 | /\ ar \in [ 1..N -> 0..MAXINT ]
39 | /\ x \in 0..MAXINT
40 | /\ found = FALSE
41 | /\ i = 1
42 | /\ pc = "Loop"
43 |
44 | Loop == /\ pc = "Loop"
45 | /\ IF i <= N /\ ~found
46 | THEN /\ found' = (ar[i]=x)
47 | /\ i' = i + 1
48 | /\ pc' = "Loop"
49 | ELSE /\ pc' = "FinalCheck"
50 | /\ UNCHANGED << found, i >>
51 | /\ UNCHANGED << ar, x >>
52 |
53 | FinalCheck == /\ pc = "FinalCheck"
54 | /\ Assert(( found <=> (\E j \in 1..N : ar[j] = x) ),
55 | "Failure of assertion at line 29, column 5.")
56 | /\ pc' = "Done"
57 | /\ UNCHANGED << ar, x, found, i >>
58 |
59 | Next == Loop \/ FinalCheck
60 | \/ (* Disjunct to prevent deadlock on termination *)
61 | (pc = "Done" /\ UNCHANGED vars)
62 |
63 | Spec == /\ Init /\ [][Next]_vars
64 | /\ WF_vars(Next)
65 |
66 | Termination == <>(pc = "Done")
67 |
68 | \* END TRANSLATION
69 |
70 | =============================================================================
71 |
--------------------------------------------------------------------------------
/state-machine/StateMachine.tla:
--------------------------------------------------------------------------------
1 | ---------------------------- MODULE StateMachine ----------------------------
2 |
3 | \* See README.md
4 |
5 | (*--fair algorithm stateMachine
6 | variables
7 | state = "start";
8 |
9 | define
10 | \* INVARIANT: we should always be in a valid state
11 | StateValid == state \in {"start", "reading", "end"}
12 |
13 | \* TEMPORAL FORMULA: since the process is fair, we will always
14 | \* eventually get a Y and terminate, and once we terminate we will
15 | \* stay terminated.
16 | \*
17 | \* NOTE: this condition does not actually hold true.
18 | \* See: https://stackoverflow.com/questions/55128505/tla-why-does-fair-algorithm-still-stutter
19 | MachineTerminates == <>[](state = "end")
20 | end define;
21 |
22 | begin
23 |
24 |
25 | Loop:
26 | while state /= "end" do
27 | either
28 | \* we got an X, keep going
29 | state := "reading"
30 | or
31 | \* we got a Y, terminate
32 | state := "end"
33 | end either;
34 | end while;
35 |
36 |
37 | end algorithm;*)
38 | \* BEGIN TRANSLATION
39 | VARIABLES state, pc
40 |
41 | (* define statement *)
42 | StateValid == state \in {"start", "reading", "end"}
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | MachineTerminates == <>[](state = "end")
51 |
52 |
53 | vars == << state, pc >>
54 |
55 | Init == (* Global variables *)
56 | /\ state = "start"
57 | /\ pc = "Loop"
58 |
59 | Loop == /\ pc = "Loop"
60 | /\ IF state /= "end"
61 | THEN /\ \/ /\ state' = "reading"
62 | \/ /\ state' = "end"
63 | /\ pc' = "Loop"
64 | ELSE /\ pc' = "Done"
65 | /\ state' = state
66 |
67 | Next == Loop
68 | \/ (* Disjunct to prevent deadlock on termination *)
69 | (pc = "Done" /\ UNCHANGED vars)
70 |
71 | Spec == /\ Init /\ [][Next]_vars
72 | /\ WF_vars(Next)
73 |
74 | Termination == <>(pc = "Done")
75 |
76 | \* END TRANSLATION
77 |
78 |
79 | =============================================================================
80 |
--------------------------------------------------------------------------------
/count-down/CountDown.tla:
--------------------------------------------------------------------------------
1 | ---------------------------- MODULE CountDown ----------------------------
2 |
3 | \* See README.md
4 |
5 | EXTENDS Naturals, TLC
6 |
7 | (* PlusCal options (-termination) *)
8 |
9 | (*--algorithm LinearSearch
10 |
11 | variables
12 | N = 10,
13 | i = N,
14 | prev = i+1;
15 |
16 | define
17 | \* Invariant for the model checker: i is less than prev
18 | \* This is a safety condition we can check in every state
19 | CountHasDecreased == i(i=0)
28 | end define;
29 |
30 | begin
31 |
32 | while i > 0 do
33 | prev := i;
34 | i := i - 1;
35 | end while;
36 |
37 |
38 | end algorithm;*)
39 | \* BEGIN TRANSLATION
40 | VARIABLES N, i, prev, pc
41 |
42 | (* define statement *)
43 | CountHasDecreased == i(i=0)
52 |
53 |
54 | vars == << N, i, prev, pc >>
55 |
56 | Init == (* Global variables *)
57 | /\ N = 10
58 | /\ i = N
59 | /\ prev = i+1
60 | /\ pc = "Lbl_1"
61 |
62 | Lbl_1 == /\ pc = "Lbl_1"
63 | /\ IF i > 0
64 | THEN /\ prev' = i
65 | /\ i' = i - 1
66 | /\ pc' = "Lbl_1"
67 | ELSE /\ pc' = "Done"
68 | /\ UNCHANGED << i, prev >>
69 | /\ N' = N
70 |
71 | Next == Lbl_1
72 | \/ (* Disjunct to prevent deadlock on termination *)
73 | (pc = "Done" /\ UNCHANGED vars)
74 |
75 | Spec == /\ Init /\ [][Next]_vars
76 | /\ WF_vars(Next)
77 |
78 | Termination == <>(pc = "Done")
79 |
80 | \* END TRANSLATION
81 | =============================================================================
82 |
--------------------------------------------------------------------------------
/race-condition/RaceCondition.tla:
--------------------------------------------------------------------------------
1 | ---------------------------- MODULE RaceCondition ----------------------------
2 |
3 | \* See README.md
4 |
5 | EXTENDS Integers, TLC
6 |
7 | (* PlusCal options (-termination) *)
8 |
9 | (*--algorithm RaceCondition
10 |
11 | variables
12 | count = 0;
13 |
14 | define
15 | \* Temporal property to check: After each of our two processes has incremented
16 | \* count, count should be 2. (This fails because one process may read a stale value
17 | \* while the other is in the middle of incrementing.)
18 | CountReachesTwo == <>[](count=2)
19 | end define;
20 |
21 | process p \in {"A", "B"}
22 | variable v = -1;
23 | begin
24 | Read:
25 | v := count;
26 | Write:
27 | count := v+1;
28 | end process;
29 |
30 | end algorithm;*)
31 | \* BEGIN TRANSLATION
32 | VARIABLES count, pc
33 |
34 | (* define statement *)
35 | CountReachesTwo == <>[](count=2)
36 |
37 | VARIABLE v
38 |
39 | vars == << count, pc, v >>
40 |
41 | ProcSet == ({"A", "B"})
42 |
43 | Init == (* Global variables *)
44 | /\ count = 0
45 | (* Process p *)
46 | /\ v = [self \in {"A", "B"} |-> -1]
47 | /\ pc = [self \in ProcSet |-> "Read"]
48 |
49 | Read(self) == /\ pc[self] = "Read"
50 | /\ v' = [v EXCEPT ![self] = count]
51 | /\ pc' = [pc EXCEPT ![self] = "Write"]
52 | /\ count' = count
53 |
54 | Write(self) == /\ pc[self] = "Write"
55 | /\ count' = v[self]+1
56 | /\ pc' = [pc EXCEPT ![self] = "Done"]
57 | /\ v' = v
58 |
59 | p(self) == Read(self) \/ Write(self)
60 |
61 | Next == (\E self \in {"A", "B"}: p(self))
62 | \/ (* Disjunct to prevent deadlock on termination *)
63 | ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars)
64 |
65 | Spec == /\ Init /\ [][Next]_vars
66 | /\ \A self \in {"A", "B"} : WF_vars(p(self))
67 |
68 | Termination == <>(\A self \in ProcSet: pc[self] = "Done")
69 |
70 | \* END TRANSLATION
71 |
72 | \* END TRANSLATION
73 |
74 | =============================================================================
75 |
--------------------------------------------------------------------------------
/simple-logic/SimpleLogic.tla:
--------------------------------------------------------------------------------
1 | ---------------------------- MODULE SimpleLogic ----------------------------
2 |
3 | (***************************************************************************)
4 | (* Some simple experiments in logic *)
5 | (***************************************************************************)
6 |
7 | VARIABLES X, Y
8 |
9 | vars == << X, Y >>
10 |
11 |
12 | (***************************************************************************)
13 | (* Discover all entries in a 2-value truth table. *)
14 | (* *)
15 | (* This Init/Next spec will visit all 4 entries. Since state transitions *)
16 | (* are arbitrary, it will never deadlock. *)
17 | (***************************************************************************)
18 |
19 | Init ==
20 | /\ X \in {TRUE, FALSE}
21 | /\ Y \in {TRUE, FALSE}
22 |
23 | Next ==
24 | /\ X' \in {TRUE, FALSE}
25 | /\ Y' \in {TRUE, FALSE}
26 |
27 | (***************************************************************************)
28 | (* Check the definition of implication. *)
29 | (* -> Specify Implication as an invariant of the model. *)
30 | (***************************************************************************)
31 |
32 | Foo ==
33 | /\ X => Y
34 |
35 | Bar ==
36 | /\ ~X \/ Y
37 |
38 | Implication ==
39 | /\ (Foo = Bar)
40 |
41 |
42 |
43 |
44 |
45 | (***************************************************************************)
46 | (* Check the same thing using an ASSUME. *)
47 | (* No model steps necessary, you can run the model with no behavioral spec.*)
48 | (***************************************************************************)
49 |
50 | ASSUME
51 | \A F, G \in {TRUE, FALSE} : (F => G) <=> ~F \/ G
52 |
53 |
54 |
55 | =============================================================================
56 | \* Modification History
57 | \* Last modified Mon Apr 01 16:45:57 CDT 2019 by eric.johnson
58 | \* Created Thu Oct 11 15:43:40 CDT 2018 by eric.johnson
59 |
60 |
--------------------------------------------------------------------------------
/implements/ImplementsB.tla:
--------------------------------------------------------------------------------
1 |
2 | ---- MODULE ImplementsB ----
3 |
4 | EXTENDS TLC, Integers
5 |
6 | \* see README.md
7 |
8 |
9 |
10 | (*--algorithm ImplementsB
11 | variables
12 | a = 2,
13 | b = 3;
14 |
15 | define
16 | \* We can initialize our instances from variables, but
17 | \* as we see below, changing the variable does not then update
18 | \* the instance
19 | X == INSTANCE ImplementsA WITH A <- a
20 | Y == INSTANCE ImplementsA WITH A <- b
21 | \* We can also have an instance that requires parameters
22 | \* when it's used.
23 | Z(A) == INSTANCE ImplementsA
24 | end define;
25 |
26 | begin
27 |
28 | assert( X!IsEven );
29 | assert( Y!IsOdd );
30 |
31 | \* This changes a but not X!A
32 | a := 3;
33 | assert( X!IsEven );
34 |
35 | \* This changes Z!A
36 | a := 3;
37 | assert( Z(a)!IsOdd );
38 | a := 4;
39 | assert( Z(a)!IsEven );
40 |
41 |
42 | end algorithm;*)
43 | \* BEGIN TRANSLATION
44 | VARIABLES a, b, pc
45 |
46 | (* define statement *)
47 | X == INSTANCE ImplementsA WITH A <- a
48 | Y == INSTANCE ImplementsA WITH A <- b
49 |
50 |
51 | Z(A) == INSTANCE ImplementsA
52 |
53 |
54 | vars == << a, b, pc >>
55 |
56 | Init == (* Global variables *)
57 | /\ a = 2
58 | /\ b = 3
59 | /\ pc = "Lbl_1"
60 |
61 | Lbl_1 == /\ pc = "Lbl_1"
62 | /\ Assert(( X!IsEven ),
63 | "Failure of assertion at line 28, column 1.")
64 | /\ Assert(( Y!IsOdd ), "Failure of assertion at line 29, column 1.")
65 | /\ a' = 3
66 | /\ Assert(( X!IsEven ),
67 | "Failure of assertion at line 33, column 1.")
68 | /\ pc' = "Lbl_2"
69 | /\ b' = b
70 |
71 | Lbl_2 == /\ pc = "Lbl_2"
72 | /\ a' = 3
73 | /\ Assert(( Z(a')!IsOdd ),
74 | "Failure of assertion at line 37, column 1.")
75 | /\ pc' = "Lbl_3"
76 | /\ b' = b
77 |
78 | Lbl_3 == /\ pc = "Lbl_3"
79 | /\ a' = 4
80 | /\ Assert(( Z(a')!IsEven ),
81 | "Failure of assertion at line 39, column 1.")
82 | /\ pc' = "Done"
83 | /\ b' = b
84 |
85 | Next == Lbl_1 \/ Lbl_2 \/ Lbl_3
86 | \/ (* Disjunct to prevent deadlock on termination *)
87 | (pc = "Done" /\ UNCHANGED vars)
88 |
89 | Spec == Init /\ [][Next]_vars
90 |
91 | Termination == <>(pc = "Done")
92 |
93 | \* END TRANSLATION
94 |
95 | ====
96 |
--------------------------------------------------------------------------------
/implements/ImplementsB.toolbox/ImplementsB___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/simple-logic/SimpleLogic.toolbox/SimpleLogic___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/race-condition/RaceCondition.toolbox/RaceCondition___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/state-machine/StateMachine.toolbox/StateMachine___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tiny-tlaplus-examples
2 |
3 | ## Description
4 |
5 | This repo contains *very small* examples of TLA+ functionality or applications, intended to help you learn TLA+.
6 |
7 | For more sophisticated examples, see:
8 |
9 | * https://github.com/tlaplus/Examples
10 | * https://www.hillelwayne.com/post/list-of-tla-examples/
11 |
12 | ## List of Examples
13 |
14 | ### [state-machine](./state-machine)
15 |
16 |
17 | TLA+ works by modeling systems via state machines. If we model an actual state machine this way, how does the generated state graph compare to the machine we're modeling?
18 |
19 | `#safety`
20 |
21 | ### [linear-search](./linear-search)
22 |
23 | What does it look like to validate the correctness of a procedural algorithm?
24 |
25 | `#correctness`
26 |
27 | ### [secret-santa](./secret-santa)
28 |
29 | What does it look like to model a concurrent system?
30 |
31 | `#concurrency` `#safety` `#correctness`
32 |
33 | ### [count-down](./count-down)
34 |
35 | What does it look like to specify a temporal condition?
36 |
37 | `#correctness`
38 |
39 | ### [simple-logic](./simple-logic)
40 |
41 | How can you use TLA+ to validate formulas in predicate logic?
42 |
43 | `#correctness`
44 |
45 | ### [deadlock](./deadlock)
46 |
47 | How can you use TLA+ to find deadlocks in a concurrent system?
48 |
49 | `#concurrency` `#liveness`
50 |
51 | ### [race-condition](./race-condition)
52 |
53 | What does it look like when two processes interact incorrectly due to a race condition?
54 |
55 | `#concurrency` `#safety`
56 |
57 | ### [extends](./extends)
58 |
59 | How can one module use operators defined in another module?
60 |
61 | `#modules`
62 |
63 | ### [implements](./implements)
64 |
65 | How can one module parameterize and/or namespace operators defined in another module?
66 |
67 | `#modules`
68 |
69 | ### [list-operations](./list-operations)
70 |
71 | Basic functional list operations(Head/Tail/Append/Len/Reverse) on sequences.
72 |
73 | `#sequences` `#recursion`
74 |
75 |
76 | ## Contributing
77 |
78 | Contributions are welcome.
79 | * Please make sure examples are *very small*.
80 | * Put each example in its own subfolder with a README.md file. (These examples use README files instead of putting all documentation into the spec itself so that they will be easier to explore on Github. As soon as a user navigates to a folder they will be reading the documentation in their browser, rather than having to navigate into the individual spec file.)
81 | * Name sub-folders and examples using the existing pattern of "spec-name" for the folder and "SpecName.tla" for the TLA+ file.
82 |
--------------------------------------------------------------------------------
/linear-search/LinearSearch.toolbox/LinearSearch___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/secret-santa/SecretSanta.toolbox/SecretSanta___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/count-down/CountDown.toolbox/CountDown___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/list-operations/ListOperations.toolbox/ListOperations___Model_1.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/secret-santa/SecretSanta.tla:
--------------------------------------------------------------------------------
1 | ---------------------------- MODULE SecretSanta ----------------------------
2 |
3 | \* See README.md
4 |
5 | EXTENDS Naturals, TLC
6 |
7 | CONSTANT N (* Number of participants *)
8 |
9 | (* PlusCal options (-termination) *)
10 |
11 | (*--algorithm SecretSanta
12 |
13 | variables
14 | (* a legal assignment maps each giver to a unique receiver different from themself *)
15 | assignment \in {p \in Permutations(1..N) : (\A i \in (1..N): (p[i] /= i))},
16 | (* keep track of who has received a gift *)
17 | received = [ i \in 1..N |-> FALSE],
18 | (* keep track of how many gifts have been given *)
19 | gifts_given = 0;
20 |
21 | define
22 | (* Temporal Invariant -- add this as a property of the model.
23 | Eventually everybody has a gift. *)
24 | EverybodyGetsGift == <>[]( \A i \in 1..N: received[i] )
25 | end define;
26 |
27 |
28 | (* Everybody will, in their own time, give a gift to their assigned receiver *)
29 | process giver \in (1..N)
30 | variables
31 | recipient = assignment[ self ];
32 | begin
33 | Give:
34 | received[ recipient ] := TRUE;
35 | gifts_given := gifts_given + 1;
36 | end process;
37 |
38 | (* We could also have a monitor who checks that the gift exchange has
39 | succeeded. For this spec it's redundant since we have a stronger
40 | check with the invariant EverybodyGetsGift. But if it were possible
41 | for some behaviors where everybody gives their gift and some behaviors
42 | where the exchange never finishes, then this monitor would still validate
43 | the end state for behaviors where the exchange does complete. *)
44 | process monitor = N+1
45 | begin
46 | Monitor:
47 | await gifts_given=N;
48 | assert( \A i \in 1..N : received[i])
49 | end process;
50 |
51 |
52 | end algorithm;*)
53 | \* BEGIN TRANSLATION
54 | VARIABLES assignment, received, gifts_given, pc
55 |
56 | (* define statement *)
57 | EverybodyGetsGift == <>[]( \A i \in 1..N: received[i] )
58 |
59 | VARIABLE recipient
60 |
61 | vars == << assignment, received, gifts_given, pc, recipient >>
62 |
63 | ProcSet == ((1..N)) \cup {N+1}
64 |
65 | Init == (* Global variables *)
66 | /\ assignment \in {p \in Permutations(1..N) : (\A i \in (1..N): (p[i] /= i))}
67 | /\ received = [ i \in 1..N |-> FALSE]
68 | /\ gifts_given = 0
69 | (* Process giver *)
70 | /\ recipient = [self \in (1..N) |-> assignment[ self ]]
71 | /\ pc = [self \in ProcSet |-> CASE self \in (1..N) -> "Give"
72 | [] self = N+1 -> "Monitor"]
73 |
74 | Give(self) == /\ pc[self] = "Give"
75 | /\ received' = [received EXCEPT ![ recipient[self] ] = TRUE]
76 | /\ gifts_given' = gifts_given + 1
77 | /\ pc' = [pc EXCEPT ![self] = "Done"]
78 | /\ UNCHANGED << assignment, recipient >>
79 |
80 | giver(self) == Give(self)
81 |
82 | Monitor == /\ pc[N+1] = "Monitor"
83 | /\ gifts_given=N
84 | /\ Assert(( \A i \in 1..N : received[i]),
85 | "Failure of assertion at line 48, column 5.")
86 | /\ pc' = [pc EXCEPT ![N+1] = "Done"]
87 | /\ UNCHANGED << assignment, received, gifts_given, recipient >>
88 |
89 | monitor == Monitor
90 |
91 | Next == monitor
92 | \/ (\E self \in (1..N): giver(self))
93 | \/ (* Disjunct to prevent deadlock on termination *)
94 | ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars)
95 |
96 | Spec == /\ Init /\ [][Next]_vars
97 | /\ \A self \in (1..N) : WF_vars(giver(self))
98 | /\ WF_vars(monitor)
99 |
100 | Termination == <>(\A self \in ProcSet: pc[self] = "Done")
101 |
102 | \* END TRANSLATION
103 |
104 | =============================================================================
105 |
--------------------------------------------------------------------------------
/deadlock/Deadlock.tla:
--------------------------------------------------------------------------------
1 | ---------------------------- MODULE Deadlock ----------------------------
2 |
3 | \* See README.md
4 |
5 | EXTENDS Integers, TLC
6 |
7 | (*--algorithm Deadlock
8 |
9 | variables
10 | NOBODY = "",
11 | COMPETITORS = {"A", "B"},
12 | LOCKS = {1, 2},
13 | lock_holder = [ i \in LOCKS |-> NOBODY ];
14 |
15 | define
16 | NotHeldByOther(lock, me) == lock_holder[lock]=me \/ lock_holder[lock]=NOBODY
17 | end define;
18 |
19 | process competitor \in COMPETITORS
20 | begin
21 | Loop:
22 | while TRUE do
23 | either
24 | Lock1:
25 | await NotHeldByOther(1, self);
26 | lock_holder[1] := self;
27 | or
28 | Lock2:
29 | await NotHeldByOther(2, self);
30 | lock_holder[2] := self;
31 | or
32 | Unlock1:
33 | if lock_holder[1] = self then
34 | lock_holder[1] := NOBODY;
35 | end if;
36 | or
37 | Unlock2:
38 | if lock_holder[2] = self then
39 | lock_holder[2] := NOBODY;
40 | end if;
41 | end either;
42 | end while;
43 | end process;
44 |
45 |
46 |
47 | end algorithm;*)
48 | \* BEGIN TRANSLATION
49 | VARIABLES NOBODY, COMPETITORS, LOCKS, lock_holder, pc
50 |
51 | (* define statement *)
52 | NotHeldByOther(lock, me) == lock_holder[lock]=me \/ lock_holder[lock]=NOBODY
53 |
54 |
55 | vars == << NOBODY, COMPETITORS, LOCKS, lock_holder, pc >>
56 |
57 | ProcSet == (COMPETITORS)
58 |
59 | Init == (* Global variables *)
60 | /\ NOBODY = ""
61 | /\ COMPETITORS = {"A", "B"}
62 | /\ LOCKS = {1, 2}
63 | /\ lock_holder = [ i \in LOCKS |-> NOBODY ]
64 | /\ pc = [self \in ProcSet |-> "Loop"]
65 |
66 | Loop(self) == /\ pc[self] = "Loop"
67 | /\ \/ /\ pc' = [pc EXCEPT ![self] = "Lock1"]
68 | \/ /\ pc' = [pc EXCEPT ![self] = "Lock2"]
69 | \/ /\ pc' = [pc EXCEPT ![self] = "Unlock1"]
70 | \/ /\ pc' = [pc EXCEPT ![self] = "Unlock2"]
71 | /\ UNCHANGED << NOBODY, COMPETITORS, LOCKS, lock_holder >>
72 |
73 | Lock1(self) == /\ pc[self] = "Lock1"
74 | /\ NotHeldByOther(1, self)
75 | /\ lock_holder' = [lock_holder EXCEPT ![1] = self]
76 | /\ pc' = [pc EXCEPT ![self] = "Loop"]
77 | /\ UNCHANGED << NOBODY, COMPETITORS, LOCKS >>
78 |
79 | Lock2(self) == /\ pc[self] = "Lock2"
80 | /\ NotHeldByOther(2, self)
81 | /\ lock_holder' = [lock_holder EXCEPT ![2] = self]
82 | /\ pc' = [pc EXCEPT ![self] = "Loop"]
83 | /\ UNCHANGED << NOBODY, COMPETITORS, LOCKS >>
84 |
85 | Unlock1(self) == /\ pc[self] = "Unlock1"
86 | /\ IF lock_holder[1] = self
87 | THEN /\ lock_holder' = [lock_holder EXCEPT ![1] = NOBODY]
88 | ELSE /\ TRUE
89 | /\ UNCHANGED lock_holder
90 | /\ pc' = [pc EXCEPT ![self] = "Loop"]
91 | /\ UNCHANGED << NOBODY, COMPETITORS, LOCKS >>
92 |
93 | Unlock2(self) == /\ pc[self] = "Unlock2"
94 | /\ IF lock_holder[2] = self
95 | THEN /\ lock_holder' = [lock_holder EXCEPT ![2] = NOBODY]
96 | ELSE /\ TRUE
97 | /\ UNCHANGED lock_holder
98 | /\ pc' = [pc EXCEPT ![self] = "Loop"]
99 | /\ UNCHANGED << NOBODY, COMPETITORS, LOCKS >>
100 |
101 | competitor(self) == Loop(self) \/ Lock1(self) \/ Lock2(self)
102 | \/ Unlock1(self) \/ Unlock2(self)
103 |
104 | Next == (\E self \in COMPETITORS: competitor(self))
105 |
106 | Spec == Init /\ [][Next]_vars
107 |
108 | \* END TRANSLATION
109 |
110 | =============================================================================
111 |
--------------------------------------------------------------------------------
/list-operations/ListOperations.tla:
--------------------------------------------------------------------------------
1 | --------------------------- MODULE ListOperations ---------------------------
2 |
3 | \* See README.md
4 |
5 | EXTENDS Naturals, Sequences, TLC
6 |
7 | CONSTANT N (* Number of elements *)
8 |
9 | (* PlusCal options (-termination) *)
10 |
11 | (*--algorithm ListOperations
12 |
13 | variables
14 | list = << >>,
15 | rlist = << >>,
16 | i = 1;
17 |
18 | define
19 | \* List reversal operator in declarative style
20 | Reverse(seq) == [ j \in 1..Len(seq) |-> seq[ Len(seq) - j + 1 ] ]
21 |
22 | \* List reversal operator in functional style
23 | RECURSIVE RecursiveReverse2(_, _)
24 | RecursiveReverse2(seq, accum) == IF seq = <<>> THEN accum ELSE RecursiveReverse2( Tail(seq), << Head(seq) >> \o accum )
25 | RecursiveReverse(seq) == RecursiveReverse2(seq, << >>)
26 | end define;
27 |
28 | begin
29 |
30 | Loop:
31 | while i <= N do
32 |
33 | AppendToList:
34 | list := Append(list, i);
35 | rlist := << i >> \o rlist;
36 |
37 | CheckList:
38 | assert( Head(list) = 1 );
39 | assert( Head(rlist) = i );
40 |
41 | assert( list[i] = i );
42 | assert( rlist[i] = 1 );
43 |
44 | assert( Len(list) = i );
45 | assert( Len(rlist) = i );
46 |
47 | assert( Reverse(list) = rlist );
48 | assert( Reverse(rlist) = list );
49 |
50 | assert( RecursiveReverse(list) = rlist );
51 | assert( RecursiveReverse(rlist) = list );
52 |
53 | IncrementCounter:
54 | i := i + 1;
55 |
56 | end while;
57 |
58 |
59 | end algorithm;*)
60 | \* BEGIN TRANSLATION
61 | VARIABLES list, rlist, i, pc
62 |
63 | (* define statement *)
64 | Reverse(seq) == [ j \in 1..Len(seq) |-> seq[ Len(seq) - j + 1 ] ]
65 |
66 |
67 | RECURSIVE RecursiveReverse2(_, _)
68 | RecursiveReverse2(seq, accum) == IF seq = <<>> THEN accum ELSE RecursiveReverse2( Tail(seq), << Head(seq) >> \o accum )
69 | RecursiveReverse(seq) == RecursiveReverse2(seq, << >>)
70 |
71 |
72 | vars == << list, rlist, i, pc >>
73 |
74 | Init == (* Global variables *)
75 | /\ list = << >>
76 | /\ rlist = << >>
77 | /\ i = 1
78 | /\ pc = "Loop"
79 |
80 | Loop == /\ pc = "Loop"
81 | /\ IF i <= N
82 | THEN /\ pc' = "AppendToList"
83 | ELSE /\ pc' = "Done"
84 | /\ UNCHANGED << list, rlist, i >>
85 |
86 | AppendToList == /\ pc = "AppendToList"
87 | /\ list' = Append(list, i)
88 | /\ rlist' = << i >> \o rlist
89 | /\ pc' = "CheckList"
90 | /\ i' = i
91 |
92 | CheckList == /\ pc = "CheckList"
93 | /\ Assert(( Head(list) = 1 ),
94 | "Failure of assertion at line 38, column 9.")
95 | /\ Assert(( Head(rlist) = i ),
96 | "Failure of assertion at line 39, column 9.")
97 | /\ Assert(( list[i] = i ),
98 | "Failure of assertion at line 41, column 9.")
99 | /\ Assert(( rlist[i] = 1 ),
100 | "Failure of assertion at line 42, column 9.")
101 | /\ Assert(( Len(list) = i ),
102 | "Failure of assertion at line 44, column 9.")
103 | /\ Assert(( Len(rlist) = i ),
104 | "Failure of assertion at line 45, column 9.")
105 | /\ Assert(( Reverse(list) = rlist ),
106 | "Failure of assertion at line 47, column 9.")
107 | /\ Assert(( Reverse(rlist) = list ),
108 | "Failure of assertion at line 48, column 9.")
109 | /\ Assert(( RecursiveReverse(list) = rlist ),
110 | "Failure of assertion at line 50, column 9.")
111 | /\ Assert(( RecursiveReverse(rlist) = list ),
112 | "Failure of assertion at line 51, column 9.")
113 | /\ pc' = "IncrementCounter"
114 | /\ UNCHANGED << list, rlist, i >>
115 |
116 | IncrementCounter == /\ pc = "IncrementCounter"
117 | /\ i' = i + 1
118 | /\ pc' = "Loop"
119 | /\ UNCHANGED << list, rlist >>
120 |
121 | Next == Loop \/ AppendToList \/ CheckList \/ IncrementCounter
122 | \/ (* Disjunct to prevent deadlock on termination *)
123 | (pc = "Done" /\ UNCHANGED vars)
124 |
125 | Spec == /\ Init /\ [][Next]_vars
126 | /\ WF_vars(Next)
127 |
128 | Termination == <>(pc = "Done")
129 |
130 | \* END TRANSLATION
131 |
132 | =============================================================================
133 |
--------------------------------------------------------------------------------