# Writing algorithms with the TLA toolbox

The following exercises use the TLA toolbox for writing and proving PlusCal algorithms. A local installation of the toolbox is available under ~herbrete/public/TLA/toolbox. Add this path to your environment variable PATH (in your local configuration file) and update your environment (applying the source command on the updated configuration file). The TLA toolbox is launched by entering the command: toolbox in a terminal. A PlusCal user's manuals are available at ~herbrete/public/TLA/c-manual.pdf and ~herbrete/public/TLA/pluscal.pdf

Aside from the resources provided above, books, tutorials and tools can be downloaded from the TLA webpage.

## Introduction to the PlusCal language

PlusCal is an algorithmic language. It differs from programming languages since:

• PlusCal algorithms can manipulate arbitrary mathematical objects (graphs, etc). Programming languages require to implement these objects using low-level types (integers, booleans, etc).
• PlusCal algorithms can be non-deterministic. Programs need to be deterministic in order to be executable.
• PlusCal has a well-defined notion of an atomic step. In general, the instructions in a program are not atomic (mechanisms are usually provided to group instructions in atomic steps)
• PlusCal has a formal semantics defined as TLA+ expressions.

The TLA toolbox offers three main features:

• The translation of PlusCal programs into TLA+ expressions.
• The TLC model-checker that allows to find bugs in algorithms, and to prove algorithms with finite resources.
• The TLA prover which is not in the scope of this class.

Launch the TLA toolbox and create a new specification using menu File > Open Spec > Add New Spec... Enter filename euclid.tla (with full access path) and confirm the creation of the new specification. An empty module euclid has been created. Copy and paste Euclid's algorithm below inside the module.

EXTENDS Naturals, TLC

CONSTANT MAXINT  (* Maximal integer *)
(* PlusCal options (-termination) *)
(*
--algorithm EuclidAlg {
variables u \in 1..MAXINT;  (* 1st integer *)
v \in 1..MAXINT;  (* 2nd integer *)

{
print <<u, v>>;

while (u /= 0) {
if (u < v) {
u := v || v := u
};
u := u - v
}
}

}
*)
In this algorithm:
• EXTENDS is used to import libraries (here, the natural numbers library and the TLC library).
• CONSTANT introduces new symbolic names. Here MAXINT is a parameter of the algorithm. Its value is unspecified.
• The algorithm itself is placed inside a comment bloc (* ... *). Its specification starts with --algorithm followed by a name.
• Two variables u and v are declared. The declaration u \in 1..MAXINT defines the initial value of variable u. It is non-deterministically chosen in the set 1..MAXINT.
• print <<u, v>>; prints the value of the tuple <<u, v>>
• The statement u := v || v := u is a parallel assignement. It has the semantics of an assignement over vectors: (u v) := (v u).

Use menu File > Parse Module to check that your algorithm is syntactically correct. Notice that some errors may not be detected by this check. Then, add the following two lignes between the closing comment *) and the end of the module:

\* BEGIN TRANSLATION
\* END TRANSLATION

Convert the PlusCal algorithm into a TLA+ specification using menu File > Translate PlusCal Algorithm. A TLA+ expression equivalent to the PlusCal algorithm has been output in between the two lignes that have just been added. The errors that are not detected during module parsing are detected during the translation. When the PlusCal algorithm is syntactically correct, the status bar at the bottom of the window is green (otherwise, it is yellow or red, and error messages are displayed).

## Model-checking PlusCal algorithms

Add two new variables u_init and v_init which are initialized to the values of u and v respectively. Then, add the following statements after the while statement:  

print <<u_init, v_init, "have gcd", v>>;
assert v = gcd(u_init, v_init);

Define gcd(x,y) between the closing comment *) and \* BEGIN TRANSLATION by copying and pasting the following TLA+ specification:

gcd(x,y) == CHOOSE i \in 1..x:                    /\ x % i = 0                    /\ y % i = 0                    /\ \A j \in 1..x: /\ x % j = 0                                      /\ y % j = 0                                      => i >= j

1. Translate the definition of gcd(x,y) in natural language
2. The algorithm is one of the two inputs required for verification. What is the other input? How is it specified in this example?
3. Create a model using menu TLC Model Checker > New Model... or open an existing model using TLC Model Checker > Open Model... In panel Model Overview, choose a value for MAXINT by double-clicking on MAXINT <-.Then click on the green arrow to launch model-checking. What is the result of model-checking?
4. What can you conclude on your algorithm?
5. Determine, by successive experimentations, the maximal value of MAXINT for which model-checking can be achieved by TLC checker using reasonable time and space.

## An incorrect binary search algorithm

Consider the PlusCal algorithm below that performs a binary search of the value x in the array t. The algorithm is purposely incorrect. The goal is to understand the errors issued by the TLC model-checker and to fix the algorithm using the error traces given by TLC.

EXTENDS Naturals, TLC

CONSTANT N      (* Size of arrays *)
CONSTANT MAXINT (* Max integer value *)

(* PlusCal options (-termination) *)

(*
--algorithm Binsearch {
variables t \in [ 1..N -> 0..MAXINT ];  (* Array of N integers in 0..MAXINT *)
x \in 0..MAXINT;              (* Value to find *)
found = FALSE;
l = 1;                        (* All elements to the left of l are < x *)
r = N;                        (* All elements to the right of r are > x *)
p = 1;                        (* Pivot *)

(* Main *)
{
print <<t, x>>;

while ((l <= r) /\ (~ found)) {
p := (l + r) \div 2;

if (t[p] = x)
found := TRUE
else if (t[p] < x)
l := p-1
else (* t[p] > x *)
r := p+1
};

assert( found <=> (\E j \in 1..N : t[j] = x) )
}

}
*)

\* BEGIN TRANSLATION\* END TRANSLATION
1. What are the loop invariant and variant that must hold for the correctness and termination of the algorithm above?
2. Create a new module, copy and paste the algorithm above, then create a new model and check the Termination property and the assertion for small instances of the model (e.g. N<-2 and MAXINT<-2). Analyze the error trace provided by the TLA toolbox. Is it a finite or an infinite path? Is it a counter-example to the termination of the algorithm or to the assertion? Explain why the error trace violates the invariant and/or the variant of loop and fix the algorithm.
3. Check again the Termination property and the assertion. Analyse the new error trace: is it a finite path ot an infinite path? Is it a counter-example to the termination of the algorithm or to the assertion? Fix the algorithm and justify which part of the specification was violated.
4. Check that the algorithm now terminates and that it is now correct.