import spot
from IPython.display import display # not needed with recent Jupyter
For interactive use, formulas can be entered as text strings and passed to the spot.formula
constructor.
f = spot.formula('p1 U p2 R (p3 & !p4)')
f
g = spot.formula('{a;first_match((b*;c[+])[:*3..5];b)}<>->(GFb & c)'); g
By default the parser recognizes an infix syntax, but when this fails, it tries to read the formula with the LBT syntax:
h = spot.formula('& | a b c'); h
Passing a formula
to spot.formula
simply returns the formula.
spot.formula(h)
By default, a formula object is presented using mathjax as above. When a formula is converted to string you get Spot's syntax by default:
str(f)
If you prefer to print the string in another syntax, you may use the to_str()
method, with an argument that indicates the output format to use. The latex
format assumes that you will the define macros such as \U
, \R
to render all operators as you wish. On the other hand, the sclatex
(with sc
for self-contained) format hard-codes the rendering of each of those operators: this is almost the same output that is used to render formulas using MathJax in a notebook. sclatex
and mathjax
only differ in the rendering of double-quoted atomic propositions.
for i in ['spot', 'spin', 'lbt', 'wring', 'utf8', 'latex', 'sclatex', 'mathjax']:
print(f"{i:10}{f.to_str(i)}")
Formulas output via format()
of f-strings can also use some convenient shorthand to select the syntax:
print(f"""\
Spin: {f:s}
Spin+parentheses: {f:sp}
Spot (default): {f}
Spot+shell quotes: {f:q}
LBT, right aligned: {f:l:~>40}
LBT, no M/W/R: {f:[MWR]l}""")
The specifiers that can be used with format
are documented as follows.
(Note: As this document is part of our test-suite we have to use print(x.__doc__)
instead of help(x)
to work around some formating changes introduced in Python 3.12's help()
.)
print(spot.formula.__format__.__doc__)
A spot.formula
object has a number of built-in predicates whose value have been computed when the formula was constructed. For instance you can check whether a formula is in negative normal form using is_in_nenoform()
, and you can make sure it is an LTL formula (i.e. not a PSL formula) using is_ltl_formula()
:
f.is_in_nenoform() and f.is_ltl_formula()
g.is_ltl_formula()
Similarly, is_syntactic_stutter_invariant()
tells whether the structure of the formula guaranties it to be stutter invariant. For LTL formula, this means the X
operator should not be used. For PSL formula, this function capture all formulas built using the siPSL grammar.
f.is_syntactic_stutter_invariant()
spot.formula('{a[*];b}<>->c').is_syntactic_stutter_invariant()
spot.formula('{a[+];b[*]}<>->d').is_syntactic_stutter_invariant()
spot.relabel
renames the atomic propositions that occur in a formula, using either letters, or numbered propositions:
gf = spot.formula('(GF_foo_) && "a > b" && "proc[2]@init"'); gf
spot.relabel(gf, spot.Abc)
spot.relabel(gf, spot.Pnn)
The AST of any formula can be displayed with show_ast()
. Despite the name, this is not a tree but a DAG, because identical subtrees are merged. Binary operators have their left and right operands denoted with L
and R
, while non-commutative n-ary operators have their operands numbered.
print(g); g.show_ast()
Any formula can also be classified in the temporal hierarchy of Manna & Pnueli
g.show_mp_hierarchy()
spot.mp_class(g, 'v')
f = spot.formula('F(a & X(!a & b))'); f
Etessami's rule for removing X (valid only in stutter-invariant formulas)
spot.remove_x(f)
Removing abbreviated operators
f = spot.formula("G(a xor b) -> F(a <-> b)")
spot.unabbreviate(f, "GF^")
spot.unabbreviate(f, "GF^ei")
Nesting level of operators
f = spot.formula('F(b & X(a U b U ((a W Fb) | (c U d))))')
print("U", spot.nesting_depth(f, spot.op_U))
print("F", spot.nesting_depth(f, spot.op_F))
# These following two are syntactic sugar for the above two
print("U", spot.nesting_depth(f, "U"))
print("F", spot.nesting_depth(f, "F"))
# If you want to consider "U" and "F" are a similar type of
# operator, you can count both with
print("FU", spot.nesting_depth(f, "FU"))
Collecting the set of atomic propositions used by a formula:
ap = spot.atomic_prop_collect(f)
print(repr(ap)) # print as an atomic_prop_set object
print(ap) # print as a string
display(ap) # LaTeX-style, for notebooks
Converting to Suffix Operator Normal Form:
f = spot.formula('G({x*} []-> Fa)')
display(f)
# In addition to the formula, returns a list of newly introduced APs
f, aps = spot.suffix_operator_normal_form(f, 'p')
display(f)
display(aps)