4 minutes
Using the TLA⁺ Command Line Interface
TLA⁺ is a formal language for modelling concurrent and distributed systems in the form of a mathematical specification. TLA⁺ is often used with a set of tools, such as the TLC model checker, distributed with the official TLA⁺ IDE: the TLA⁺ toolbox.
The toolbox is fine, but I personally prefer to edit my specifications using my favorite editor rather than a specialized IDE. Turns out running the TLA⁺ tools from the command line is quite simple yet not very well documented, that’s why I decided to write down my process for using TLA⁺ outside of the toolbox, hope it helps!
Downloading the tools
The tools are developed on Github and written in Java, each release consists in
a few assets such as OS specific versions of the toolbox but also contains a
standalone version of the tools in the form of the tla2tools.jar
file. To
download the tools simply grab the last tla2tools.jar
on the release
page. At the time of writing, the
latest stable release is 1.7.1 and it can be downloaded with:
wget https://github.com/tlaplus/tlaplus/releases/download/v1.7.1/tla2tools.jar
Next, you need a version of Java on your system, I’m using java 11 and it works
just fine. You can check your Java installation with java --version
. Then
running the tools is pretty simple:
java -cp tla2tools.jar tlc2.TLC
This should raise an error (Missing input TLA+ module
) but you should also get
the version of TLC (TLC2 Version 2.16
in my case) so it’s a good sign that the
installation is working.
Using convenient wrappers
For ease of use, I use small bash wrappers around the tools so that I can call
tlc
directly from command line. You can copy the following scripts and put
them somewhere in your $PATH
to do the same.
Don’t forget to replace </path/to/tla2tools.jar>
by the real path of
tla2tools.jar
!
Here are the tools:
TLC
Used to check models. See the TLC section for an example of usage.
#!/usr/bin/env bash
java -cp </path/to/tla2tools.jar> tlc2.TLC $@
TLAToTeX
Produces a .tex
file from a TLA⁺ specification that can in turn be used to
produce a PDF.
#!/usr/bin/env bash
java -cp </path/to/tla2tools.jar> tla2tex.TLA $@
TeXToTLA
Given a .tex
file containing some TLA⁺ in a tla
environment, produces a new
.tex
file with code for rendering the specification. Rendering the final
.tex
requires having
tlatex.sty
in scope.
#!/usr/bin/env bash
java -cp </path/to/tla2tools.jar> tla2tex.TeX $@
SANY
A TLA⁺ parser that can report syntax errors in a spec.
#!/usr/bin/env bash
java -cp </path/to/tla2tools.jar> tla2sany.SANY $@
The TLC model checker
Working with TLC from the command line requires to create a few additional files
that the toolbox usually generates automatically. Imagine you wan to specify a
two bits clock, dump the following spec in a Clock.tla
file (the name is
important, TLC will complain otherwise):
---------------------- MODULE Clock ----------------------
CONSTANT InitialValue
VARIABLE clock
Init == clock = InitialValue
Tick == IF clock = 0 THEN clock' = 1 ELSE clock' = 0
IsValid == clock \in {0, 1}
Spec == Init /\ [][Tick]_<<clock>>
==========================================================
So nothing too fancy here, we describe a clock that can take two values: 0
and 1. When doing model checking, we want to give a concrete value to the
InitialValue
constant, we also want to tell TLC to check some properties such
as IsValid
.
To do that we need another module, dump the following specification in a
ClockModel.tla
file:
------------------- MODULE ClockModel --------------------
EXTENDS Clock
InputInitialValue == 0
PropertyIsValid == []IsValid
==========================================================
This module extends the clock specification Clock
(file name are important for
this to work!) and defines two predicate. I like to prefix my predicate with
Input
or Property
depending on what they represent. Here we defined an
initial value and a temporal property.
Then we need to tell TLC what are the inputs, properties and specifications to
check, this is done using a last file ClockModel.cfg
(once again, the name is
important, it must be the same as the model filename with the .cfg
extension
instead of .tla
).
Copy the following in ClockModel.cfg
:
CONSTANT InitialValue <- InputInitialValue
PROPERTY PropertyIsValid
SPECIFICATION Spec
This file tells TLC that the InitialValue
constant must take the value
InputInitialValue
we defined in our model, that it has to check the
PropertyIsValid
temporal property and that specification is defined by the
Spec
predicate.
And that’s it, now we can check our model using TLC:
tlc ClockModel.tla
Which should return without error.
If your model is expected to reach some terminal state, pass the -deadlock
flag to TLC so that deadlocks are no longer considered as bugs.
Conclusion
I hope this was helpful, you can also find some documentation
here or with the -help
flag for most tools. Feel free to report issues or corrections
here and enjoy writing TLA⁺
specs outside of the toolbox!