Several typos
* HACKING: Missing "to", extraneous 's'. * spot/misc/timer.hh: Extraneous space. * spot/twa/acc.hh: Extraneous 's', typos. * spot/twaalgos/genem.hh: Typo. * spot/twaalgos/sccinfo.cc: Fix indentation. * spot/twaalgos/sccinfo.hh: Missing 's'. * tests/python/acc_cond.ipynb: Extraneous 'e', missing comma. * tests/python/decompose.ipynb: Extraneous 't'. * tests/python/ltsmin-dve.ipynb: Extraneous verb.
%% Cell type:code id: tags: | ||
``` python | ||
from IPython.display import display | ||
import spot | ||
spot.setup(show_default='.bans') | ||
``` | ||
%% Cell type:markdown id: tags: | ||
This notebook demonstrates how to use the `decompose_scc()` function to split an automaton in up to three automata capturing different behaviors. This is based on the paper [Strength-based decomposition of the property Büchi automaton for faster model checking](https://www.lrde.epita.fr/~adl/dl/adl/renault.13.tacas.pdf) (TACAS'13). | ||
This page uses the Python bindings, but the same decompositions can be performed from the shell using [`autfilt`](https://spot.lrde.epita.fr/autfilt.html) and its `--decompose-scc` option. | ||
# Basics | ||
Let's define the following strengths of accepting SCCs: | ||
- an accepting SCC is **inherently weak** if it does not contain any rejecting cycle | ||
- an accepting SCC is **inherently terminal** if it is *inherently weak* and complete (i.e. from any state, you can stay in the SCC by reading any word) | ||
- an accepting SCC is **strictly inherently weak** if it is *inherently weak* and not complete (in other words: *weak* but not *terminal*) | ||
- an accepting SCC is **strong** if it is not inherently weak. | ||
The strengths **strong**, **stricly inherently weak**, and **inherently terminal** define a partition of all accepting SCCs. The following Büchi automaton has 4 SCCs, and its 3 accepting SCCs show an example of each strength. | ||
Note: the reason we use the word *inherently* is that the *weak* and *terminal* properties are usually defined syntactically: an accepting SCC would be weak if all its transitions belong to the same acceptance sets. This syntactic criterion is a sufficient condition for an accepting SCC to not have any rejecting cycle, but it is not necessary. Hence a *weak* SCC is *inherently weak*; but while an *inherently weak* SCC is not necessarily *weak*, it can be modified to be *weak* without alterning the langage. | ||
%% Cell type:code id: tags: | ||
``` python | ||
aut = spot.translate('(Ga -> Gb) W c') | ||
aut | ||
``` | ||
%% Output | ||
<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd3d85c40f0> > | ||
%% Cell type:markdown id: tags: | ||
The `decompose_strength()` function takes an automaton, and a string specifying which strength to preserve. | ||
The letters used for this specification are as follows: | ||
- `t`: (inherently) terminal | ||
- `w`: (strictly inherently) weak | ||
- `s`: strong | ||
For instance if we want to preserve only the **strictly inherently weak** part of this automaton, we should get only the SCC with the self-loop on $b$, and the SCC above it so that we can reach it. However the SCC above is not stricly weak, so it should not accept any word in the new automaton. | ||
%% Cell type:code id: tags: | ||
``` python | ||
spot.decompose_scc(aut, 'w') | ||
``` | ||
%% Output | ||
<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd3d85c40c0> > | ||
%% Cell type:markdown id: tags: | ||
Similarly, we can extract all the behaviors captured by the **inherently terminal** part of the automaton: | ||
%% Cell type:code id: tags: | ||
``` python | ||
spot.decompose_scc(aut, 't') | ||
``` | ||
%% Output | ||
<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd3d860a060> > | ||
%% Cell type:markdown id: tags: | ||
Here is the **strong** part: | ||
%% Cell type:code id: tags: | ||
``` python | ||
strong = spot.decompose_scc(aut, 's'); strong | ||
``` | ||
%% Output | ||
<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd3d85c4120> > | ||
%% Cell type:markdown id: tags: | ||
The union of these three automata recognize the same language as the original automaton. | ||
The application proposed in the aforementioned TACAS'13 paper is for parallelizing model checking. Instead of testing the emptiness of the product between `aut` and a system, one could test the emptiness **3** products in parallel: each with a sub-automaton of different strength. Model checking using weak and terminal automata can be done with much more simpler emptiness check procedures than needed for the general case. So in effect, we have isolated the "hard" (i.e. strong) part of the original automaton in a smaller automaton, and we only need to use a full-fledged emptiness check for this case. | ||
An additional bonus is that it is possible that the simplification algorithms will do a better job at simplifying the sub-automata than at simplifying the original `aut`. For instance here the `strong` automaton can be further simplified: | ||
%% Cell type:code id: tags: | ||
``` python | ||
strong.postprocess('small') | ||
``` | ||
%% Output | ||
<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd3d8571690> > | ||
%% Cell type:markdown id: tags: | ||
# Multi-strength extraction | ||
The string passed to `decompose_strength()` can include multiple letters to extract multiple strengths at once. | ||
%% Cell type:code id: tags: | ||
``` python | ||
for opt in ('sw', 'st', 'wt'): | ||
a = spot.decompose_scc(aut, opt) | ||
a.set_name("option: " + opt) | ||
display(a) | ||
``` | ||
%% Output | ||
%% Cell type:markdown id: tags: | ||
# Generalized acceptance | ||
There is nothing that prevents the above decomposition to work with other types of acceptance. | ||
## Rabin | ||
The following Rabin automaton was generated with | ||
ltldo -f '(Ga -> Gb) W c' 'ltl2dstar --ltl2nba=spin:ltl2tgba@-Ds' -H | autfilt -H --merge-transitions | ||
(The `autfilt -H --merge-transitions` pass is just here to reduce the size of the file and make the automaton more readable.) | ||
%% Cell type:code id: tags: | ||
``` python | ||
aut = spot.automaton(""" | ||
HOA: v1 | ||
States: 9 | ||
Start: 2 | ||
AP: 3 "a" "b" "c" | ||
acc-name: Rabin 2 | ||
Acceptance: 4 (Fin(0) & Inf(1)) | (Fin(2) & Inf(3)) | ||
properties: trans-labels explicit-labels state-acc complete | ||
properties: deterministic | ||
--BODY-- | ||
State: 0 {2} | ||
[0&!2] 0 | ||
[0&2] 1 | ||
[!0&!2] 5 | ||
[!0&2] 6 | ||
State: 1 {2} | ||
[0] 1 | ||
[!0] 6 | ||
State: 2 {2} | ||
[0&!1&!2] 3 | ||
[0&1&!2] 4 | ||
[!0&!2] 5 | ||
[2] 6 | ||
State: 3 {1 2} | ||
[0&!2] 0 | ||
[0&2] 1 | ||
[!0&!2] 5 | ||
[!0&2] 6 | ||
State: 4 {1 2} | ||
[0&!1&!2] 0 | ||
[0&!1&2] 1 | ||
[!0&!2] 5 | ||
[!0&2] 6 | ||
[0&1&!2] 7 | ||
[0&1&2] 8 | ||
State: 5 {1 2} | ||
[0&!1&!2] 0 | ||
[!0&!2] 5 | ||
[2] 6 | ||
[0&1&!2] 7 | ||
State: 6 {1 2} | ||
[t] 6 | ||
State: 7 {3} | ||
[0&!1&!2] 0 | ||
[0&!1&2] 1 | ||
[!0&!2] 5 | ||
[!0&2] 6 | ||
[0&1&!2] 7 | ||
[0&1&2] 8 | ||
State: 8 {3} | ||
[0&!1] 1 | ||
[!0] 6 | ||
[0&1] 8 | ||
--END-- | ||
""") | ||
aut | ||
``` | ||
%% Output | ||
<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd3d8571540> > | ||
%% Cell type:markdown id: tags: | ||
Let's decompose it into three strengths: | ||
%% Cell type:code id: tags: | ||
``` python | ||
for (name, opt) in (('terminal', 't'), ('strictly weak', 'w'), ('strong', 's')): | ||
a = spot.decompose_scc(aut, opt) | ||
a.set_name(name) | ||
display(a) | ||
``` | ||
%% Output | ||
%% Cell type:markdown id: tags: | ||
Note how the two weak automata (i.e., stricly weak and terminal) are now using a Büchi acceptance condition (because that is sufficient for weak automata) while the strong automaton inherited the original acceptance condition. | ||
When extracting multiple strengths and one of the strength is **strong**, we preserve the original acceptance. For instance extracting **strong** and **inherently terminal** gives the following automaton, where only **stricly inherently weak** SCCs have become rejecting. | ||
%% Cell type:code id: tags: | ||
``` python | ||
spot.decompose_scc(aut, "st") | ||
``` | ||
%% Output | ||
<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd3d8571a80> > | ||
%% Cell type:markdown id: tags: | ||
The weak automata seem to be good candidates for further simplification. Let's add a call to `postprocess()` to our decomposition loop, trying to preserve the determinism and state-based acceptance of the original automaton. | ||
%% Cell type:code id: tags: | ||
``` python | ||
for (name, opt) in (('inherently terminal', 't'), ('strictly inherently weak', 'w'), ('strong', 's')): | ||
a = spot.decompose_scc(aut, opt).postprocess('deterministic', 'SBAcc') | ||
a.set_name(name) | ||
display(a) | ||
``` | ||
%% Output | ||
%% Cell type:markdown id: tags: | ||
## Streett | ||
Since this notebook also serves as a test suite, let's try a Streett automaton. This one was generated with | ||
ltldo -f '(Ga -> Gb) W c' 'ltl2dstar --automata=streett --ltl2nba=spin:ltl2tgba@-Ds' -H | | ||
autfilt -H --merge-transitions | ||
%% Cell type:code id: tags: | ||
``` python | ||
aut = spot.automaton(""" | ||
HOA: v1 | ||
States: 8 | ||
Start: 7 | ||
AP: 3 "a" "b" "c" | ||
acc-name: Streett 2 | ||
Acceptance: 4 (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)) | ||
properties: trans-labels explicit-labels state-acc complete | ||
properties: deterministic | ||
--BODY-- | ||
State: 0 {2} | ||
[0&1] 0 | ||
[0&!1] 3 | ||
[!0] 4 | ||
State: 1 {2} | ||
[0&1&2] 0 | ||
[0&1&!2] 1 | ||
[0&!1&!2] 2 | ||
[0&!1&2] 3 | ||
[!0&2] 4 | ||
[!0&!2] 7 | ||
State: 2 {2} | ||
[0&1&!2] 1 | ||
[0&!1&!2] 2 | ||
[0&2] 3 | ||
[!0&2] 4 | ||
[!0&!2] 7 | ||
State: 3 {0 3} | ||
[0] 3 | ||
[!0] 4 | ||
State: 4 {1 3} | ||
[t] 4 | ||
State: 5 {3} | ||
[0&!1] 3 | ||
[!0] 4 | ||
[0&1] 5 | ||
State: 6 {3} | ||
[0&!1&!2] 2 | ||
[0&!1&2] 3 | ||
[!0&2] 4 | ||
[0&1&2] 5 | ||
[0&1&!2] 6 | ||
[!0&!2] 7 | ||
State: 7 {3} | ||
[0&!1&!2] 2 | ||
[2] 4 | ||
[0&1&!2] 6 | ||
[!0&!2] 7 | ||
--END-- | ||
""") | ||
aut | ||
``` | ||
%% Output | ||