import spot
from spot.jupyter import display_inline
spot.setup(show_default='.vtnA')
TL;DR Model checking a system $M$ against a specification $\varphi$ amounts to check whether $\mathscr{L}(M\otimes A)=\emptyset$, where $A$ is an automaton for $\lnot\varphi$. If we have some extra knowledge $K$ about $M$, we can replace the previous check by $\mathscr{L}(M\otimes B)=\emptyset$ where $B$ is an automaton simpler than $A$, but that has been built from $A$ and $K$.
Assuming A
is the the automaton for $\lnot\varphi$, and that K
is some apriori knowledge about the system to check, this combines A
and K
into a bounded automaton (Ab
), whose labels can then be simplified (Aminato
). The resulting automaton can be further minimized. The whole process reduces both the size and the strength of the automaton.
A = spot.translate('F(a & c) | G(Fb & F!b)')
K = 'FG(b) & G(c)'
Ab = spot.update_bounds_given(A, K)
Aminato = spot.bounds_simplify(Ab)
Asimpl = Aminato.postprocess('small')
display_inline(A, Ab, Aminato, Asimpl)
This demonstrate the stutterize_given(A, [K1, K2,...], type)
function that attempts to build a stutter-invariant automaton. It takes an automaton A
to simplify, a list of knowledges [K1, K2, ...]
that can be used for simplification, and a type
of simplification (True
for the relax variant, and False
for the retrict variant.) It returns a stutter-invariant automaton if it manages to build one (property prop_stutter_invariant()
will be set on the result in this case), or the original automaton otherwise.
A = spot.translate('XFa'); K = spot.translate('!a', 'Buchi')
sirelax = spot.stutterize_given(A, [K], True).postprocess('small')
sirestrict = spot.stutterize_given(A, [K], False).postprocess('small')
display_inline(A, K, sirestrict, sirelax, per_row=2)
This is probably one of the very first example we worked with, but it does not show as much as the one we kept for Figure 3.
aut1 = spot.translate('a | G(Fc & F!q)')
aut2 = spot.update_bounds_given(aut1, 'G(q)')
aut3 = spot.bounds_simplify(aut2)
display_inline(aut1, aut2, aut3, aut3.postprocess())
The following example shows how multiple knowledge can be accumulated in the bounded automaton.
aut1 = spot.translate('a U (b U c)')
aut2 = spot.update_bounds_given(aut1, 'G(b -> Xc)')
aut3 = spot.update_bounds_given(aut2, '!a')
aut4 = spot.bounds_simplify(aut3)
display_inline(aut1, aut2, aut3, aut4, aut4.postprocess(), show='.vt')
The following example also accumulates some (trivial) knowledge. It builds an automaton that is unfortunately stutter-sensitive because of the relaxed initial transition. If that transition was restricted to p0&p1
, the automaton would be stutter-insensitive.
aut1 = spot.translate('F(!p0 | X!p1)')
aut2 = spot.update_bounds_given(aut1, 'p0')
aut3 = spot.update_bounds_given(aut2, 'p1')
aut4 = spot.bounds_simplify(aut3)
display_inline(aut1, aut2, aut3, aut4)
Passing this result through sutterize_given
and then postprocess()
achieves the desired reduction.
sg = spot.stutterize_given(aut1, [spot.translate("p0"), spot.translate("p1")])
display_inline(sg, sg.postprocess())