doc: add org-mode documentation for user tools

* doc/org/.gitignore, doc/org/genltl.org, doc/org/ioltl.org,
doc/org/ltl2tgba.org, doc/org/ltl2tgta.org, doc/org/ltlcross.org,
doc/org/ltlfilt.org, doc/org/randltl.org, doc/org/tools.org: New files.
This commit is contained in:
Alexandre Duret-Lutz 2013-01-10 10:30:48 +01:00
parent 2f5d961d10
commit 345b8c5b14
9 changed files with 2299 additions and 0 deletions

7
doc/org/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
*.png
err
*.html
*.csv
*.json
scheck.ltl
sum.py

84
doc/org/genltl.org Normal file
View file

@ -0,0 +1,84 @@
#+TITLE: =genltl=
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
#+LINK_UP: file:tools.html
This tool generates LTL formulas according to scalable patterns.
These pattern are usually taken from the literature (see the man page
for references). Sometimes the same pattern is given different names
in different papers, so we alias different option names to the same
pattern.
#+BEGIN_SRC sh :results verbatim :exports results
genltl --help | sed -n '/Pattern selection:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
#+begin_example
--and-f=RANGE, --gh-e=RANGE
F(p1)&F(p2)&...&F(pn)
--and-fg=RANGE FG(p1)&FG(p2)&...&FG(pn)
--and-gf=RANGE, --ccj-phi=RANGE, --gh-c2=RANGE
GF(p1)&GF(p2)&...&GF(pn)
--ccj-alpha=RANGE F(p1&F(p2&F(p3&...F(pn)))) &
F(q1&F(q2&F(q3&...F(qn))))
--ccj-beta=RANGE F(p&X(p&X(p&...X(p)))) & F(q&X(q&X(q&...X(q))))
--ccj-beta-prime=RANGE F(p&(Xp)&(XXp)&...(X...X(p))) &
F(q&(Xq)&(XXq)&...(X...X(q)))
--gh-q=RANGE (F(p1)|G(p2))&(F(p2)|G(p3))&... &(F(pn)|G(p{n+1}))
--gh-r=RANGE (GF(p1)|FG(p2))&(GF(p2)|FG(p3))&...
&(GF(pn)|FG(p{n+1}))
--go-theta=RANGE !((GF(p1)&GF(p2)&...&GF(pn)) -> G(q->F(r)))
--or-fg=RANGE, --ccj-xi=RANGE
FG(p1)|FG(p2)|...|FG(pn)
--or-g=RANGE, --gh-s=RANGE G(p1)|G(p2)|...|G(pn)
--or-gf=RANGE, --gh-c1=RANGE
GF(p1)|GF(p2)|...|GF(pn)
--r-left=RANGE (((p1 R p2) R p3) ... R pn)
--r-right=RANGE (p1 R (p2 R (... R pn)))
--rv-counter=RANGE n-bit counter
--rv-counter-carry=RANGE n-bit counter w/ carry
--rv-counter-carry-linear=RANGE
n-bit counter w/ carry (linear size)
--rv-counter-linear=RANGE n-bit counter (linear size)
--u-left=RANGE, --gh-u=RANGE
(((p1 U p2) U p3) ... U pn)
--u-right=RANGE, --gh-u2=RANGE, --go-phi=RANGE
(p1 U (p2 U (... U pn)))
#+end_example
An example is probably all it takes to explain how this tool works:
#+BEGIN_SRC sh :results verbatim :exports both
genltl --and-gf=1..5 --u-left=1..5
#+END_SRC
#+RESULTS:
#+begin_example
GFp1
GFp1 & GFp2
GFp1 & GFp2 & GFp3
GFp1 & GFp2 & GFp3 & GFp4
GFp1 & GFp2 & GFp3 & GFp4 & GFp5
p1
p1 U p2
(p1 U p2) U p3
((p1 U p2) U p3) U p4
(((p1 U p2) U p3) U p4) U p5
#+end_example
=genltl= supports the [[file:ioltl.org][common option for output of LTL formulas]], so you
may output these pattern for various tools.
Note that for the =--lbt= output, each formula is relabeled using
=p0=, =p1=, ... before it is output, when the pattern (like
=--ccj-alpha=) use different names.
# Local variables:
# eval: (setenv "PATH" (concat "../../src/bin" path-separator (getenv "PATH")))
# eval: (org-babel-do-load-languages 'org-babel-load-languages '((sh . t) (dot . t)))
# eval: (setq org-confirm-babel-evaluate nil)
# End:
# LocalWords: genltl num toc LTL scalable SRC sed gh pn fg FG gf qn
# LocalWords: ccj Xp XXp Xq XXq rv GFp lbt

162
doc/org/ioltl.org Normal file
View file

@ -0,0 +1,162 @@
#+TITLE: Common input and output options for LTL/PSL formulas
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
#+LINK_UP: file:tools.html
Spot supports different syntaxes for LTL/PSL formulas. This pages
document the options, common to all tools where it makes sense, that
are used to specify input and output of formula.
* Common input options
All tools that read LTL/PSL formulas implement the following options:
#+BEGIN_SRC sh :results verbatim :exports results
ltl2tgba --help | sed -n '/Input options:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
: -f, --formula=STRING process the formula STRING
: -F, --file=FILENAME process each line of FILENAME as a formula
: --lbt-input read all formulas using LBT's prefix syntax
: --lenient parenthesized blocks that cannot be parsed as
: subformulas are considered as atomic properties
=-f= is used to pass one formula one the command line, but this option can
be repeated to pass multiple formulas.
=-F= is used to read formulas from a file (one formula per line).
This option can also be repeated to pass multiple files. If the
filename specified is =-= (as in =-F-=), then formulas are read from
standard input.
** Default parser
Spot's default LTL parser is able to parse the syntaxes of many tools,
such as [[http://spinroot.com][Spin]], [[http://vlsi.colorado.edu/~rbloem/wring.html][Wring]], [[http://goal.im.ntu.edu.tw][Goal]], etc. For instance here are the preferred ways
to express the same formula for different tools.
# <<tab:formula-syntaxes>>
| Tool | Formula |
|--------------+-------------------------|
| Spot | =G(a -> (b R !c))= |
| Spot (UTF-8) | =□(a → (b R c̅))= |
| Spin | =[](a -> (b V !c))= |
| Wring | =G(a=1 -> (b=1 R c=0))= |
| Goal | =G(a --> (b R ~c))= |
Spot's default LTL parser will understand all of them.
For a complete definition of the supported operators, including PSL
operators, please refer to the =doc/tl/tl.pdf= document inside the
Spot distribution.
For Spot, an atomic proposition is any alphanumeric string that does
not start with the (upper case) characters =F=, =G=, or =X=. For
instance =gfa= is an atomic proposition, but =GFa= actually denotes
the LTL formula =G(F(a))=. Any double-quoted string is also
considered to be an atomic proposition, so if =GFa= had to be an
atomic proposition, it could be written
#+HTML: <code>"GFa"</code>
.
These double-quote string also make it possible to embed arbitrarily
complex expressions that represent an atomic proposition that Spot
should not try to interpret. For instance:
: "a < b" U "process[2]@ok"
** Lenient mode
In version 6, Spin extended its syntax to support arbitrary atomic expression
in LTL formulas. The previous formula would be written simply:
: (a < b) U (process[2]@ok)
While Spot cannot read the above syntax by default, it can do it if
you specify the =--lenient= option. (This global option affects all
formulas that are input.)
The same parser is used, however its processing of parenthesis blocks
is different: every time a parenthesis block is scanned, the parser
first tries to recursively parse the block as an LTL/PSL formula, and
if this parsing failed, the block is considered to be an atomic
proposition.
For instance =(a U b) U c= will be successfully converted into an LTL
formula with two operators, while parsing =(a + b < 2) U c= will
consider =a + b < 2= as an atomic proposition.
An unfortunate side-effect of =--lenient= parsing is that many syntax
errors will not be caught. Compare the following syntax error:
#+BEGIN_SRC sh :results verbatim :exports code
ltlfilt -f '(a U b U) U c'
#+END_SRC
#+RESULTS:
#+BEGIN_SRC sh :results verbatim :exports results
(ltlfilt -f '(a U b U) U c' 2>&1 | cat) | sed '/^$/d'
#+END_SRC
#+RESULTS:
: >>> (a U b U) U c
: ^
: syntax error, unexpected closing parenthesis
: >>> (a U b U) U c
: ^
: missing right operand for "until operator"
With the same command in =--lenient= mode:
#+BEGIN_SRC sh :results verbatim :exports both
ltlfilt --lenient -f '(a U b U) U c'
#+END_SRC
#+RESULTS:
: "a U b U" U c
Here =a U b U= was taken as an atomic proposition.
** Prefix parser
The prefix syntax used by tools such as [[http://www.tcs.hut.fi/Software/maria/tools/lbt/][LBT]], [[http://www.tcs.hut.fi/Software/lbtt/][LBTT]], or [[http://tcs.legacy.ics.tkk.fi/users/tlatvala/scheck/][scheck]], require
a different parser. For these tools, the above example formula has to
be written =G i p0 V p1 ! p2= (atomic propositions must start with =p=
and be followed by a number). Spot's =--lbt-input= option can be used
to activate the parser for this syntax.
As an extension to LBT's syntax, atomic propositions may also be
double-quoted. In that case they do not have to follow the "=p= +
number" rule.
=--lbt-input= is a global option that affects *all* formulas that are read.
* Common output options
All tools that output LTL/PSL formulas implement the following options:
#+BEGIN_SRC sh :results verbatim :exports results
ltlfilt --help | sed -n '/Output options:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
: -8, --utf8 output using UTF-8 characters
: -l, --lbt output in LBT's syntax
: -p, --full-parentheses output fully-parenthesized formulas
: -s, --spin output in Spin's syntax
: --spot output in Spot's syntax (default)
: --wring output in Wring's syntax
# LocalWords: syntaxes LTL PSL num toc SRC ltl tgba sed FILENAME
The =--spot=, =--utf-8=, =--spin=, =--wring= select different
output syntax as seen in [[tab:formula-syntaxes][the above table]]. The =-p= option can
be used to request that parenthesis be used at all levels.
Note that by default Spot always output parentheses around operators
such as =U=, because not all tools agree on their associativity. For
instance =a U b U c= is read by Spot as =a U (b U c)= (because =U= is
right-associative in the PSL standard), while Spin (among other tools)
with read it as =(a U b) U c=.
The =--lbt= option request an output in LBT's prefix format, and in
that case discussing associativity and parentheses makes no sense.
# LocalWords: lbt LBT's filename UTF gfa GFa ltlfilt LBTT scheck
# LocalWords: utf associativity

716
doc/org/ltl2tgba.org Normal file
View file

@ -0,0 +1,716 @@
#+TITLE: =ltl2tgba=
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
#+LINK_UP: file:tools.html
This tool translates LTL or PSL formulas into two kinds of Büchi
automata. The default is to output Transition-based Generalized Büchi
Automata (hereinafter abbreviated TGBA), but more traditional Büchi
automata (BA) may be requested using the =-B= option.
* TGBA and BA
Formulas to translate may be specified using [[file:ioltl.org][common input options for
LTL/PSL formulas]].
#+BEGIN_SRC sh :results verbatim :exports both
ltl2tgba -f 'Fa & GFb'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1"]
1 -> 1 [label="!a\n"]
1 -> 2 [label="a\n"]
2 [label="2"]
2 -> 2 [label="b\n{Acc[b]}"]
2 -> 2 [label="!b\n"]
}
#+end_example
Actually, because =ltl2tgba= is often used with a single formula
passed on the command line, the =-f= option can be omitted and any
command-line parameter that is not the argument of some option will be
assumed to be a formula to translate (this differs from [[file:ltlfilt.org][=ltlfilt=]],
where such parameters are assumed to be filenames).
The default output format, as shown above, is [[http://http://www.graphviz.org/][GraphViz]]'s format. This
can converted into a picture, or into vectorial format using =dot= or
=dotty=. Typically, you could get a =pdf= of this TGBA using
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba "Fa & GFb" | dot -Tpdf > tgba.pdf
#+END_SRC
#+RESULTS:
The result would look like this:
#+NAME: dotex
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba "Fa & GFb" | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: dotex
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1"]
1 -> 2 [label="a\\n"]
1 -> 1 [label="!a\\n"]
2 [label="2"]
2 -> 2 [label="b\\n{Acc[b]}"]
2 -> 2 [label="!b\\n"]
}
#+end_example
#+BEGIN_SRC dot :file dotex.png :cmdline -Tpng :var txt=dotex :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:dotex.png]]
The string between braces, =Acc[b]=, represents an acceptance set (its
actual name is not really important): any transition labeled by
=Acc[b]= belongs to the =Acc[b]= acceptance set. You may have many
transitions in the same acceptance set, and a transition may also
belong to multiple acceptance sets. An infinite path through this
automaton is accepting iff it visit each acceptance set infinitely
often. Therefore, in the above example, any accepted path will
/necessarily/ leave the initial state after a finite amount of steps,
and then it will verify the property =b= infinitely often. It is also
possible that an automaton do not use any acceptance set at all, in
which any run is accepting.
Here is a TGBA with multiple acceptance sets (we omit the call to
=dot= to render the output of =ltl2tgba= from now on):
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba 'GFa & GFb'
#+END_SRC
#+RESULTS:
: digraph G {
: 0 [label="", style=invis, height=0]
: 0 -> 1
: 1 [label="1"]
: 1 -> 1 [label="a & b\n{Acc[b], Acc[a]}"]
: 1 -> 1 [label="b & !a\n{Acc[b]}"]
: 1 -> 1 [label="a & !b\n{Acc[a]}"]
: 1 -> 1 [label="!b & !a\n"]
: }
#+NAME: dotex2
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba "GFa & GFb" | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: dotex2
: digraph G {
: 0 [label="", style=invis, height=0]
: 0 -> 1
: 1 [label="1"]
: 1 -> 1 [label="a & b\\n{Acc[b], Acc[a]}"]
: 1 -> 1 [label="b & !a\\n{Acc[b]}"]
: 1 -> 1 [label="a & !b\\n{Acc[a]}"]
: 1 -> 1 [label="!b & !a\\n"]
: }
#+BEGIN_SRC dot :file dotex2.png :cmdline -Tpng :var txt=dotex2 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:dotex2.png]]
The above TGBA has two acceptance sets: =Acc[a]= and =Acc[b]=.
The position of these acceptance sets ensures that =a= and =b= atomic
proposition must be true infinitely often.
A Büchi automaton for the previous formula can be obtained with the
=-B= option:
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba -B 'GFa & GFb'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0", peripheries=2]
1 -> 1 [label="a & b\n{Acc[1]}"]
1 -> 2 [label="b & !a\n{Acc[1]}"]
1 -> 3 [label="!b\n{Acc[1]}"]
2 [label="1"]
2 -> 1 [label="a\n"]
2 -> 2 [label="!a\n"]
3 [label="2"]
3 -> 1 [label="a & b\n"]
3 -> 2 [label="b & !a\n"]
3 -> 3 [label="!b\n"]
}
#+end_example
#+NAME: dotex2ba
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba -B 'GFa & GFb' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: dotex2ba
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0", peripheries=2]
1 -> 1 [label="a & b\\n{Acc[1]}"]
1 -> 2 [label="b & !a\\n{Acc[1]}"]
1 -> 3 [label="!b\\n{Acc[1]}"]
2 [label="1"]
2 -> 1 [label="a\\n"]
2 -> 2 [label="!a\\n"]
3 [label="2"]
3 -> 1 [label="a & b\\n"]
3 -> 2 [label="b & !a\\n"]
3 -> 3 [label="!b\\n"]
}
#+end_example
#+BEGIN_SRC dot :file dotex2ba.png :cmdline -Tpng :var txt=dotex2ba :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:dotex2ba.png]]
Although accepting states in the Büchi automaton are pictured with
double-lines, internally this automaton is still handled as a TGBA
with a single acceptance set =Acc[1]= such that the transitions
leaving the state are either all accepting, or all non-accepting.
This is the reason why the =Acc[1]= sets are still shown in the
output: it shows that a Büchi automaton is (a special case of) a TGBA.
Various options controls the output format of =ltl2tgba=:
#+BEGIN_SRC sh :results verbatim :exports results
ltl2tgba --help | sed -n '/Output format:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
: -8, --utf8 enable UTF-8 characters in output (ignored with
: --lbtt or --spin)
: --dot GraphViz's format (default)
: --lbtt LBTT's format
: -s, --spin Spin neverclaim (implies --ba)
: --spot SPOT's format
: --stats=FORMAT output statistics about the automaton
The =-8= option can be used to improve the readability of the output
if your system can display UTF-8 correctly.
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba -B8 'GFa & GFb'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0", peripheries=2]
1 -> 1 [label="a∧b\n{Acc[1]}"]
1 -> 2 [label="b∧a̅\n{Acc[1]}"]
1 -> 3 [label="b̅\n{Acc[1]}"]
2 [label="1"]
2 -> 1 [label="a\n"]
2 -> 2 [label="a̅\n"]
3 [label="2"]
3 -> 1 [label="a∧b\n"]
3 -> 2 [label="b∧a̅\n"]
3 -> 3 [label="b̅\n"]
}
#+end_example
#+NAME: dotex2ba8
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba -B8 "GFa & GFb" | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: dotex2ba8
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0", peripheries=2]
1 -> 1 [label="a∧b\\n{Acc[1]}"]
1 -> 2 [label="b∧a̅\\n{Acc[1]}"]
1 -> 3 [label="b̅\\n{Acc[1]}"]
2 [label="1"]
2 -> 1 [label="a\\n"]
2 -> 2 [label="a̅\\n"]
3 [label="2"]
3 -> 1 [label="a∧b\\n"]
3 -> 2 [label="b∧a̅\\n"]
3 -> 3 [label="b̅\\n"]
}
#+end_example
#+BEGIN_SRC dot :file dotex2ba8.png :cmdline -Tpng :var txt=dotex2ba8 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:dotex2ba8.png]]
* Spin output
Using the =--spin= or =-s= option, =ltl2tgba= will produce a Büchi automaton
(the =-B= option is implied) as a never claim that can be fed to Spin.
=ltl2tgba -s= is therefore a drop-in replacement for =spin -f=.
#+BEGIN_SRC sh :results verbatim :exports both
ltl2tgba -s 'GFa & GFb'
#+END_SRC
#+RESULTS:
#+begin_example
never { /* G(Fa & Fb) */
accept_init:
if
:: ((a) && (b)) -> goto accept_init
:: ((b) && (!((a)))) -> goto T0_S2
:: ((!((b)))) -> goto T0_S3
fi;
T0_S2:
if
:: ((a)) -> goto accept_init
:: ((!((a)))) -> goto T0_S2
fi;
T0_S3:
if
:: ((a) && (b)) -> goto accept_init
:: ((b) && (!((a)))) -> goto T0_S2
:: ((!((b)))) -> goto T0_S3
fi;
}
#+end_example
Since Spin 6 extended its syntax to support arbitrary atomic
propositions, you may also need put the parser in =--lenient= mode to
support these:
#+BEGIN_SRC sh :results verbatim :exports both
ltl2tgba -s --lenient '(a < b) U (process[2]@ok)'
#+END_SRC
#+RESULTS:
: never { /* "a < b" U "process[2]@ok" */
: T0_init:
: if
: :: ((process[2]@ok)) -> goto accept_all
: :: ((a < b) && (!(process[2]@ok))) -> goto T0_init
: fi;
: accept_all:
: skip
: }
* Do you favor deterministic or small automata?
The translation procedure can be controled by a few switches. A first
set of options specifies the intent of the translation: whenever
possible, would you prefer a small automaton or a deterministic
automaton?
#+BEGIN_SRC sh :results verbatim :exports results
ltl2tgba --help | sed -n '/Translation intent:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
: -a, --any no preference
: -D, --deterministic prefer deterministic automata
: --small prefer small automata (default)
The =--any= option tells the translator that it should not target any
particular form of result: any automaton denoting the given formula is
OK. This effectively disables post-processings and speeds up the
translation.
With the =-D= option, the translator will /attempt/ to produce a
deterministic automaton, even if this requires a lot of states. =ltl2tgba=
knows how to produce the minimal deterministic Büchi automaton for
any obligation property (this includes safety properties).
With the =--small= option (the default), the translator will not
produce a deterministic automaton when it knows how to build smaller
automaton.
An example formula where the difference between =-D= and =--small= is
flagrant is =Ga|Gb|Gc=:
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba 'Ga|Gb|Gc'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1"]
1 -> 2 [label="b\n"]
1 -> 3 [label="c\n"]
1 -> 4 [label="a\n"]
2 [label="2"]
2 -> 2 [label="b\n"]
3 [label="3"]
3 -> 3 [label="c\n"]
4 [label="4"]
4 -> 4 [label="a\n"]
}
#+end_example
#+NAME: gagbgc1
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba "Ga|Gb|Gc" | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: gagbgc1
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1"]
1 -> 2 [label="c\\n"]
1 -> 3 [label="b\\n"]
1 -> 4 [label="a\\n"]
2 [label="2"]
2 -> 2 [label="c\\n"]
3 [label="3"]
3 -> 3 [label="b\\n"]
4 [label="4"]
4 -> 4 [label="a\\n"]
}
#+end_example
#+BEGIN_SRC dot :file gagbgc1.png :cmdline -Tpng :var txt=gagbgc1 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:gagbgc1.png]]
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba -D 'Ga|Gb|Gc'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="6"]
1 -> 1 [label="a & b & c\n{Acc[1]}"]
1 -> 2 [label="b & c & !a\n{Acc[1]}"]
1 -> 3 [label="a & c & !b\n{Acc[1]}"]
1 -> 4 [label="c & !a & !b\n{Acc[1]}"]
1 -> 5 [label="a & b & !c\n{Acc[1]}"]
1 -> 6 [label="b & !a & !c\n{Acc[1]}"]
1 -> 7 [label="a & !b & !c\n{Acc[1]}"]
2 [label="2"]
2 -> 2 [label="b & c\n{Acc[1]}"]
2 -> 4 [label="c & !b\n{Acc[1]}"]
2 -> 6 [label="b & !c\n{Acc[1]}"]
3 [label="4"]
3 -> 3 [label="a & c\n{Acc[1]}"]
3 -> 4 [label="c & !a\n{Acc[1]}"]
3 -> 7 [label="a & !c\n{Acc[1]}"]
4 [label="1"]
4 -> 4 [label="c\n{Acc[1]}"]
5 [label="5"]
5 -> 5 [label="a & b\n{Acc[1]}"]
5 -> 6 [label="b & !a\n{Acc[1]}"]
5 -> 7 [label="a & !b\n{Acc[1]}"]
6 [label="3"]
6 -> 6 [label="b\n{Acc[1]}"]
7 [label="0"]
7 -> 7 [label="a\n{Acc[1]}"]
}
#+end_example
#+NAME: gagbgc2
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba -D 'Ga|Gb|Gc' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: gagbgc2
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="6"]
1 -> 1 [label="a & b & c\\n{Acc[1]}"]
1 -> 2 [label="b & c & !a\\n{Acc[1]}"]
1 -> 3 [label="a & c & !b\\n{Acc[1]}"]
1 -> 4 [label="c & !a & !b\\n{Acc[1]}"]
1 -> 5 [label="a & b & !c\\n{Acc[1]}"]
1 -> 6 [label="b & !a & !c\\n{Acc[1]}"]
1 -> 7 [label="a & !b & !c\\n{Acc[1]}"]
2 [label="1"]
2 -> 2 [label="b & c\\n{Acc[1]}"]
2 -> 4 [label="c & !b\\n{Acc[1]}"]
2 -> 6 [label="b & !c\\n{Acc[1]}"]
3 [label="2"]
3 -> 3 [label="a & c\\n{Acc[1]}"]
3 -> 4 [label="c & !a\\n{Acc[1]}"]
3 -> 7 [label="a & !c\\n{Acc[1]}"]
4 [label="0"]
4 -> 4 [label="c\\n{Acc[1]}"]
5 [label="4"]
5 -> 5 [label="a & b\\n{Acc[1]}"]
5 -> 6 [label="b & !a\\n{Acc[1]}"]
5 -> 7 [label="a & !b\\n{Acc[1]}"]
6 [label="3"]
6 -> 6 [label="b\\n{Acc[1]}"]
7 [label="5"]
7 -> 7 [label="a\\n{Acc[1]}"]
}
#+end_example
#+BEGIN_SRC dot :file gagbgc2.png :cmdline -Tpng :var txt=gagbgc2 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:gagbgc2.png]]
You can augment the number of terms in the disjunction to magnify the
difference. For N terms, the =--small= automaton has N+1 states,
while the =--deterministic= automaton needs 2^N-1 states.
A last parameter that can be used to tune the translation is the amount
of pre- and post-processing performed. These two steps can be adjusted
via a common set of switches:
#+BEGIN_SRC sh :results verbatim :exports results
ltl2tgba --help | sed -n '/Optimization level:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
: --high all available optimizations (slow, default)
: --low minimal optimizations (fast)
: --medium moderate optimizations
Pre-processings are rewritings done on the LTL formulas, usually to
reduce its size, but mainly to put it in a form that will help the
translator (for instance =F(a|b)= is easier to translate than
=F(a)|F(b)=). At =--low= level, only simple syntactic rewritings are
performed. At =--medium= level, additional simplifications based on
syntactic implications are performed. At =--high= level, language
containment is used instead of syntactic implications.
Post-processings are cleanups and simplifications of the automaton
produced by the core translator. The algorithms used during post-processing
are
- SCC filtering: removing useless strongly connected components,
and useless acceptance sets.
- direct simulation: merge states based on suffix inclusion.
- iterated simulations: merge states based on suffix inclusion,
or prefix inclusion, in a loop.
- WDBA minimization: determinize and minimize automata representing
obligation properties.
- degeneralization: convert a TGBA into a BA
The chaining of these various algorithms depends on the selected
combination of optimization level (=--low=, =--medium=, =--high=),
translation intent (=--small=, =--deterministic=) and type of
automaton desired (=--tgba=, =--ba=).
A notable configuration is =--any --low=, which will produce a TGBA as
fast as possible. In this case, post-processing is disabled, and only
syntactic rewritings are performed. This can be used for
satisfiability checking, although in this context even building an
automaton is overkill (you only need an accepted run).
Finally, it should be noted that the default optimization options
(=--small --high=) are usually overkill. =--low= will produce good
automata most of the time. Most of pattern formulas of [[file:genltl.org][=genltl=]] will
be efficiently translated in this configuration (meaning that =--small
--high= will not produce a better automaton). If you are planning to
generate automata for large family of pattern formulas, it makes sense
to experiment with the different settings on a small version of the
pattern, and select the lowest setting that satisfies your
expectations.
* Translating multiple formulas for statistics
If multiple formulas are given to =ltl2tgba=, the corresponding
automata will be output one after the other. This is not very
convenient, since most of these output formats are not designed to
represent multiple automata, and tools like =dot= will only display
the first one.
One situation where passing many formulas to =ltl2tgba= is useful is
in combination with the =--stats=FORMAT= option. This option will
output statistics about the translated automata instead of the
automata themselves. The =FORMAT= string should indicate which
statistics should be output, and how they should be output using the
following sequence of characters (other characters are output as-is):
#+BEGIN_SRC sh :results verbatim :exports results
ltl2tgba --help | sed -n '/^ *%/p'
#+END_SRC
#+RESULTS:
: %% a single %
: %a number of acceptance sets
: %d 1 if the automaton is deterministic, 0 otherwise
: %e number of edges
: %f the formula, in Spot's syntax
: %n number of nondeterministic states
: %s number of states
: %S number of SCCs
: %t number of transitions
For instance we can study the size of the automata generated for the
right-nested =U= formulas as follows:
#+BEGIN_SRC sh :results verbatim :exports both
genltl --u-right=1..8 | ltl2tgba -F - --stats '%s states and %e edges for "%f"'
#+END_SRC
#+RESULTS:
: 2 states and 2 edges for "p1"
: 2 states and 3 edges for "p1 U p2"
: 3 states and 6 edges for "p1 U (p2 U p3)"
: 4 states and 10 edges for "p1 U (p2 U (p3 U p4))"
: 5 states and 15 edges for "p1 U (p2 U (p3 U (p4 U p5)))"
: 6 states and 21 edges for "p1 U (p2 U (p3 U (p4 U (p5 U p6))))"
: 7 states and 28 edges for "p1 U (p2 U (p3 U (p4 U (p5 U (p6 U p7)))))"
: 8 states and 36 edges for "p1 U (p2 U (p3 U (p4 U (p5 U (p6 U (p7 U p8))))))"
Here =-F -= means that formulas should be read from the standard input.
When computing the size of an automaton, we distinguish /transitions/
and /edges/. An edge between two states is labeled by a Boolean
formula and may in fact represent several transitions labeled by
compatible Boolean assignment.
For instance if the atomic propositions are =x= and =y=, an edge labeled
by the formula =!x= actually represents two transitions labeled respectively
with =!x&y= and =!x&!y=.
Two automata with the same structures (states and edges) but differing
labels, may have a different count of transitions, e.g., if one has
more restricted labels.
* Building Monitors
In addition to TGBA and BA, =ltl2tgba= can output /monitor/ using the
=-M= option. These are finite automata that accept all prefixes of a
formula. The idea is that you can use these automata to monitor a
system as it is running, and report a violation as soon as no
compatible outgoing transition exist.
=ltl2tgba -M= may output non-deterministic monitors while =ltl2tgba
-MD= (short for =--monitor --deterministic=) will output the minimal
deterministic monitor for the given formula.
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba -M '(Xa & Fb) | Gc'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1", peripheries=2]
1 -> 2 [label="1\n"]
1 -> 3 [label="c\n"]
2 [label="2", peripheries=2]
2 -> 4 [label="a\n"]
3 [label="3", peripheries=2]
3 -> 3 [label="c\n"]
4 [label="4", peripheries=2]
4 -> 4 [label="1\n"]
}
#+end_example
#+NAME: monitor1
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba -M '(Xa & Fb) | Gc' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: monitor1
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1", peripheries=2]
1 -> 2 [label="1\\n"]
1 -> 3 [label="c\\n"]
2 [label="2", peripheries=2]
2 -> 4 [label="a\\n"]
3 [label="3", peripheries=2]
3 -> 3 [label="c\\n"]
4 [label="4", peripheries=2]
4 -> 4 [label="1\\n"]
}
#+end_example
#+BEGIN_SRC dot :file monitor1.png :cmdline -Tpng :var txt=monitor1 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:monitor1.png]]
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgba -M '(Xa & Fb) | Gc'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1", peripheries=2]
1 -> 2 [label="1\n"]
1 -> 3 [label="c\n"]
2 [label="2", peripheries=2]
2 -> 4 [label="a\n"]
3 [label="3", peripheries=2]
3 -> 3 [label="c\n"]
4 [label="4", peripheries=2]
4 -> 4 [label="1\n"]
}
#+end_example
#+NAME: monitor2
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgba -MD '(Xa & Fb) | Gc' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: monitor2
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="1", peripheries=2]
1 -> 2 [label="c\\n"]
1 -> 3 [label="!c\\n"]
2 [label="4", peripheries=2]
2 -> 4 [label="a\\n"]
2 -> 5 [label="c & !a\\n"]
3 [label="3", peripheries=2]
3 -> 4 [label="a\\n"]
4 [label="2", peripheries=2]
4 -> 4 [label="1\\n"]
5 [label="0", peripheries=2]
5 -> 5 [label="c\\n"]
}
#+end_example
#+BEGIN_SRC dot :file monitor2.png :cmdline -Tpng :var txt=monitor2 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:monitor2.png]]
Because they accept all finite executions that could be extended to
match the formula, monitor cannot be used to check for eventualities
such as =F(a)=. Any finite execution can be extended to match =F(a)=.
# Local variables:
# eval: (setenv "PATH" (concat "../../src/bin" path-separator (getenv "PATH")))
# eval: (org-babel-do-load-languages 'org-babel-load-languages '((sh . t) (dot . t)))
# eval: (setq org-confirm-babel-evaluate nil)
# End:
# LocalWords: ltl tgba num toc PSL Büchi automata SRC GFb invis Acc
# LocalWords: ltlfilt filenames GraphViz vectorial pdf Tpdf dotex
# LocalWords: sed png cmdline Tpng txt iff GFa ba utf UTF lbtt Fb
# LocalWords: GraphViz's LBTT's neverclaim SPOT's init goto fi Gb
# LocalWords: controled Gc gagbgc disjunction pre rewritings SCC Xa
# LocalWords: WDBA determinize degeneralization satisfiability SCCs
# LocalWords: genltl nondeterministic eval setenv concat getenv
# LocalWords: setq

342
doc/org/ltl2tgta.org Normal file
View file

@ -0,0 +1,342 @@
#+TITLE: =ltl2tgta=
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
#+LINK_UP: file:tools.html
This tool generates various form of Testing Automata, i.e., automata
that observe the /changes/ of atomic propositions, not their values.
Three types of automata can be output. The only output format
supported currently is [[http://http://www.graphviz.org/][GraphViz]]'s format, with option =-8= to enable
UTF-8 characters as in other tools.
The =--ta= option will translate a formula into Testing Automaton, as
described by [[http://spinroot.com/spin/Workshops/ws06/039.pdf][Geldenhuys and Hansen (Spin'06)]].
Here is the output on =a U Gb= (we omit the call to =dot=, as shown while
discussing [[file:ltl2tgba.org][=ltl2tgba=]]).
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgta --ta --multiple-init 'a U Gb'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
-1 [label="", style=invis, height=0]
-1 -> 1 [label="a & b"]
-2 [label="", style=invis, height=0]
-2 -> 2 [label="a & !b"]
-3 [label="", style=invis, height=0]
-3 -> 3 [label="b & !a"]
1 [label="0\na & b",shape=box]
1 -> 3 [label="{a}\n"]
1 -> 2 [label="{b}\n"]
1 -> 4 [label="{a}\n"]
2 [label="1\na & !b"]
2 -> 1 [label="{b}\n"]
2 -> 3 [label="{a, b}\n"]
3 [label="2\nb & !a",shape=box]
3 -> 4 [label="{a}\n"]
4 [label="3",peripheries=2,shape=box]
4 -> 4 [label="{a}\n{Acc[1]}"]
}
#+end_example
#+NAME: augb-ta
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgta --ta --multiple-init 'a U Gb' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: augb-ta
#+begin_example
digraph G {
-1 [label="", style=invis, height=0]
-1 -> 1 [label="a & !b"]
-2 [label="", style=invis, height=0]
-2 -> 2 [label="b & !a"]
-3 [label="", style=invis, height=0]
-3 -> 3 [label="a & b"]
1 [label="2\\na & !b"]
1 -> 3 [label="{b}\\n"]
1 -> 2 [label="{a, b}\\n"]
2 [label="0\\nb & !a",shape=box]
2 -> 4 [label="{a}\\n"]
3 [label="1\\na & b",shape=box]
3 -> 2 [label="{a}\\n"]
3 -> 1 [label="{b}\\n"]
3 -> 4 [label="{a}\\n"]
4 [label="3",peripheries=2,shape=box]
4 -> 4 [label="{a}\\n{Acc[1]}"]
}
#+end_example
#+BEGIN_SRC dot :file augb-ta.png :cmdline -Tpng :var txt=augb-ta :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:augb-ta.png]]
As always, the labels of the states have no influence on the language
recognized by the automaton. This automaton has three possible
initial states. The initial state should be chosen depending on the
initial valuation of =a= and =b= in the system to be synchronized with
this testing automaton. For instance if =a= is true and =b= false in
the initial state, the testing automaton should start in the state
pointed to by the initial arrow labeled =a & !b=. In the rest of the
testing automaton, the transitions are labeled by the sets of atomic
propositions that should change in the system for the testing
automaton to progress. States with a double enclosure are Büchi
accepting, meaning that any execution that visits one of these states
is accepting. All states have an implicit self-loop labeled by ={}=:
if the system progress without changing the value of =a= and =b=, the
testing automaton remains in the same state. Rectangle states are
livelock-accepting: any execution of the system that get stuck into
one of these state is accepting.
Without the =--multiple-init= option, a fake initial state is added.
This is the default since it often makes the result more readable.
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgta --ta 'a U Gb'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label=init]
1 -> 2 [label="b & !a\n"]
1 -> 3 [label="a & b\n"]
1 -> 4 [label="a & !b\n"]
2 [label="2",shape=box]
2 -> 5 [label="{a}\n"]
3 [label="3",shape=box]
3 -> 5 [label="{a}\n"]
3 -> 2 [label="{a}\n"]
3 -> 4 [label="{b}\n"]
4 [label="1"]
4 -> 3 [label="{b}\n"]
4 -> 2 [label="{a, b}\n"]
5 [label="4",peripheries=2,shape=box]
5 -> 5 [label="{a}\n{Acc[1]}"]
}
#+end_example
#+NAME: augb-ta2
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgta --ta 'a U Gb' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: augb-ta2
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label=init]
1 -> 2 [label="b & !a\\n"]
1 -> 3 [label="a & b\\n"]
1 -> 4 [label="a & !b\\n"]
2 [label="2",shape=box]
2 -> 5 [label="{a}\\n"]
3 [label="3",shape=box]
3 -> 2 [label="{a}\\n"]
3 -> 4 [label="{b}\\n"]
3 -> 5 [label="{a}\\n"]
4 [label="1"]
4 -> 3 [label="{b}\\n"]
4 -> 2 [label="{a, b}\\n"]
5 [label="4",peripheries=2,shape=box]
5 -> 5 [label="{a}\\n{Acc[1]}"]
}
#+end_example
#+BEGIN_SRC dot :file augb-ta2.png :cmdline -Tpng :var txt=augb-ta2 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:augb-ta2.png]]
The =--gba= option can be used to request a Generalized Testing
Automaton, i.e., a Testing Automaton with Generalized Büchi
acceptance. In that case double-enclosures are not used anymore, and
Büchi accepting transitions are marked with the same ={Acc[x],Acc[y]}=
notation used in TGBA.
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgta --gta 'GFa & GFb'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label=init]
1 -> 2 [label="a & b\n"]
1 -> 3 [label="b & !a\n"]
1 -> 4 [label="a & !b\n"]
1 -> 5 [label="!b & !a\n"]
2 [label="1",shape=box]
2 -> 3 [label="{a}\n{Acc[b], Acc[a]}"]
2 -> 4 [label="{b}\n{Acc[b], Acc[a]}"]
2 -> 5 [label="{a, b}\n{Acc[b], Acc[a]}"]
3 [label="4"]
3 -> 2 [label="{a}\n{Acc[b]}"]
3 -> 4 [label="{a, b}\n{Acc[b]}"]
3 -> 5 [label="{b}\n{Acc[b]}"]
4 [label="2"]
4 -> 2 [label="{b}\n{Acc[a]}"]
4 -> 3 [label="{a, b}\n{Acc[a]}"]
4 -> 5 [label="{a}\n{Acc[a]}"]
5 [label="3"]
5 -> 2 [label="{a, b}\n"]
5 -> 3 [label="{b}\n"]
5 -> 4 [label="{a}\n"]
}
#+end_example
#+NAME: gfagfb-gta
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgta --gta 'GFa & GFb' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: gfagfb-gta
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label=init]
1 -> 2 [label="a & b\\n"]
1 -> 3 [label="b & !a\\n"]
1 -> 4 [label="a & !b\\n"]
1 -> 5 [label="!b & !a\\n"]
2 [label="1",shape=box]
2 -> 3 [label="{a}\\n{Acc[b], Acc[a]}"]
2 -> 4 [label="{b}\\n{Acc[b], Acc[a]}"]
2 -> 5 [label="{a, b}\\n{Acc[b], Acc[a]}"]
3 [label="4"]
3 -> 2 [label="{a}\\n{Acc[b]}"]
3 -> 4 [label="{a, b}\\n{Acc[b]}"]
3 -> 5 [label="{b}\\n{Acc[b]}"]
4 [label="2"]
4 -> 2 [label="{b}\\n{Acc[a]}"]
4 -> 3 [label="{a, b}\\n{Acc[a]}"]
4 -> 5 [label="{a}\\n{Acc[a]}"]
5 [label="3"]
5 -> 2 [label="{a, b}\\n"]
5 -> 3 [label="{b}\\n"]
5 -> 4 [label="{a}\\n"]
}
#+end_example
#+BEGIN_SRC dot :file gfagfb-gta.png :cmdline -Tpng :var txt=gfagfb-gta :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:gfagfb-gta.png]]
The interpretation is similar to that of the TA. Execution that
stutter in a livelock-accepting (square) state are accepting as well
as execution that visit the =Acc[a]= and =Acc[b]= acceptance sets
infinitely often. Those acceptance sets are carried by transitions,
as in TGBAs.
Finally, the default is to output a Transition-based Generalized
Testing Automaton [fn:topnoc]. In TGTAs, the stuttering states are
made explicit with ={}= self-loops. Since these self-loop can be in
acceptance sets, livelock acceptance states are no longer needed.
#+BEGIN_SRC sh :results verbatim :exports code
ltl2tgta 'GFa & GFb'
#+END_SRC
#+RESULTS:
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label=init]
1 -> 2 [label="a & b\n"]
1 -> 3 [label="b & !a\n"]
1 -> 4 [label="a & !b\n"]
1 -> 5 [label="!b & !a\n"]
2 [label="3"]
2 -> 3 [label="{a}\n{Acc[b], Acc[a]}"]
2 -> 4 [label="{b}\n{Acc[b], Acc[a]}"]
2 -> 5 [label="{a, b}\n{Acc[b], Acc[a]}"]
2 -> 2 [label="{}\n{Acc[b], Acc[a]}"]
3 [label="4"]
3 -> 2 [label="{a}\n{Acc[b]}"]
3 -> 4 [label="{a, b}\n{Acc[b]}"]
3 -> 5 [label="{b}\n{Acc[b]}"]
3 -> 3 [label="{}\n"]
4 [label="2"]
4 -> 2 [label="{b}\n{Acc[a]}"]
4 -> 3 [label="{a, b}\n{Acc[a]}"]
4 -> 5 [label="{a}\n{Acc[a]}"]
4 -> 4 [label="{}\n"]
5 [label="1"]
5 -> 2 [label="{a, b}\n"]
5 -> 3 [label="{b}\n"]
5 -> 4 [label="{a}\n"]
5 -> 5 [label="{}\n"]
}
#+end_example
#+NAME: gfagfb-tgta
#+BEGIN_SRC sh :results verbatim :exports none
ltl2tgta 'GFa & GFb' | sed 's/\\/\\\\/'
#+END_SRC
#+RESULTS: gfagfb-tgta
#+begin_example
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label=init]
1 -> 2 [label="a & b\\n"]
1 -> 3 [label="b & !a\\n"]
1 -> 4 [label="a & !b\\n"]
1 -> 5 [label="!b & !a\\n"]
2 [label="1"]
2 -> 3 [label="{a}\\n{Acc[b], Acc[a]}"]
2 -> 4 [label="{b}\\n{Acc[b], Acc[a]}"]
2 -> 5 [label="{a, b}\\n{Acc[b], Acc[a]}"]
2 -> 2 [label="{}\\n{Acc[b], Acc[a]}"]
3 [label="4"]
3 -> 2 [label="{a}\\n{Acc[b]}"]
3 -> 4 [label="{a, b}\\n{Acc[b]}"]
3 -> 5 [label="{b}\\n{Acc[b]}"]
3 -> 3 [label="{}\\n"]
4 [label="3"]
4 -> 2 [label="{b}\\n{Acc[a]}"]
4 -> 3 [label="{a, b}\\n{Acc[a]}"]
4 -> 5 [label="{a}\\n{Acc[a]}"]
4 -> 4 [label="{}\\n"]
5 [label="2"]
5 -> 2 [label="{a, b}\\n"]
5 -> 3 [label="{b}\\n"]
5 -> 4 [label="{a}\\n"]
5 -> 5 [label="{}\\n"]
}
#+end_example
#+BEGIN_SRC dot :file gfagfb-tgta.png :cmdline -Tpng :var txt=gfagfb-tgta :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:gfagfb-tgta.png]]
[fn:topnoc]: This new class of automaton, as well as the
implementation of the previous testing automata classes, is part of
Ala Eddine BEN SALEM's PhD work, and should appear in a future edition
of ToPNoC (LNCS 7400).
# Local variables:
# eval: (setenv "PATH" (concat "../../src/bin" path-separator (getenv "PATH")))
# eval: (org-babel-do-load-languages 'org-babel-load-languages '((sh . t) (dot . t)))
# eval: (setq org-confirm-babel-evaluate nil)
# End:
# LocalWords: ltl tgta num toc Automata automata GraphViz UTF Gb na
# LocalWords: Geldenhuys tgba SRC init invis nb Acc augb sed png fn
# LocalWords: cmdline Tpng txt Büchi livelock gba gta GFa GFb TGTAs
# LocalWords: gfagfb topnoc Eddine SALEM's ToPNoC LNCS eval setenv
# LocalWords: concat getenv setq

373
doc/org/ltlcross.org Normal file
View file

@ -0,0 +1,373 @@
#+TITLE: =ltlcross=
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
#+LINK_UP: file:tools.html
=ltlcross= is a tool for cross-comparing the output of LTL-to-Büchi
translators. It is actually a Spot-based clone of [[http://www.tcs.hut.fi/Software/lbtt/][LBTT]], the
/LTL-to-Büchi Translator Testbench/, that essentially performs the
same sanity checks.
The main motivations for rewriting this tool were:
- support for PSL formulas in addition to LTL
- more statistics (like counting the number of logical transitions
represented by each physical edge), output in a format that
can be more easily be post-processed,
- more precise time measurement (LBTT was only precise to
1/100 of a second, reporting most times as "0.00s").
Although =ltlcross= performs the same sanity checks as LBTT, it does
not implement any of the interactive features of LBTT. Essentially
=ltlcross= will report problems, but you will be on your own to
investigate and fix them.
The core of =ltlcross= is a loop that does the following steps:
- Input a formula
- Translate the formula and its negation using each configured translator.
If there are 3 translators, the positive and negative translations
will be denoted =P0=, =N0=, =P1=, =N1=, =P2=, =N2=.
- Build the products of these automata with a random state-space (the same
state-space for all translations).
- Perform sanity checks between all these automata to detect any problem.
- Gather statistics if requested.
* Formula selection
Formulas to translate should be specified using the [[file:ioltl.org][common input options]].
Standard input is read if no =-f= or =-F= option is given.
* Configuring translators
Each translator should be specified as a string that use some of the
following character sequences:
#+BEGIN_SRC sh :results verbatim :exports results
ltlcross --help | sed -n '/character sequences:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
: %f,%s,%l,%w the formula as a (quoted) string in Spot, Spin,
: LBT, or Wring's syntax
: %F,%S,%L,%W the formula as a file in Spot, Spin, LBT, or
: Wring's syntax
: %N,%T the output automaton as a Never claim, or in
: LBTT's format
For instance here is how we could cross-compare the never claims
output by =spin= and =ltl2tgba= for the formulas =GFa= and =X(a U b)=.
#+BEGIN_SRC sh :results verbatim :exports code
ltlcross -f 'GFa' -f 'X(a U b)' 'ltl2tgba -s %s >%N' 'spin -f %s >%N'
#+END_SRC
#+RESULTS:
When =ltlcross= executes these commands, =%s= will be replaced
by the formula in Spin's syntax, and =%N= will be replaced by a
temporary file into which the output of the translator is redirected
before it is read back by =ltlcross=.
#+BEGIN_SRC sh :results verbatim :exports results
ltlcross -f 'GFa' -f 'X(a U b)' 'ltl2tgba -s %s >%N' 'spin -f %s >%N' 2>&1
#+END_SRC
#+RESULTS:
#+begin_example
([](<>(a)))
Running [P0]: ltl2tgba -s '([](<>(a)))' >'lck-o0-iDGV6y'
Running [P1]: spin -f '([](<>(a)))' >'lck-o1-sA3FYp'
Running [N0]: ltl2tgba -s '(!([](<>(a))))' >'lck-o0-1ClVQg'
Running [N1]: spin -f '(!([](<>(a))))' >'lck-o1-wyErP7'
Performing sanity checks and gathering statistics...
(X((a) U (b)))
Running [P0]: ltl2tgba -s '(X((a) U (b)))' >'lck-o0-ex1BYY'
Running [P1]: spin -f '(X((a) U (b)))' >'lck-o1-UNE8dQ'
Running [N0]: ltl2tgba -s '(!(X((a) U (b))))' >'lck-o0-coM8tH'
Running [N1]: spin -f '(!(X((a) U (b))))' >'lck-o1-eHPoQy'
Performing sanity checks and gathering statistics...
no problem detected
#+end_example
=ltlcross= can only read two kinds of output:
- Never claims (only if they are restricted to representing an
automaton using =if=, =goto=, and =skip= statements) such as those
output by [[http://spinroot.com/][=spin=]], [[http://www.lsv.ens-cachan.fr/~gastin/ltl2ba/][=ltl2ba=]], [[http://sourceforge.net/projects/ltl3ba/][=ltl3ba=]], or =ltl2tgba --spin=. These
should be indicated using =%N=.
- [[http://www.tcs.hut.fi/Software/lbtt/doc/html/Format-for-automata.html][LBTT's format]], which supports generalized Büchi automata with
either state-based acceptance or transition-based acceptance.
This output is used for instance by [[http://www.tcs.hut.fi/Software/maria/tools/lbt/][=lbt=]], [[http://web.archive.org/web/20080607170403/http://www.science.unitn.it/~stonetta/modella.html][=modella=]], or =ltl2tgba
--lbtt=. These should be indicated using =%T=.
Of course all configured tools need not the same =%= sequences.
* Getting statistics
Detailed statistics about the result of each translation, and the
product of that resulting automaton with the random state-space, can
be obtained using the =--csv=FILE= or =--json=FILE= option.
The following compare =ltl2tgba=, =spin=, and =lbt= on three random
formula (where =W= and =M= operators have been removed because they
are not supported by =spin= and =lbt=).
#+BEGIN_SRC sh :results verbatim :exports code
randltl -n 2 a b |
ltlfilt --remove-wm |
ltlcross --csv=results.csv \
'ltl2tgba -s %f >%N' \
'spin -f %s >%N' \
'lbt < %L >%T'
#+END_SRC
#+RESULTS:
#+BEGIN_SRC sh :results verbatim :exports results
randltl -n 2 a b c | ltlfilt --remove-wm |
ltlcross --csv=results.csv --json=results.json \
'ltl2tgba -s %f >%N' \
'spin -f %s >%N' \
'lbt < %L >%T' --csv=results.csv 2>&1
#+END_SRC
#+RESULTS:
#+begin_example
-:1: (G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1)))))))
Running [P0]: ltl2tgba -s '(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1)))))))' >'lck-o0-eGEYaZ'
Running [P1]: spin -f '([](((p0) U ((p0) && ([](p1)))) V (([](p1)) || ((p0) U ((p0) && ([](p1)))))))' >'lck-o1-nYpFBX'
Running [P2]: lbt < 'lck-i0-fGdZQ0' >'lck-o2-CPs23V'
Running [N0]: ltl2tgba -s '(!(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1))))))))' >'lck-o0-kXiZZS'
Running [N1]: spin -f '(!([](((p0) U ((p0) && ([](p1)))) V (([](p1)) || ((p0) U ((p0) && ([](p1))))))))' >'lck-o1-7ILLzR'
Running [N2]: lbt < 'lck-i0-9KG0wU' >'lck-o2-CcMCaQ'
Performing sanity checks and gathering statistics...
-:2: (!((G(F(p0))) -> (F(p1))))
Running [P0]: ltl2tgba -s '(!((G(F(p0))) -> (F(p1))))' >'lck-o0-IOckzW'
Running [P1]: spin -f '(!((<>(p1)) || (!([](<>(p0))))))' >'lck-o1-tsT3RZ'
Running [P2]: lbt < 'lck-i1-5TJXmT' >'lck-o2-5E9jb3'
Running [N0]: ltl2tgba -s '(G(F(p0))) -> (F(p1))' >'lck-o0-M3XRO9'
Running [N1]: spin -f '(<>(p1)) || (!([](<>(p0))))' >'lck-o1-6nxqfd'
Running [N2]: lbt < 'lck-i1-4hS5u6' >'lck-o2-vNItGg'
Performing sanity checks and gathering statistics...
no problem detected
#+end_example
After this execution, the file =results.csv= contains the following:
#+BEGIN_SRC sh :results verbatim :exports results
cat results.csv
#+END_SRC
#+RESULTS:
#+begin_example
"formula", "tool", "states", "edges", "transitions", "acc", "scc", "nondetstates", "nondeterministic", "time", "product_states", "product_transitions", "product_scc"
"(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1)))))))", "ltl2tgba -s %f >%N", 3, 5, 9, 1, 3, 2, 1, 0.0453898, 401, 5136, 3
"(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1)))))))", "spin -f %s >%N", 6, 13, 18, 1, 3, 6, 1, 0.0108596, 995, 14384, 5
"(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1)))))))", "lbt < %L >%T", 8, 41, 51, 1, 3, 8, 1, 0.00343479, 1389, 42998, 5
"(!(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1))))))))", "ltl2tgba -s %f >%N", 4, 10, 16, 1, 3, 0, 0, 0.0437875, 797, 16340, 3
"(!(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1))))))))", "spin -f %s >%N", 7, 24, 63, 1, 4, 6, 1, 0.0061535, 1400, 64668, 4
"(!(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1))))))))", "lbt < %L >%T", 39, 286, 614, 3, 28, 33, 1, 0.00384434, 7592, 602204, 4400
"(!((G(F(p0))) -> (F(p1))))", "ltl2tgba -s %f >%N", 2, 4, 4, 1, 1, 0, 0, 0.0416853, 398, 4198, 1
"(!((G(F(p0))) -> (F(p1))))", "spin -f %s >%N", 2, 3, 5, 1, 1, 1, 1, 0.00325558, 398, 5227, 1
"(!((G(F(p0))) -> (F(p1))))", "lbt < %L >%T", 5, 10, 15, 1, 4, 5, 1, 0.00299424, 409, 6401, 12
"(G(F(p0))) -> (F(p1))", "ltl2tgba -s %f >%N", 3, 5, 11, 1, 3, 1, 1, 0.0422192, 600, 11663, 3
"(G(F(p0))) -> (F(p1))", "spin -f %s >%N", 3, 5, 14, 1, 3, 1, 1, 0.00293655, 600, 14840, 3
"(G(F(p0))) -> (F(p1))", "lbt < %L >%T", 11, 18, 54, 2, 11, 5, 1, 0.0030133, 1253, 26891, 457
#+end_example
This can be loaded in any spreadsheet application. Although we only
supplied 2 random generated formulas, the output contains 4 formulas because
=ltlcross= had to translate the positive and negative version of each.
If we had used the option =--json=results.json= instead of
=--cvs=results.csv=, the file =results.json= would have contained the
following [[http://www.json.org/][JSON]] output.
#+BEGIN_SRC sh :results verbatim :exports results
cat results.json
#+END_SRC
#+RESULTS:
#+begin_example
{
"tools": [
"ltl2tgba -s %f >%N",
"spin -f %s >%N",
"lbt < %L >%T"
],
"inputs": [
"(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1)))))))",
"(!(G(((p0) U ((p0) & (G(p1)))) R ((G(p1)) | ((p0) U ((p0) & (G(p1))))))))",
"(!((G(F(p0))) -> (F(p1))))",
"(G(F(p0))) -> (F(p1))"
],
"fields": [
"input", "tool", "states", "edges", "transitions", "acc", "scc", "nondetstates", "nondeterministic", "time", "product_states", "product_transitions", "product_scc"
],
"results": [
[ 0, 0, 3, 5, 9, 1, 3, 2, 1, 0.0431589, 401, 5136, 3 ],
[ 0, 1, 6, 13, 18, 1, 3, 6, 1, 0.0104812, 995, 14384, 5 ],
[ 0, 2, 8, 41, 51, 1, 3, 8, 1, 0.00321619, 1389, 42998, 5 ],
[ 1, 0, 4, 10, 16, 1, 3, 0, 0, 0.0443761, 797, 16340, 3 ],
[ 1, 1, 7, 24, 63, 1, 4, 6, 1, 0.00623927, 1400, 64668, 4 ],
[ 1, 2, 39, 286, 614, 3, 28, 33, 1, 0.00386306, 7592, 602204, 4400 ],
[ 2, 0, 2, 4, 4, 1, 1, 0, 0, 0.0414639, 398, 4198, 1 ],
[ 2, 1, 2, 3, 5, 1, 1, 1, 1, 0.00327304, 398, 5227, 1 ],
[ 2, 2, 5, 10, 15, 1, 4, 5, 1, 0.00322862, 409, 6401, 12 ],
[ 3, 0, 3, 5, 11, 1, 3, 1, 1, 0.0432979, 600, 11663, 3 ],
[ 3, 1, 3, 5, 14, 1, 3, 1, 1, 0.00296043, 600, 14840, 3 ],
[ 3, 2, 11, 18, 54, 2, 11, 5, 1, 0.00295457, 1253, 26891, 457 ]
]
}
#+end_example
Here the =fields= table describes the columns of the =results= table,
and the =input= and =tool= columns contains indices relative to the
=inputs= and =tools= table. This format is more compact when dealing
with lots of translators and formulas, because they don't have to be
repeated on each line as in the CSV version.
JSON data can be easily processed in any language. For instance the
following Python3 script averages each column for each tool,
and presents the results in a form that can almost be copied into a
LaTeX table (the =%= in the tool names have to be taken care of).
#+BEGIN_SRC python :results output :exports both
#!/usr/bin/python3
import json
data = json.load(open('results.json'))
datacols = range(2, len(data["fields"]))
# Index results by tool
results = { t:[] for t in range(0, len(data["tools"])) }
for l in data["results"]:
results[l[1]].append(l)
# Average columns for each tools, and display them as a table
print("%-18s &" % "tool", "count &",
" & ".join(data["fields"][2:]), "\\\\")
for i in range(0, len(data["tools"])):
c = len(results[i])
sums = ["%6.2f" % (sum([x[j] for x in results[i]])/c)
for j in datacols]
print("%-18s & %3d & " % (data["tools"][i], c),
" & ".join(sums), "\\\\")
#+END_SRC
#+RESULTS:
: tool & count & states & edges & transitions & acc & scc & nondetstates & nondeterministic & time & product_states & product_transitions & product_scc \\
: ltl2tgba -s %f >%N & 4 & 3.00 & 6.00 & 10.00 & 1.00 & 2.50 & 0.75 & 0.50 & 0.04 & 549.00 & 9334.25 & 2.50 \\
: spin -f %s >%N & 4 & 4.50 & 11.25 & 25.00 & 1.00 & 2.75 & 3.50 & 1.00 & 0.01 & 848.25 & 24779.75 & 3.25 \\
: lbt < %L >%T & 4 & 15.75 & 88.75 & 183.50 & 1.75 & 11.50 & 12.75 & 1.00 & 0.00 & 2660.75 & 169623.50 & 1218.50 \\
When computing such statistics, you should be aware that inputs for
which a tool failed to generate an automaton (e.g. it crashed, or it
was killed if you used =ltlcross='s =--timeout= option to limit run
time) are not represented in the CSV or JSON files. However data for
bogus automata are still included: as shown below =ltlcross= will
report inconsistencies between automata as errors, but it does not try
to guess who is incorrect.
* Detecting problems
If a translator exits with a non-zero status code, or fails to output
an automaton =ltlcross= can read, and error will be displayed and the
result of the translation will be discarded.
Otherwise =ltlcross= performs the following checks on all translated
formulas ($P_i$ and $N_i$ designate respectively the translation of
positive and negative formulas by the ith translator).
- Intersection check: $P_i\otimes N_j$ must be empty for all
pairs of $(i,j)$.
A single failing translator might generate a lot of lines of
the form:
: error: P0*N1 is nonempty
: error: P1*N0 is nonempty
: error: P1*N1 is nonempty
: error: P1*N2 is nonempty
: error: P1*N3 is nonempty
: error: P1*N4 is nonempty
: error: P1*N5 is nonempty
: error: P1*N6 is nonempty
: error: P1*N7 is nonempty
: error: P1*N8 is nonempty
: error: P1*N9 is nonempty
: error: P2*N1 is nonempty
: error: P3*N1 is nonempty
: error: P4*N1 is nonempty
: error: P5*N1 is nonempty
: error: P6*N1 is nonempty
: error: P7*N1 is nonempty
: error: P8*N1 is nonempty
: error: P9*N1 is nonempty
In this example, translator number =1= looks clearly faulty
(at least the other 9 translators do not contradict each other).
- Cross-comparison checks: for some state-space $S$,
all $P_i\otimes S$ are either all empty, or all non-empty.
Similarly all $N_i\otimes S$ are either all empty, or all non-empty.
A cross-comparison failure could be displayed as:
: error: {P0,P2,P3,P4,P5,P6,P7,P8,P9} disagree with {P1} when evaluating the state-space
- Consistency check:
For each $i$, the products $P_i\otimes S$ and $N_i\otimes S$
actually cover all states of $S$. Because $S$ does not have any
deadlock, any of its infinite path must be accepted by $P_i$ or
$N_i$ (or both).
An error in that case is displayed as
: error: inconsistency between P1 and N1
The above checks are the same that are performed by [[http://www.tcs.hut.fi/Software/lbtt/][LBTT]].
If any problem was reported during the translation of one of the
formulas, =ltlcheck= will exit with an exit status of =1=. Statistics
(if requested) are output nonetheless, and include any faulty
automaton as well.
* Miscellaneous options
** =--stop-on-error=
The =--stop-on-error= will cause =ltlcross= to abort on the first
detected error. This include failure to start some translator, read
its output, or failure to passe the sanity checks. Timeouts are
allowed.
One use for this option is when =ltlcross= is used in combination with
=randltl= to check translators on an infinite stream of formulas.
For instance the following will cross-compare =ltl2tgba= against
=ltl3ba= until it finds an error, or your interrupt the command, or it
runs out of memory (the hash tables used by =randltl= and =ltlcross=
to remove duplicate formulas will keep growing).
#+BEGIN_SRC sh :export code :eval no
randltl -n -1 --tree-size 10..25 a b c | ltlcross --stop-on-error 'ltl2tgba --lbtt %f >%T' 'ltl3ba -f %s >%N'
#+END_SRC
** =--no-check=
The =--no-check= option disables all sanity checks, and only use the supplied
formulas in their positive form.
When checks are enabled, the negated formulas are intermixed with the
positives ones in the results. Therefore the =--no-check= option can
be used to gather statistics about a specific set of formulas.
# Local variables:
# eval: (setenv "PATH" (concat "../../src/bin" path-separator (getenv "PATH")))
# eval: (org-babel-do-load-languages 'org-babel-load-languages '((sh . t) (dot . t) (python . t)))
# eval: (setq org-confirm-babel-evaluate nil)
# eval: (setq org-babel-python-command "/usr/bin/python3")
# End:
# LocalWords: ltlcross num toc LTL Büchi LBTT Testbench PSL SRC sed
# LocalWords: automata LBT LBTT's ltl tgba GFa lck iDGV sA FYp BYY
# LocalWords: ClVQg wyErP UNE dQ coM tH eHPoQy goto ba lbt modella
# LocalWords: lbtt csv json randltl ltlfilt wm eGEYaZ nYpFBX fGdZQ
# LocalWords: CPs kXiZZS ILLzR wU CcMCaQ IOckzW tsT RZ TJXmT jb XRO
# LocalWords: nxqfd hS vNItGg acc scc nondetstates nondeterministic
# LocalWords: cvs LaTeX datacols len ith otimes ltlcheck eval setq
# LocalWords: setenv concat getenv

233
doc/org/ltlfilt.org Normal file
View file

@ -0,0 +1,233 @@
#+TITLE: =ltlfilt=
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
#+LINK_UP: file:tools.html
This tool is a filter for LTL formulas. (It will also work with PSL
formulas.) It can be used to perform a number of tasks. Essentially:
- converting formulas from one syntax to another,
- transforming formulas,
- selecting formulas matching some criterion.
* Changing syntaxes
Because it read and write formulas, =ltlfilt= accepts
all the [[file:ioltl.org][common input and output options]].
Additionally, if no =-f= or =-F= option is specified, =ltlfilt=
will read formulas from the standard input.
For instance the following will convert two LTL formulas expressed
using infix notation (with different names supported for the same
operators) and convert it into LBT's syntax.
#+BEGIN_SRC sh :results verbatim :exports results
ltlfilt -l -f 'p1 U (p2 & GFp3)' -f 'X<>[]p4'
#+END_SRC
#+RESULTS:
: U p1 & p2 G F p3
: X F G p4
Conversely, here is how to rewrite formulas expressed using the
LBT's Polish notation. Let's take the following four formulas
taken from examples distributed with =scheck=:
#+BEGIN_SRC sh :results verbatim :exports both
cat >scheck.ltl<<EOF
! | G p0 & G p1 F p3
| | X p7 F p6 & | | t p3 p7 U | f p3 p3
& U & X p0 X p4 F p1 X X U X F p5 U p0 X X p3
U p0 & | p0 p5 p1
EOF
#+END_SRC
#+RESULTS:
These can be turned into something easier to read (to the human) with:
#+BEGIN_SRC sh :results verbatim :exports both
ltlfilt --lbt-input -F scheck.ltl
#+END_SRC
#+RESULTS:
: !(Gp0 | (Gp1 & Fp3))
: Xp7 | Fp6 | p3
: ((Xp0 & Xp4) U Fp1) & XX(XFp5 U (p0 U XXp3))
: p0 U ((p0 | p5) & p1)
* Altering the formula
As with [[file:randltl.org][=randltl=]], the =-r= option can be used to simplify formulas.
#+BEGIN_SRC sh :results verbatim :exports both
ltlfilt --lbt-input -F scheck.ltl -r
#+END_SRC
#+RESULTS:
: F!p0 & (F!p1 | G!p3)
: p3 | Xp7 | Fp6
: Fp1 & XX(XFp5 U (p0 U XXp3))
: p0 U (p1 & (p0 | p5))
You may notice that operands of n-ary operators such as =&= or =|= can
be reordered by =ltlfilt= even when the formula is not changed
otherwise. This is because Spot internally order all operands of
commutative and associative operators, and that this order depends on
the order in which the subformulas are first encountered. Adding
transformation options such as =-r= may alter this order. However
this difference is semantically insignificant.
Formulas can be easily negated using the =-n= option, rewritten into
negative normal form using the =--nnf= option, and the =W= and =M=
operators can be rewritten using =U= and =R= using the =--remove-wm=
option (note that this is already done when a formula is output in
Spin's syntax).
Another way to alter formula is to rename the atomic propositions it
uses. The =--relabel=abc= will relabel all atomic propositions using
letters of the alphabet, while =--relabel=pnn= will use =p0=, =p1=,
etc. as in LBT's syntax.
#+BEGIN_SRC sh :results verbatim :exports both
ltlfilt --lbt-input -F scheck.ltl -r --relabel=abc
#+END_SRC
#+RESULTS:
: F!a & (F!b | G!c)
: a | Xb | Fc
: Fa & XX(XFb U (c U XXd))
: a U (b & (a | c))
Note that the relabeling is reset between each formula: =p3= became
=c= in the first formula, but it became =d= in the third.
Another use of relabeling is to get rid of complex atomic propositions
such as the one shown when [[file:ioltl.org][presenting lenient mode]]:
#+BEGIN_SRC sh :results verbatim :exports both
ltlfilt --lenient --relabel=pnn -f '(a < b) U (process[2]@ok)'
#+END_SRC
#+RESULTS:
: p0 U p1
* Filtering
=ltlfilt= supports many ways to filter formulas:
#+BEGIN_SRC sh :results verbatim :exports results
ltlfilt --help | sed -n '/Filtering options.*:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
#+begin_example
--boolean match Boolean formulas
--bsize-max=INT match formulas with Boolean size <= INT
--bsize-min=INT match formulas with Boolean size >= INT
--equivalent-to=FORMULA match formulas equivalent to FORMULA
--eventual match pure eventualities
--guarantee match guarantee formulas (even pathological)
--implied-by=FORMULA match formulas implied by FORMULA
--imply=FORMULA match formulas implying FORMULA
--ltl match only LTL formulas (no PSL operator)
--nox match X-free formulas
--obligation match obligation formulas (even pathological)
--safety match safety formulas (even pathological)
--size-max=INT match formulas with size <= INT
--size-min=INT match formulas with size >= INT
--syntactic-guarantee match syntactic-guarantee formulas
--syntactic-obligation match syntactic-obligation formulas
--syntactic-persistence match syntactic-persistence formulas
--syntactic-recurrence match syntactic-recurrence formulas
--syntactic-safety match syntactic-safety formulas
--universal match purely universal formulas
-u, --unique drop formulas that have already been output (not
affected by -v)
-v, --invert-match select non-matching formulas
#+end_example
Most of the above options should be self-explanatory. For instance
the following command will extract all formulas from =scheck.ltl=
which do not represent guarantee properties.
#+BEGIN_SRC sh :results verbatim :exports both
ltlfilt --lbt-input -F scheck.ltl -v --guarantee
#+END_SRC
#+RESULTS:
: !(Gp0 | (Gp1 & Fp3))
Combining =ltlfilt= with [[file:randltl.org][=randltl=]] makes it easier to generate random
formulas that respect certain constraints. For instance let us
generate 10 formulas that are equivalent to =a U b=:
#+BEGIN_SRC sh :results verbatim :exports both
randltl -n -1 a b | ltlfilt --equivalent-to 'a U b' | head -n 10
#+END_SRC
#+RESULTS:
#+begin_example
!(!a R !b)
(!Gb -> a) U b
a U b
Fb & (a W b)
((a <-> !(a | b)) W a) U ((!b M b) U b)
(b <-> (Xb M a)) -> b
(a | b) U b
((!b U b) -> (a W b)) U b
(a xor b) U b
b R (Fb & (a U (a W b)))
#+end_example
The =-n -1= option to =randltl= will cause it to output an infinite
stream of random formulas. =ltlfilt=, which reads its standard input
by default, will select only those equivalent to =a U b=. The output
of =ltlfilt= would still be an infinite stream of random formulas, so
we display only the first 10 using the standard =head= utility. Less
trivial formulas could be obtained by adding the =-r= option to
=randltl= (or equivalently adding the =-r= and =-u= option to
=ltlfilt=).
Another similar example, that requires two calls to =ltlfilt=, is the
generation of random pathological safety formulas. Pathological
safety formulas are safety formulas that do not /look/ so
syntactically. We can generate some starting again with =randltl=,
then ignoring all syntactic safety formulas, and keeping only the
safety formulas in the remaining list.
#+BEGIN_SRC sh :results verbatim :exports both
randltl -r -n -1 a b | ltlfilt -v --syntactic-safety | ltlfilt --safety | head -n 10
#+END_SRC
#+RESULTS:
#+begin_example
(!a & Fa) R Xa
!a | (a & b) | (((!a & b) | (a & !b)) M (!a M X!a))
G(!a M Xa)
G((G!b & !a) | (a & Fb)) R a
G!a M !a
G(!a M ((!b & XGb) | (b & XF!b)))
F(b | G!b)
F(Xa | G!a)
G(XXa | (b & F!a))
G((!a & (!a M !b)) | (a & (a W b)))
#+end_example
=ltlfilt='s filtering ability can also be used to answer questions
about a single formula. For instance is =a U (b U a)= equivalent to
=b U a=?
#+BEGIN_SRC sh :results verbatim :exports both
ltlfilt -f 'a U (b U a)' --equivalent-to 'b U a'
#+END_SRC
#+RESULTS:
: a U (b U a)
The commands prints the formula and returns an exit status of 0 if the
two formulas are equivalent. It would print nothing and set the exit
status to 1, were the two formulas not equivalent.
# Local variables:
# eval: (setenv "PATH" (concat "../../src/bin" path-separator (getenv "PATH")))
# eval: (org-babel-do-load-languages 'org-babel-load-languages '((sh . t) (dot . t)))
# eval: (setq org-confirm-babel-evaluate nil)
# End:
# LocalWords: ltlfilt num toc LTL PSL syntaxes LBT's SRC GFp scheck
# LocalWords: ltl EOF lbt Gp Fp Xp XFp XXp randltl ary nnf wm abc
# LocalWords: pnn Xb Fc XFb XXd sed boolean bsize nox Gb Fb Xa XGb
# LocalWords: XF XXa

327
doc/org/randltl.org Normal file
View file

@ -0,0 +1,327 @@
#+TITLE: =randltl=
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
#+LINK_UP: file:tools.html
This tool generates random formulas. By default, it will generate one
random LTL formula using atomic propositions supplied on the
command-line. It can be instructed to generate random Boolean or PSL
formulas instead, but let us first focus on LTL generation.
For instance to obtain one random LTL formula over the propositions
=a=, =b=, or =c=, use:
#+BEGIN_SRC sh :results verbatim :exports both
randltl a b c
#+END_SRC
#+RESULTS:
: G(Gb W (Gb M c))
Note that the result does not always use all atomic propositions.
The syntax of the formula output can be changed using the
[[file:ioltl.org][common output options]]:
#+BEGIN_SRC sh :results verbatim :exports results
randltl --help | sed -n '/Output options:/,/^$/p' | sed '1d;$d'
#+END_SRC
#+RESULTS:
: -8, --utf8 output using UTF-8 characters
: -l, --lbt output in LBT's syntax
: -p, --full-parentheses output fully-parenthesized formulas
: -s, --spin output in Spin's syntax
: --spot output in Spot's syntax (default)
: --wring output in Wring's syntax
When you select Spin's or Wring's syntax, operators =W= and =M= are
automatically rewritten using =U= and =R= (written =V= for Spin).
When you select LBT's syntax, you should name you atomic propositions
like =p0=, =p1=, etc... (Atomic proposition named differently will be
output by Spot in double-quotes, but this is not supported by LBT.)
#+BEGIN_SRC sh :results verbatim :exports both
randltl -l p1 p2 p3
randltl -8 p1 p2 p3
randltl -s p1 p2 p3
randltl --wring p1 p2 p3
#+END_SRC
#+RESULTS:
: G W G p2 M G p2 p3
: □(□p2 W (□p2 M p3))
: []((p3 U (p3 && []p2)) V ([]p2 || (p3 U (p3 && []p2))))
: (G(((p3=1) U ((p3=1) * (G(p2=1)))) R ((G(p2=1)) + ((p3=1) U ((p3=1) * (G(p2=1)))))))
As you might guess from the above result, for a given set of atomic
propositions (and on the same computer) the generated formula will
always be the same. This is because each time =randltl= starts, it
initialize the seed of the random number generator to =0=. This seed
can be changed using the =--seed= option. For instance the following
three commands:
#+BEGIN_SRC sh :results verbatim :exports both
randltl a b c
randltl --seed=123 a b c
randltl --seed=0 a b c
#+END_SRC
Will give three formulas in which the first and last are identical:
#+RESULTS:
: G(Gb W (Gb M c))
: X((c <-> F(a M Xc)) -> a)
: G(Gb W (Gb M c))
When generating random formulas, we usually want large quantity of
them. Rather than running =randltl= several times with different
seeds, we can use the =-n= option to specify a number of formulas to
produce.
#+BEGIN_SRC sh :results verbatim :exports both
randltl -n 5 a b c
#+END_SRC
#+RESULTS:
: G(Gb W (Gb M c))
: !(GFb -> Fa)
: (((c xor Xc) R c) R Gc) & !c
: X(1 U Xb) M Fb
: !XFb U !(Xa W 0)
By default =randltl= will never output the same formula twice (this
can be changed with the =--allow-dups= option), so it may generate
more formulas internally than it eventually prints. To ensure
termination, for each output formula the number of ignored (because
duplicated) random formulas that are generated is limited to 100000.
Therefore in some situations, most likely when generating small
formulas, with few atomic proposition, you may see =randltl= stop
before the requested number of formulas has been output with an error
message.
If the integer passed to =-n= is negative, =randltl= will attempt to
generate as many formulas as it can. This is most useful when
=randltl= is piped to =ltlfilt= to select random formulas matching a
certain criterion, as we shall see later.
Besides the list of atomic propositions (=a b c= in our example) and
the seed, several other parameters control the generation of the
random formulas.
Initially, the random generator selects a tree size for the formula.
The default size is =15=, but it can be changed using the =--tree-size=
option. For instance in the following, for each formula the tree size
will be chosen randomly in the range =22..30=.
#+BEGIN_SRC sh :results verbatim :exports both
randltl -n 5 a b c --tree-size=22..30
#+END_SRC
#+RESULTS:
: ((Fc W 0) M 1) & ((a | XXc) M (b W Fb))
: (!(c | (a R Xb)) <-> (Xc R (a & c))) -> !a
: 0
: X(Xc R GX(1 U Xb)) & GX(b M Xc)
: (!b -> ((c xor Fa) W b)) W (!Fb U a)
The tree size is just the number of nodes in the syntax tree of the
formula during its construction. However because Spot automatically
applies some /trivial simplifications/ during the construction of its
formulas (e.g., =F(F(a)= is reduced to =F(a)=, =a&0= to =0=, etc.),
the actual size of the formula output may be smaller than the
tree size specified.
It is pretty common to obtain the formulas =0= or =1= among the first
formulas output, since many random formulas trivially simplify to
these. However because duplicate formulas are suppressed by default,
they shall only occur once.
Stronger simplifications may be requested using the =-r= option, that
implements many rewritings that helps Spot translators algorithms (so
beware that using =-r= reduces the randomness of the output).
#+BEGIN_SRC sh :results verbatim :exports both
randltl -n 5 a b c --tree-size=22..30 -r
#+END_SRC
#+RESULTS:
: GFc & ((a | XXc) M Fb)
: !a | (!c & (!a U X!b)) | (a & c & Xc)
: 0
: XG(b M Xc)
: (((!c & Fa) | (c & G!a)) W b) W (G!b U a)
The generator build the syntax tree recursively from its root, by
considering all operators that could be used for a given tree size (for
example a tree-size of 2 disables binary operators). A /priority/ is
associated to each operator, and the probability of this operator
being selected is this priority over the sum of the priorities of all
considered operators. The default priorities for each operator can
be seen with =--dump-priorities=:
#+BEGIN_SRC sh :results verbatim :exports both
randltl a b c --dump-priorities
#+END_SRC
#+RESULTS:
#+begin_example
Use --ltl-priorities to set the following LTL priorities:
ap 3
false 1
true 1
not 1
F 1
G 1
X 1
equiv 1
implies 1
xor 1
R 1
U 1
W 1
M 1
and 1
or 1
#+end_example
Where =ap= stands for /atomic propositions/ (=a=, =b=, =c=). In this
example, when the generator builds a leaf of the syntax tree (i.e., a
subformula of tree-size 1), it must ignore all operators, and chose
between =ap=, =false=, or =true=, and the odds of choosing =ap= is
3/(3+1+1).
As indicated at the top of the output, these priorities can be changed
using the =--ltl-priorities= options. The most common scenario is to
disable some of the operators by giving them a null priority. The
following example disables 6 operators, and augments the priority of
=U= to 3 to favor its occurrence.
#+BEGIN_SRC sh :results verbatim :exports both
randltl -n 5 a b c --ltl-priorities 'xor=0,implies=0,equiv=0,W=0,M=0,X=0,U=3'
#+END_SRC
#+RESULTS:
: F(Fb U (c & Gb))
: !(Fb U Fa)
: ((Gc U c) U c) U Fc
: 0
: 1
When using =-r= to simplify generated formulas, beware that these
rewritings may use operators that you disabled during the initial
random generation: you may obtain a formula that uses =W= even if =W=
has a null priority. (You can use =ltlfilt= to rewrite these
operators if that is a problem.)
If the =--weak-fairness= option is used, for each random formula
generated, a weak-fairness formula of the form =GF(a) & GF(b) & GF(c)=
is generated for a subset of the atomic propositions and "ANDed" to
the random formula. The =--tree-size= option has no influence on the
weak-fairness formula appended.
#+BEGIN_SRC sh :results verbatim :exports both
randltl -n 5 a b c --weak-fairness
#+END_SRC
#+RESULTS:
: G(Gb W (Gb M c)) & GFb
: GFb & !(GFb -> Fa) & GFa
: GFb & (((c xor Xc) R c) R Gc) & !c
: GFb & GFa & (X(1 U Xb) M Fb)
: GFb & (!XFb U !(Xa W 0)) & GFc
Boolean formulas may be output with the =-B= option:
#+BEGIN_SRC sh :results verbatim :exports both
randltl -B -n 5 a b c
#+END_SRC
#+RESULTS:
: !a -> !b
: !(!(a -> (b xor c)) -> !a)
: !c | (!c xor (c xor (c xor !c)))
: !b
: a xor !(!b <-> (!a -> c))
In that case, priorities should be set with =--boolean-priorities=.
Finally, PSL formulas may be output using the =-P= option. However
keep in mind that since LTL formulas are PSL formulas, generating
random PSL formula may produce many LTL formulas that do not use any
PSL operator (this is even more so the case when simplifications are
enabled with =-r=).
#+BEGIN_SRC sh :results verbatim :exports both
randltl -P -n 5 a b c
#+END_SRC
#+RESULTS:
: G(Gb M ((c & Xb) | (!a M 1)))
: !(Fa xor X({{c | {a xor !b}}[*]}[]-> Fb))
: c & Gc
: 0
: 1
As shown with the =--dump-priorities= output below, tweaking the
priorities used to generated PSL formulas requires three different
options:
#+BEGIN_SRC sh :results verbatim :exports both
randltl -P a b c --dump-priorities
#+END_SRC
#+RESULTS:
#+begin_example
Use --ltl-priorities to set the following LTL priorities:
ap 3
false 1
true 1
not 1
F 1
G 1
X 1
Closure 1
equiv 1
implies 1
xor 1
R 1
U 1
W 1
M 1
and 1
or 1
EConcat 1
UConcat 1
Use --sere-priorities to set the following SERE priorities:
eword 1
boolform 1
star 1
star_b 1
and 1
andNLM 1
or 1
concat 1
fusion 1
Use --boolean-priorities to set the following Boolean formula priorities:
ap 3
false 1
true 1
not 1
equiv 1
implies 1
xor 1
and 1
or 1
#+end_example
The =--ltl-priorities= option we have seen previously now recognize
some new PSL-specific operators: =Closure= is the ={sere}= operator,
=EConcat= is the ={sere}<>->f= operator, and =UConcat= is the
={sere}[]->f= operator. When these operator are selected, they
require a SERE argument which is generated according to the priorities
set by =--sere-priorities=: =eword= is the empty word, =boolform= is a
Boolean formula (generated using the priorities set by
=--boolean-priorities=), =star= is the unbounded Kleen star, while
=star_b= is the bounded version, and =andNLM= is the
non-length-matching variant of the =and= operator.
# Local variables:
# eval: (setenv "PATH" (concat "../../src/bin" path-separator (getenv "PATH")))
# eval: (org-babel-do-load-languages 'org-babel-load-languages '((sh . t) (dot . t)))
# eval: (setq org-confirm-babel-evaluate nil)
# End:
# LocalWords: randltl num toc LTL PSL SRC Gb sed utf UTF lbt LBT's
# LocalWords: Xc GFb Gc Xb Fb XFb Xa dups ltlfilt Fc XXc GX GFc XG
# LocalWords: rewritings ltl ap GF ANDed GFa boolean EConcat eword
# LocalWords: UConcat boolform andNLM concat Kleen eval setenv setq
# LocalWords: getenv

55
doc/org/tools.org Normal file
View file

@ -0,0 +1,55 @@
#+TITLE: Command-line tools installed by Spot 1.0
#+EMAIL spot@lrde.epita.fr
#+OPTIONS: H:2 num:nil toc:t
This document introduces command-line tools that are installed with
the Spot library. We give some examples to highlight possible
use-cases but shall not attempt to cover all features exhaustively
(please check the man pages for further inspiration).
* Conventions
For technical reasons related to the way we generate these pages, we
use the following convention when rendering shell commands. The
commands issued to the shell are formatted like this with a green line
on the left:
#+NAME: helloworld
#+BEGIN_SRC sh :results verbatim :exports both
echo Hello World
#+END_SRC
And the output of such a command is formatted as follows, with a red
line on the left:
#+RESULTS: helloworld
: Hello World
Parts of these documents (e.g., lists of options) are actually the
results of shell commands and will be presented as above, even if the
corresponding commands are hidden.
* Common options
- [[file:ioltl.org][common input and output options for LTL/PSL formulas]]
* Command-line tools
- [[file:randltl.org][=randltl=]] Generate random LTL/PSL formulas.
- [[file:ltlfilt.org][=ltlfilt=]] Filter LTL/PSL formulas.
- [[file:genltl.org][=genltl=]] Generate LTL formulas from scalable patterns.
- [[file:ltl2tgba.org][=ltl2tgba=]] Translate LTL/PSL formulas into Büchi automata.
- [[file:ltl2tgta.org][=ltl2tgta=]] Translate LTL/PSL formulas into Testing automata.
- [[file:ltlcross.org][=ltlcross=]] Cross-compare LTL/PSL-to-Büchi translators.
# Local variables:
# eval: (setenv "PATH" (concat "../../src/bin" path-separator (getenv "PATH")))
# eval: (org-babel-do-load-languages 'org-babel-load-languages '((sh . t) (dot . t)))
# eval: (setq org-confirm-babel-evaluate nil)
# End:
# LocalWords: num toc helloworld SRC LTL PSL randltl ltlfilt genltl
# LocalWords: scalable ltl tgba Büchi automata tgta ltlcross eval
# LocalWords: setenv concat getenv setq