Skip to main content

Utilities for working with TLA+ state graphs

Project description

tlaplus-state-graph-utils.py

Python utilities for working with TLA+ state graphs

Installation

pip install tlaplus-state-graph-utils

Using the CLI

Installing the package puts a CLI program named tlaplus-state-graph-utils.py in your PATH. Here is its --help text:

usage: tlaplus-state-graph-utils.py [-h] [--version] COMMAND ...

utilities for working with TLA+ state graphs

options:
  -h, --help  show this help message and exit
  --version   show program's version number and exit

subcommands:
  COMMAND     description
    convert   convert between state graph formats

It currently has only one subcommand called convert which can be used to convert between different representations of TLA+ state graphs. Here is its --help text:

usage: tlaplus-state-graph-utils.py convert [-h] [--output OUTPUT]
                                    [--from {reasonable-json,tlaplus-dot-json}]
                                    [--to {reasonable-json,d2}] [--pretty]
                                    [--reasonable-json-structured-state]
                                    [--reasonable-json-simple-structured-state]
                                    [--reasonable-json-itf-state]
                                    [--d2-output-state-as D2_OUTPUT_STATE_AS]
                                    [input]

convert between TLA+ state graph formats/representations

positional arguments:
  input                 input file path or '-' to use stdin (the default)

options:
  -h, --help            show this help message and exit
  --output OUTPUT, -o OUTPUT
                        output file path or '-' to use stdout (the default)
  --from {reasonable-json,tlaplus-dot-json}, -f {reasonable-json,tlaplus-dot-json}
                        input format (guessed from extension & content if not
                        given)
  --to {reasonable-json,d2}, -t {reasonable-json,d2}
                        output format (if not given, defaults to reasonable-
                        json when outputting to stdout, otherwise guessed from
                        extension)
  --pretty              produce pretty-printed rather than compact output

reasonable-json options:
  options relevant when outputting in reasonable-json format

  --reasonable-json-structured-state
                        include state contents represented as structured JSON
  --reasonable-json-simple-structured-state
                        include state contents represented as simplified
                        structured JSON (lossy, i.e. doesn't encode all
                        details of TLA+, but easy to work with)
  --reasonable-json-itf-state
                        include state contents represented in ITF state format
                        (see: https://apalache-mc.org/docs/adr/015adr-
                        trace.html)

D2 options:
  options relevant when outputting in D2 format

  --d2-output-state-as D2_OUTPUT_STATE_AS
                        how to represent individual states in the D2 output:
                        label: without modification as a D2 node label; latex:
                        as a LaTeX equation which D2 will render; nested-
                        containers: as nested containers, one per variable,
                        record, etc.; nested-containers-simple-values-inline:
                        as above but with terminal/simple values not getting
                        their own container; nested-containers-simple-values-
                        inline-newline: as above but with keys and terminal
                        values separated by newlines

For instance, this converts a GraphViz dot file produced by TLA+'s state diagram output into a "reasonable" JSON format that's easier to work with:

# In your TLA+ Model directory:
dot -Tjson Model_1.dot | tlaplus-state-graph-utils.py convert -t reasonable-json

The following sections go into more details about the supported input and output formats.

Input formats

dot JSON

TLA+ does not currently have a "canonical" format for state graphs (see TLA+ GitHub issue #639) and so the only halfway convenient way to get this information out of TLA+ is to process the GraphViz dot files it produces.

In particular, as suggested in a comment on the aforementioned issue, dot itself can convert these into a JSON representation (dot -Tjson), which can then by read in by this utility (it automatically considers filenames ending in .dot.json to be such files).

Reasonable JSON

Another possible input format is the "reasonable JSON" format produced by this tool itself - it is explained in more detail in the Output formats section below.

Output formats

"Reasonable JSON"

The aforementioned "reasonable JSON" format is meant to make it easier for other tools to work with TLA+ state graphs. It looks like this:

{
  "metadata": {
    "format": {
      "name": "reasonable-tlaplus-state-graph-json",
      "version": "0.1.1"
    }
  },
  "states": [
    {
      "id": 1,
      "labelTlaPlus": "/\\ a = 1 /\\ b = 2 \n ...",
      // optional, if requested:
      "structuredState": ...,
      "simpleStructuredState": ...,
      "itfState": ...
      // optional, if added by user:
      "styleClass": "someclass"
    },
    ...
  ],
  "steps": [
    {
      "id": 0,
      "actionName": "CheckFileExists",
      "fromStateId": 1,
      "toStateId": 2,
      "colorId": "1"
    },
    ...
  ]
}
Structured state

If present, the optional fields structuredState, simpleStructuredState and itfState contain different JSON representations of each state's "content" (i.e. the set of variables and their values for that state). They can be switched on independently of one another via the --reasonable-json-structured-state, --reasonable-json-simple-structured-state, and --reasonable-json-simple-structured-state CLI flags.

The "structured" and "simple-structured" formats are ad-hoc formats defined by this tool (if you need docs for this please open an issue).

The ITF state format is the same as that used in traces output by the Apalache model checker and described in the "State object" section of its ADR-015.

Style class

The optional field styleClass represents a "class" of styling options to apply to the state in question and will be included in output formats that support such a "class" concept (e.g. D2 - see below).

D2

Another supported output format is D2, but to use it, the package's d2 extra needs to be installed:

pip install tlaplus-state-graph-utils[d2]'

Here is an example showing how to go from a dot file produced by TLA+ to a graph rendered using D2 in one shell command:

# In your TLA+ Model directory:
dot -Tjson Model_1.dot \
| tlaplus-state-graph-utils.py convert -t d2 \
| D2_LAYOUT=elk d2 - > Model_1.svg

There are many different ways to represent the contents of each state (i.e. the set of variables and their values) in D2, which can be configured via the --d2-output-state-as option:

label
latex
nested-containers
nested-containers-simple-values-inline
nested-containers-simple-values-inline-newline

Cookbook / advanced techniques

Conditional styling

While there is no built-in support for making styleClass dependent on the TLA+ state contents (yet?), it's possible to hack something together using structured/JSON state output and the jq JSON processing tool, e.g.:

tlaplus-state-graph-utils.py convert --reasonable-json-simple-structured-state \
| jq '.states[] |= (.styleClass =
if .someKey == "some-value" then
  "class1"
elif .someKey == "some-other-value" then
  "class2"
else
  .styleClass
end
)'

This overwrites the styleClass attribute of each state (adding it if it doesn't exist) depending on the value of the someKey variable in it.

It is recommended to use the simple-structured-state format for such kinds of processing because it's designed to be easy to work with in jq.

styleClass is included in e.g. the D2 output, making it possible to create graphs like this with this technique (see dev/render-test-examples.sh for the full script to generate this one):

Use as a library

I'm too lazy to write this or set up automated API docs, especially considering nobody is going to use it. If you want to use this as a library, please just open an issue saying so and I'll get started (and maybe clean things up a little).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tlaplus_state_graph_utils-0.2.0.tar.gz (34.9 kB view details)

Uploaded Source

Built Distribution

tlaplus_state_graph_utils-0.2.0-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

File details

Details for the file tlaplus_state_graph_utils-0.2.0.tar.gz.

File metadata

File hashes

Hashes for tlaplus_state_graph_utils-0.2.0.tar.gz
Algorithm Hash digest
SHA256 18c3260769861d30a273feadf7707973309f6cdc08f23eb273287d462ac44f02
MD5 b16a6704fd09d5780c43fdbc64e1115a
BLAKE2b-256 4aebf279fc482632c221f8869be4851dde3ee09ec4ebfc5fd1b820d18d467679

See more details on using hashes here.

File details

Details for the file tlaplus_state_graph_utils-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for tlaplus_state_graph_utils-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1b58250bd3fb3426dff1cc0731984eacc0ee74df7baf9e09382b42391efdfa3e
MD5 575b7ad3c32128e0c28de59bc4d59b8e
BLAKE2b-256 705a55013e9b3d3a9df6bf56d51f788bfa8f8bf753a33a2eb280a9c873028a3f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page