restructure the complementation code

The previous code was sometime doing the work of remove_fin() in
addition to complementing the acceptance conditions.  This separate
the two operations clearly.  Also the specialized code for
complementing weak automata is now a specialized code for remove_fin()
on weak automata.

* src/twaalgos/dtgbacomp.hh, src/twaalgos/dtgbacomp.cc: Rename as ...
* src/twaalgos/complement.hh, src/twaalgos/complement.cc: ... these.
* src/twaalgos/Makefile.am: Adjust.
* src/twaalgos/complement.hh (dtgba_complement): Rename as ...
(dtwa_complement): ... this, and restrict the purpose to completion
and accetance complementation.  Further acceptance simplification
can be done with remove_fin() and to_generalized_buchi().
* src/twaalgos/remfin.cc (remove_fin): Specialize handling of weak
automata using the code that was originally in dtgba_complement().
Also mark the output as state-based when the input has to Inf.
* src/twaalgos/postproc.cc, src/twaalgos/postproc.hh: Make sure
scc_filter is always called after to_generalized_buchi().
* bench/stutter/stutter_invariance_randomgraph.cc,
src/bin/ltlcross.cc, src/tests/ikwiad.cc, src/twaalgos/minimize.cc,
src/twaalgos/powerset.cc, src/twaalgos/stutter.cc: Adjust usage.
* src/tests/dstar.test, src/tests/ltl2dstar4.test,
src/tests/remfin.test: Adjust expected outputs.
* wrap/python/spot_impl.i: Export dtwa_complement().
This commit is contained in:
Alexandre Duret-Lutz 2015-10-13 19:30:26 +02:00
parent fb642c6df5
commit 06d3bc67ea
18 changed files with 336 additions and 448 deletions

12
NEWS
View file

@ -1,8 +1,18 @@
New in spot 1.99.4a (not yet released) New in spot 1.99.4a (not yet released)
* Rename dtgba_complement() as dtwa_complement(), rename the header
as complement.hh, and restrict the purpose of this function to
just complete the automaton and complement its acceptance
condition. Any further acceptance condition transformation
can be done with to_generalized_buchi() or remove_fin().
* The remove_fin() has learnt how to better deal with automata that
are declared as weak. This code was previously in
dtgba_complement().
Python: Python:
* Add bindings for complete(). * Add bindings for complete() and dtwa_complement()
* Formulas now have a custom __format__ function. See * Formulas now have a custom __format__ function. See
https://spot.lrde.epita.fr/tut01.html for examples. https://spot.lrde.epita.fr/tut01.html for examples.

View file

@ -19,7 +19,8 @@
#include "misc/timer.hh" #include "misc/timer.hh"
#include "tl/apcollect.hh" #include "tl/apcollect.hh"
#include "twaalgos/dtgbacomp.hh" #include "twaalgos/complement.hh"
#include "twaalgos/remfin.hh"
#include "twaalgos/randomgraph.hh" #include "twaalgos/randomgraph.hh"
#include "twaalgos/dot.hh" #include "twaalgos/dot.hh"
#include "twaalgos/product.hh" #include "twaalgos/product.hh"
@ -80,7 +81,7 @@ main(int argc, char** argv)
true); true);
} }
while (a->is_empty()); while (a->is_empty());
auto na = spot::dtgba_complement(a); auto na = spot::remove_fin(spot::dtwa_complement(a));
std::cout << d << ',' << props_n << ',' << seed; std::cout << d << ',' << props_n << ',' << seed;
stats.print(a); stats.print(a);

View file

@ -53,7 +53,7 @@
#include "twaalgos/isweakscc.hh" #include "twaalgos/isweakscc.hh"
#include "twaalgos/reducerun.hh" #include "twaalgos/reducerun.hh"
#include "twaalgos/word.hh" #include "twaalgos/word.hh"
#include "twaalgos/dtgbacomp.hh" #include "twaalgos/complement.hh"
#include "twaalgos/cleanacc.hh" #include "twaalgos/cleanacc.hh"
#include "misc/formater.hh" #include "misc/formater.hh"
#include "twaalgos/stats.hh" #include "twaalgos/stats.hh"
@ -1016,7 +1016,7 @@ namespace
if (!no_complement && pos[n] if (!no_complement && pos[n]
&& ((want_stats && !(*pstats)[n].nondeterministic) && ((want_stats && !(*pstats)[n].nondeterministic)
|| (!want_stats && is_deterministic(pos[n])))) || (!want_stats && is_deterministic(pos[n]))))
comp_pos[n] = dtgba_complement(pos[n]); comp_pos[n] = dtwa_complement(pos[n]);
} }
// ---------- Negative Formula ---------- // ---------- Negative Formula ----------
@ -1056,7 +1056,7 @@ namespace
if (!no_complement && neg[n] if (!no_complement && neg[n]
&& ((want_stats && !(*nstats)[n].nondeterministic) && ((want_stats && !(*nstats)[n].nondeterministic)
|| (!want_stats && is_deterministic(neg[n])))) || (!want_stats && is_deterministic(neg[n]))))
comp_neg[n] = dtgba_complement(neg[n]); comp_neg[n] = dtwa_complement(neg[n]);
} }
} }

View file

@ -244,7 +244,7 @@ digraph G {
node [shape="circle"] node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0", peripheries=2]
0 -> 1 [label="!a & !b"] 0 -> 1 [label="!a & !b"]
0 -> 2 [label="a & !b"] 0 -> 2 [label="a & !b"]
1 [label="1", peripheries=2] 1 [label="1", peripheries=2]

View file

@ -60,7 +60,8 @@
#include "twaalgos/simulation.hh" #include "twaalgos/simulation.hh"
#include "twaalgos/compsusp.hh" #include "twaalgos/compsusp.hh"
#include "twaalgos/powerset.hh" #include "twaalgos/powerset.hh"
#include "twaalgos/dtgbacomp.hh" #include "twaalgos/complement.hh"
#include "twaalgos/remfin.hh"
#include "twaalgos/complete.hh" #include "twaalgos/complete.hh"
#include "twaalgos/dtbasat.hh" #include "twaalgos/dtbasat.hh"
#include "twaalgos/dtgbasat.hh" #include "twaalgos/dtgbasat.hh"
@ -338,7 +339,7 @@ checked_main(int argc, char** argv)
bool opt_determinize = false; bool opt_determinize = false;
unsigned opt_determinize_threshold = 0; unsigned opt_determinize_threshold = 0;
unsigned opt_o_threshold = 0; unsigned opt_o_threshold = 0;
bool opt_dtgbacomp = false; bool opt_dtwacomp = false;
bool reject_bigger = false; bool reject_bigger = false;
bool opt_monitor = false; bool opt_monitor = false;
bool containment = false; bool containment = false;
@ -411,7 +412,7 @@ checked_main(int argc, char** argv)
} }
else if (!strcmp(argv[formula_index], "-DC")) else if (!strcmp(argv[formula_index], "-DC"))
{ {
opt_dtgbacomp = true; opt_dtwacomp = true;
} }
else if (!strncmp(argv[formula_index], "-DS", 3) else if (!strncmp(argv[formula_index], "-DS", 3)
|| !strncmp(argv[formula_index], "-DT", 3)) || !strncmp(argv[formula_index], "-DT", 3))
@ -1203,14 +1204,14 @@ checked_main(int argc, char** argv)
a = satminimized; a = satminimized;
} }
if (opt_dtgbacomp) if (opt_dtwacomp)
{ {
tm.start("DTGBA complement"); tm.start("DTωA complement");
a = dtgba_complement(ensure_digraph(a)); a = remove_fin(dtwa_complement(ensure_digraph(a)));
tm.stop("DTGBA complement"); tm.stop("DTωA complement");
} }
if (opt_determinize || opt_dtgbacomp || opt_dtbasat >= 0 if (opt_determinize || opt_dtwacomp || opt_dtbasat >= 0
|| opt_dtgbasat >= 0) || opt_dtgbasat >= 0)
{ {
if (scc_filter && (reduction_dir_sim || reduction_rev_sim)) if (scc_filter && (reduction_dir_sim || reduction_rev_sim))

View file

@ -41,13 +41,13 @@ $ltlfilt -f '(GFa -> GFb) & (GFc -> GFd)' -l |
ltl2dstar --ltl2nba=spin:$ltl2tgba@-s $STR - - | ltl2dstar --ltl2nba=spin:$ltl2tgba@-s $STR - - |
$autfilt --tgba --stats '%S %E %A %s %e %t %a %d' | $autfilt --tgba --stats '%S %E %A %s %e %t %a %d' |
tee out tee out
test "`cat out`" = '9 144 4 25 416 416 2 0' test "`cat out`" = '9 144 4 25 149 416 2 0'
$ltlfilt -f '(GFa -> GFb) & (GFc -> GFd)' -l | $ltlfilt -f '(GFa -> GFb) & (GFc -> GFd)' -l |
ltl2dstar --ltl2nba=spin:$ltl2tgba@-s $STR - - | ltl2dstar --ltl2nba=spin:$ltl2tgba@-s $STR - - |
SPOT_STREETT_CONV_MIN=1 $autfilt --tgba --stats '%S %E %A %s %e %t %a %d' | SPOT_STREETT_CONV_MIN=1 $autfilt --tgba --stats '%S %E %A %s %e %t %a %d' |
tee out tee out
test "`cat out`" = '9 144 4 25 482 482 2 0' test "`cat out`" = '9 144 4 25 218 482 2 0'
LTL2DSTAR="ltl2dstar $STR --ltl2nba=spin:$ltl2tgba@-s %L" LTL2DSTAR="ltl2dstar $STR --ltl2nba=spin:$ltl2tgba@-s %L"

View file

@ -218,20 +218,13 @@ Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc properties: trans-labels explicit-labels state-acc
--BODY-- --BODY--
State: 0 State: 0
[0&1] 0 [t] 0
[!0&!1] 0 [!0] 1
[!0&1] 0 [!1] 2
[0&!1] 0
[!0&!1] 1
[!0&1] 1
[!0&!1] 2
[0&!1] 2
State: 1 {0} State: 1 {0}
[!0&!1] 1 [!0] 1
[!0&1] 1
State: 2 {0} State: 2 {0}
[!0&!1] 2 [!1] 2
[0&!1] 2
--END-- --END--
HOA: v1 HOA: v1
States: 4 States: 4
@ -275,7 +268,7 @@ State: 2
[!1] 0 [!1] 0
[0&!1] 1 {0} [0&!1] 1 {0}
[!0&!1] 2 {0} [!0&!1] 2 {0}
[!0&!1] 3 {0} [!0&!1] 3
State: 3 State: 3
[!0&!1] 3 {0 1 4} [!0&!1] 3 {0 1 4}
--END-- --END--
@ -325,31 +318,30 @@ Acceptance: 2 Inf(1) | Inf(0)
properties: trans-labels explicit-labels state-acc properties: trans-labels explicit-labels state-acc
--BODY-- --BODY--
State: 0 State: 0
[!0] 6
[0] 0 [0] 0
[!0] 6
[0] 8 [0] 8
[0] 9 [0] 9
State: 1 {0 1} State: 1 {0 1}
[!0] 3 [t] 3
[0] 3
State: 2 {0 1} State: 2 {0 1}
[!0] 5
[0] 1 [0] 1
[!0] 5
State: 3 {0 1} State: 3 {0 1}
[!0] 6
[0] 0 [0] 0
[!0] 6
State: 4 {0 1} State: 4 {0 1}
[!0] 6
[0] 4 [0] 4
[!0] 6
State: 5 {0 1} State: 5 {0 1}
[!0] 7
[0] 3 [0] 3
[!0] 7
State: 6 State: 6
[!0] 6
[0] 0 [0] 0
State: 7 {1}
[!0] 6 [!0] 6
State: 7 {1}
[0] 4 [0] 4
[!0] 6
State: 8 State: 8
[0] 8 [0] 8
State: 9 {1} State: 9 {1}
@ -547,68 +539,61 @@ Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc properties: trans-labels explicit-labels state-acc
--BODY-- --BODY--
State: 0 State: 0
[0&1] 0 [t] 0
[!0&!1] 0 [!0] 1
[!0&1] 0 [!1] 2
[0&!1] 0
[!0&!1] 1
[!0&1] 1
[!0&!1] 2
[0&!1] 2
State: 1 {0} State: 1 {0}
[!0&!1] 1 [!0] 1
[!0&1] 1
State: 2 {0} State: 2 {0}
[!0&!1] 2 [!1] 2
[0&!1] 2
--END-- --END--
HOA: v1 HOA: v1
States: 4 States: 4
Start: 0 Start: 0
AP: 2 "a" "b" AP: 2 "a" "b"
acc-name: generalized-Buchi 2 acc-name: Buchi
Acceptance: 2 Inf(0)&Inf(1) Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels trans-acc properties: trans-labels explicit-labels trans-acc
--BODY-- --BODY--
State: 0 State: 0
[t] 0 {0 1} [t] 0 {0}
[0] 1 {0 1} [0] 1 {0}
[!0] 2 {0 1} [!0] 2 {0}
State: 1 State: 1
[1] 0 {1} [1] 0
[0&1] 1 {1} [0&1] 1
[!0&1] 2 {0 1} [!0&1] 2 {0}
State: 2 State: 2
[!1] 0 [!1] 0
[0&!1] 1 [0&!1] 1
[!0&!1] 2 [!0&!1] 2
[!0&!1] 3 [!0&!1] 3
State: 3 State: 3
[!0&!1] 3 {0 1} [!0&!1] 3 {0}
--END-- --END--
HOA: v1 HOA: v1
States: 4 States: 4
Start: 0 Start: 0
AP: 2 "a" "b" AP: 2 "a" "b"
acc-name: generalized-Buchi 2 acc-name: Buchi
Acceptance: 2 Inf(0)&Inf(1) Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels trans-acc properties: trans-labels explicit-labels trans-acc
--BODY-- --BODY--
State: 0 State: 0
[t] 0 {1} [t] 0
[0] 1 {1} [0] 1
[!0] 2 {0 1} [!0] 2 {0}
State: 1 State: 1
[1] 0 {1} [1] 0
[0&1] 1 {0 1} [0&1] 1 {0}
[!0&1] 2 {0 1} [!0&1] 2 {0}
State: 2 State: 2
[!1] 0 [!1] 0
[0&!1] 1 {0 1} [0&!1] 1 {0}
[!0&!1] 2 {0 1} [!0&!1] 2 {0}
[!0&!1] 3 {0 1} [!0&!1] 3
State: 3 State: 3
[!0&!1] 3 {0 1} [!0&!1] 3 {0}
--END-- --END--
HOA: v1 HOA: v1
States: 1 States: 1
@ -646,47 +631,42 @@ State: 0
[!0] 0 [!0] 0
[0] 1 [0] 1
State: 1 {0} State: 1 {0}
[!0] 1 [t] 1
[0] 1
--END-- --END--
HOA: v1 HOA: v1
States: 10 States: 9
Start: 2 Start: 2
AP: 1 "p1" AP: 1 "p1"
acc-name: Buchi acc-name: Buchi
Acceptance: 1 Inf(0) Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc properties: trans-labels explicit-labels trans-acc
--BODY-- --BODY--
State: 0 State: 0
[!0] 6
[0] 0 [0] 0
[!0] 6
[0] 8 [0] 8
[0] 9 State: 1
State: 1 {0} [t] 3
[!0] 3 State: 2
[0] 3
State: 2 {0}
[!0] 5
[0] 1 [0] 1
State: 3 {0} [!0] 5
[!0] 6 State: 3
[0] 0 [0] 0
State: 4 {0}
[!0] 6 [!0] 6
[0] 4 State: 4
State: 5 {0} [0] 4 {0}
[!0] 7 [!0] 6
State: 5
[0] 3 [0] 3
[!0] 7
State: 6 State: 6
[!0] 6
[0] 0 [0] 0
State: 7 {0}
[!0] 6 [!0] 6
[0] 4 State: 7
[0] 4 {0}
[!0] 6
State: 8 State: 8
[0] 8 [0] 8 {0}
State: 9 {0}
[0] 9
--END-- --END--
HOA: v1 HOA: v1
States: 15 States: 15
@ -694,83 +674,75 @@ Start: 13
AP: 2 "p1" "p0" AP: 2 "p1" "p0"
acc-name: Buchi acc-name: Buchi
Acceptance: 1 Inf(0) Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc properties: trans-labels explicit-labels trans-acc
--BODY-- --BODY--
State: 0 {0} State: 0
[0&1] 0 {0}
[!0&1] 1 {0}
[0&!1] 11 {0}
[!0&!1] 12 [!0&!1] 12
[0&!1] 11 State: 1
[!0&1] 1 [0&1] 0 {0}
[0&1] 0 [!0&1] 1 {0}
State: 1 {0} [0&!1] 11 {0}
[!0&!1] 12 [!0&!1] 12
[0&!1] 11 State: 2
[!0&1] 1 [!0&1] 2 {0}
[0&1] 0
State: 2 {0}
[!0&!1] 10
[0&!1] 11
[!0&1] 2
[0&1] 9 [0&1] 9
State: 3 {0} [!0&!1] 10 {0}
[0&!1] 11 {0}
State: 3
[!0&1] 1 {0}
[0&1] 3 {0}
[0&!1] 11 {0}
[!0&!1] 12 [!0&!1] 12
[0&!1] 11 State: 4
[!0&1] 1 [!0&1] 4 {0}
[0&1] 3 [0&1] 7 {0}
State: 4 {0} [!1] 12
[!0&!1] 12 State: 5
[0&!1] 12 [!0&1] 5 {0}
[!0&1] 4
[0&1] 7
State: 5 {0}
[!0&!1] 10
[0&!1] 12
[!0&1] 5
[0&1] 8 [0&1] 8
State: 6 {0} [!0&!1] 10 {0}
[!0&!1] 12
[0&!1] 11
[!0&1] 4
[0&1] 6
State: 7 {0}
[!0&!1] 12
[0&!1] 12 [0&!1] 12
[!0&1] 4 State: 6
[0&1] 7 [!0&1] 4 {0}
[0&1] 6 {0}
[0&!1] 11 {0}
[!0&!1] 12
State: 7
[!0&1] 4 {0}
[0&1] 7 {0}
[!1] 12
State: 8 State: 8
[!0&!1] 12 [1] 8
[0&!1] 12 [!1] 12
[!0&1] 8 [1] 14
[0&1] 8
[!0&1] 14
[0&1] 14
State: 9 State: 9
[!0&!1] 12
[0&!1] 11
[!0&1] 1 [!0&1] 1
[0&1] 3 [0&1] 3
State: 10 {0}
[!0&!1] 10
[0&!1] 12
[!0&1] 5
[0&1] 8
State: 11 {0}
[!0&!1] 12
[0&!1] 11 [0&!1] 11
[!0&!1] 12
State: 10
[!0&1] 5 {0}
[0&1] 8
[!0&!1] 10 {0}
[0&!1] 12
State: 11
[0&1] 6 {0}
[!0&1] 8 [!0&1] 8
[0&1] 6 [0&!1] 11 {0}
[!0&!1] 12
State: 12 State: 12
[!0&!1] 12 [1] 8
[0&!1] 12 [!1] 12
[!0&1] 8
[0&1] 8
State: 13 State: 13
[!0&!1] 10
[0&!1] 11
[!0&1] 2 [!0&1] 2
[0&1] 3 [0&1] 3
State: 14 {0} [!0&!1] 10
[!0&1] 14 [0&!1] 11
[0&1] 14 State: 14
[1] 14 {0}
--END-- --END--
HOA: v1 HOA: v1
States: 4 States: 4
@ -797,44 +769,26 @@ State: 3 {0}
[!0&1] 3 [!0&1] 3
--END-- --END--
HOA: v1 HOA: v1
States: 6 States: 5
Start: 5 Start: 4
AP: 2 "p0" "p1" AP: 2 "p0" "p1"
acc-name: Buchi acc-name: Buchi
Acceptance: 1 Inf(0) Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc complete properties: trans-labels explicit-labels trans-acc deterministic
properties: deterministic
--BODY-- --BODY--
State: 0 State: 0
[!0&!1] 0 [0] 1
[0&!1] 0
[!0&1] 0
[0&1] 0
State: 1 State: 1
[!0&!1] 0 [t] 1 {0}
[0&!1] 2 State: 2
[!0&1] 0 [!0&1] 0
[0&1] 2 [0] 1 {0}
State: 2 {0} [!0&!1] 2 {0}
[!0&!1] 2 State: 3
[0&!1] 2 [1] 0
[!0&1] 2 [!1] 2
[0&1] 2
State: 3 {0}
[!0&!1] 3
[0&!1] 2
[!0&1] 1
[0&1] 2
State: 4 State: 4
[!0&!1] 3 [t] 3
[0&!1] 3
[!0&1] 1
[0&1] 1
State: 5
[!0&!1] 4
[0&!1] 4
[!0&1] 4
[0&1] 4
--END-- --END--
HOA: v1 HOA: v1
States: 5 States: 5
@ -845,24 +799,18 @@ Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc properties: trans-labels explicit-labels state-acc
--BODY-- --BODY--
State: 0 State: 0
[!0&!1] 2
[0&!1] 0 [0&!1] 0
[!0&1] 2 [!0] 2
[0&1] 3 [0&1] 3
State: 1 State: 1
[!0&!1] 2
[0&!1] 1 [0&!1] 1
[!0&1] 2 [!0 | 1] 2
[0&1] 2
State: 2 {0} State: 2 {0}
[!0&!1] 2
[0&!1] 0 [0&!1] 0
[!0&1] 2 [!0 | 1] 2
[0&1] 2
State: 3 State: 3
[!0&!1] 2
[0&!1] 0 [0&!1] 0
[!0&1] 2 [!0] 2
[0&1] 3 [0&1] 3
[0&1] 4 [0&1] 4
State: 4 {0} State: 4 {0}

View file

@ -33,10 +33,10 @@ twaalgos_HEADERS = \
canonicalize.hh \ canonicalize.hh \
cleanacc.hh \ cleanacc.hh \
complete.hh \ complete.hh \
complement.hh \
compsusp.hh \ compsusp.hh \
copy.hh \ copy.hh \
cycles.hh \ cycles.hh \
dtgbacomp.hh \
degen.hh \ degen.hh \
dot.hh \ dot.hh \
dtbasat.hh \ dtbasat.hh \
@ -90,10 +90,10 @@ libtwaalgos_la_SOURCES = \
canonicalize.cc \ canonicalize.cc \
cleanacc.cc \ cleanacc.cc \
complete.cc \ complete.cc \
complement.cc \
compsusp.cc \ compsusp.cc \
copy.cc \ copy.cc \
cycles.cc \ cycles.cc \
dtgbacomp.cc \
degen.cc \ degen.cc \
dot.cc \ dot.cc \
dtbasat.cc \ dtbasat.cc \

View file

@ -0,0 +1,35 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "complement.hh"
#include "sccinfo.hh"
#include "complete.hh"
#include "cleanacc.hh"
namespace spot
{
twa_graph_ptr
dtwa_complement(const const_twa_graph_ptr& aut)
{
// Simply complete the automaton, and complement its acceptance.
auto res = cleanup_acceptance_here(complete(aut));
res->set_acceptance(res->num_sets(), res->get_acceptance().complement());
return res;
}
}

View file

@ -23,13 +23,19 @@
namespace spot namespace spot
{ {
/// \brief Complement a deterministic TGBA /// \brief Complement a deterministic TωA
/// ///
/// The automaton \a aut should be deterministic. It does no need /// The automaton \a aut should be deterministic. It will be
/// to be complete. Acceptance can be transition-based, or /// completed if it isn't already. In these conditions,
/// state-based. Unless the input automaton is marked as weak (in /// complementing the automaton can be done by just complementing
/// which case the output will also be weak and deterministic) the /// the acceptance condition.
/// resulting automaton is very unlikely to be deterministic. ///
/// In particular, this implies that an input that use
/// generalized Büchi will be output as generalized co-Büchi.
///
/// Functions like to_generalized_buchi() or remove_fin() are
/// frequently called after dtwa_complement() to obtain an easier
/// acceptance condition (maybe at the cost of loosing determinism.)
SPOT_API twa_graph_ptr SPOT_API twa_graph_ptr
dtgba_complement(const const_twa_graph_ptr& aut); dtwa_complement(const const_twa_graph_ptr& aut);
} }

View file

@ -1,187 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dtgbacomp.hh"
#include "sccinfo.hh"
#include "complete.hh"
#include "cleanacc.hh"
namespace spot
{
namespace
{
static twa_graph_ptr
dtgba_complement_nonweak(const const_twa_graph_ptr& aut)
{
// Clone the original automaton.
auto res = make_twa_graph(aut,
{ false, // state based
false, // inherently_weak
false, // deterministic
true, // stutter inv.
});
// Copy the old acceptance condition before we replace it.
acc_cond oldacc = aut->acc(); // Copy it!
// We will modify res in place, and the resulting
// automaton will only have one acceptance set.
// This changes aut->acc();
res->set_buchi();
// The resulting automaton is weak.
res->prop_inherently_weak();
res->prop_state_based_acc();
unsigned num_sets = oldacc.num_sets();
unsigned n = res->num_states();
// We will duplicate the automaton as many times as we have
// acceptance sets, and we need one extra sink state.
res->new_states(num_sets * n + 1);
unsigned sink = res->num_states() - 1;
// The sink state has an accepting self-loop.
res->new_acc_edge(sink, sink, bddtrue);
for (unsigned src = 0; src < n; ++src)
{
// Keep track of all conditions on edge leaving state
// SRC, so we can complete it.
bdd missingcond = bddtrue;
for (auto& t: res->out(src))
{
if (t.dst >= n) // Ignore edges we added.
break;
missingcond -= t.cond;
acc_cond::mark_t curacc = t.acc;
// The original edge must not accept anymore.
t.acc = 0U;
// Edge that were fully accepting are never cloned.
if (oldacc.accepting(curacc))
continue;
// Save t.cond and t.dst as the reference to t
// is invalided by calls to new_edge().
unsigned dst = t.dst;
bdd cond = t.cond;
// Iterate over all the acceptance conditions in 'curacc',
// an duplicate it for each clone for which it does not
// belong to the acceptance set.
unsigned add = 0;
for (unsigned set = 0; set < num_sets; ++set)
{
add += n;
if (!oldacc.has(curacc, set))
{
// Clone the edge
res->new_acc_edge(src + add, dst + add, cond);
assert(dst + add < sink);
// Using `t' is disallowed from now on as it is a
// reference to a edge that may have been
// reallocated.
// At least one edge per cycle should have a
// nondeterministic copy from the original clone.
// We use state numbers to select it, as any cycle
// is guaranteed to have at least one edge
// with dst <= src. FIXME: Computing a feedback
// arc set would be better.
if (dst <= src)
res->new_edge(src, dst + add, cond);
}
}
assert(add == num_sets * n);
}
// Complete the original automaton.
if (missingcond != bddfalse)
res->new_edge(src, sink, missingcond);
}
res->merge_edges();
res->purge_dead_states();
return res;
}
static twa_graph_ptr
dtgba_complement_weak(const const_twa_graph_ptr& aut)
{
// Clone the original automaton.
auto res = make_twa_graph(aut,
{ true, // state based
true, // inherently weak
true, // determinisitic
true, // stutter inv.
});
scc_info si(res);
// We will modify res in place, and the resulting
// automaton will only have one acceptance set.
acc_cond::mark_t all_acc = res->set_buchi();
res->prop_state_based_acc();
unsigned sink = res->num_states();
for (unsigned src = 0; src < sink; ++src)
{
acc_cond::mark_t acc = 0U;
unsigned scc = si.scc_of(src);
if (si.is_rejecting_scc(scc) && !si.is_trivial(scc))
acc = all_acc;
// Keep track of all conditions on edge leaving state
// SRC, so we can complete it.
bdd missingcond = bddtrue;
for (auto& t: res->out(src))
{
missingcond -= t.cond;
t.acc = acc;
}
// Complete the original automaton.
if (missingcond != bddfalse)
{
if (res->num_states() == sink)
{
res->new_state();
res->new_acc_edge(sink, sink, bddtrue);
}
res->new_edge(src, sink, missingcond);
}
}
//res->merge_edges();
return res;
}
}
twa_graph_ptr dtgba_complement(const const_twa_graph_ptr& aut)
{
if (aut->acc().is_generalized_buchi())
{
if (aut->is_inherently_weak())
return dtgba_complement_weak(aut);
else
return dtgba_complement_nonweak(aut);
}
else
{
// Simply complete the automaton, and complement its
// acceptance.
auto res = cleanup_acceptance_here(complete(aut));
res->set_acceptance(res->num_sets(),
res->get_acceptance().complement());
return res;
}
}
}

View file

@ -44,7 +44,8 @@
#include "twaalgos/ltl2tgba_fm.hh" #include "twaalgos/ltl2tgba_fm.hh"
#include "twaalgos/bfssteps.hh" #include "twaalgos/bfssteps.hh"
#include "twaalgos/isdet.hh" #include "twaalgos/isdet.hh"
#include "twaalgos/dtgbacomp.hh" #include "twaalgos/complement.hh"
#include "twaalgos/remfin.hh"
namespace spot namespace spot
{ {
@ -632,7 +633,7 @@ namespace spot
{ {
// If the automaton is deterministic, complementing is // If the automaton is deterministic, complementing is
// easy. // easy.
aut_neg_f = dtgba_complement(aut_f); aut_neg_f = remove_fin(dtwa_complement(aut_f));
} }
else else
{ {
@ -654,7 +655,7 @@ namespace spot
{ {
// Complement the minimized WDBA. // Complement the minimized WDBA.
assert(min_aut_f->is_inherently_weak()); assert(min_aut_f->is_inherently_weak());
auto neg_min_aut_f = dtgba_complement(min_aut_f); auto neg_min_aut_f = remove_fin(dtwa_complement(min_aut_f));
if (product(aut_f, neg_min_aut_f)->is_empty()) if (product(aut_f, neg_min_aut_f)->is_empty())
// Finally, we are now sure that it was safe // Finally, we are now sure that it was safe
// to minimize the automaton. // to minimize the automaton.

View file

@ -139,6 +139,23 @@ namespace spot
return do_sba_simul(d, ba_simul_); return do_sba_simul(d, ba_simul_);
} }
twa_graph_ptr
postprocessor::do_scc_filter(const twa_graph_ptr& a, bool arg)
{
if (scc_filter_ == 0)
return a;
if (state_based_ && a->has_state_based_acc())
return scc_filter_states(a);
else
return scc_filter(a, arg);
}
twa_graph_ptr
postprocessor::do_scc_filter(const twa_graph_ptr& a)
{
return do_scc_filter(a, scc_filter_ > 1);
}
#define PREF_ (pref_ & (Small | Deterministic)) #define PREF_ (pref_ & (Small | Deterministic))
#define COMP_ (pref_ & Complete) #define COMP_ (pref_ & Complete)
#define SBACC_ (pref_ & SBAcc) #define SBACC_ (pref_ & SBAcc)
@ -146,22 +163,6 @@ namespace spot
twa_graph_ptr twa_graph_ptr
postprocessor::run(twa_graph_ptr a, formula f) postprocessor::run(twa_graph_ptr a, formula f)
{ {
if (type_ != Generic && !a->acc().is_generalized_buchi())
a = to_generalized_buchi(a);
if (PREF_ == Any && level_ == Low)
if (type_ == Generic
|| type_ == TGBA
|| (type_ == BA && a->is_sba())
|| (type_ == Monitor && a->num_sets() == 0))
{
if (COMP_)
a = complete(a);
if (SBACC_)
a = sbacc(a);
return a;
}
if (simul_ < 0) if (simul_ < 0)
simul_ = (level_ == Low) ? 1 : 3; simul_ = (level_ == Low) ? 1 : 3;
if (ba_simul_ < 0) if (ba_simul_ < 0)
@ -171,6 +172,28 @@ namespace spot
if (type_ == BA || SBACC_) if (type_ == BA || SBACC_)
state_based_ = true; state_based_ = true;
bool tgb_used = false;
if (type_ != Generic && !a->acc().is_generalized_buchi())
{
a = to_generalized_buchi(a);
tgb_used = true;
}
if (PREF_ == Any && level_ == Low)
if (type_ == Generic
|| type_ == TGBA
|| (type_ == BA && a->is_sba())
|| (type_ == Monitor && a->num_sets() == 0))
{
if (tgb_used)
a = do_scc_filter(a);
if (COMP_)
a = complete(a);
if (SBACC_)
a = sbacc(a);
return a;
}
int original_acc = a->num_sets(); int original_acc = a->num_sets();
// Remove useless SCCs. // Remove useless SCCs.
@ -178,13 +201,8 @@ namespace spot
// Do not bother about acceptance conditions, they will be // Do not bother about acceptance conditions, they will be
// ignored. // ignored.
a = scc_filter_states(a); a = scc_filter_states(a);
else if (scc_filter_ > 0) else
{ a = do_scc_filter(a);
if (state_based_ && a->has_state_based_acc())
a = scc_filter_states(a);
else
a = scc_filter(a, scc_filter_ > 1);
}
if (type_ == Monitor) if (type_ == Monitor)
{ {
@ -380,7 +398,7 @@ namespace spot
in = dba; in = dba;
} }
const_twa_graph_ptr res = complete(in); twa_graph_ptr res = complete(in);
if (target_acc == 1) if (target_acc == 1)
{ {
if (sat_states_ != -1) if (sat_states_ != -1)
@ -408,14 +426,7 @@ namespace spot
if (res) if (res)
{ {
if (state_based_) dba = do_scc_filter(res, true);
// FIXME: This does not simplify generalized acceptance
// conditions, but calling scc_filter() would break the
// BA-typeness of res by removing acceptance marks from
// out-of-SCC transitions.
dba = scc_filter_states(res);
else
dba = scc_filter(res, true);
dba_is_minimal = true; dba_is_minimal = true;
} }
} }
@ -438,18 +449,12 @@ namespace spot
{ {
if (dba && !dba_is_minimal) // WDBA is already clean. if (dba && !dba_is_minimal) // WDBA is already clean.
{ {
if (state_based_ && dba->has_state_based_acc()) dba = do_scc_filter(dba, true);
dba = scc_filter_states(dba);
else
dba = scc_filter(dba, true);
assert(!sim); assert(!sim);
} }
else if (sim) else if (sim)
{ {
if (state_based_ && sim->has_state_based_acc()) sim = do_scc_filter(sim, true);
sim = scc_filter_states(sim);
else
sim = scc_filter(sim, true);
assert(!dba); assert(!dba);
} }
} }

View file

@ -105,6 +105,8 @@ namespace spot
twa_graph_ptr do_simul(const twa_graph_ptr& input, int opt); twa_graph_ptr do_simul(const twa_graph_ptr& input, int opt);
twa_graph_ptr do_sba_simul(const twa_graph_ptr& input, int opt); twa_graph_ptr do_sba_simul(const twa_graph_ptr& input, int opt);
twa_graph_ptr do_degen(const twa_graph_ptr& input); twa_graph_ptr do_degen(const twa_graph_ptr& input);
twa_graph_ptr do_scc_filter(const twa_graph_ptr& a, bool arg);
twa_graph_ptr do_scc_filter(const twa_graph_ptr& a);
output_type type_; output_type type_;
int pref_; int pref_;

View file

@ -34,7 +34,8 @@
#include "twaalgos/gtec/gtec.hh" #include "twaalgos/gtec/gtec.hh"
#include "twaalgos/sccfilter.hh" #include "twaalgos/sccfilter.hh"
#include "twaalgos/ltl2tgba_fm.hh" #include "twaalgos/ltl2tgba_fm.hh"
#include "twaalgos/dtgbacomp.hh" #include "twaalgos/complement.hh"
#include "twaalgos/remfin.hh"
#include "misc/bitvect.hh" #include "misc/bitvect.hh"
#include "misc/bddlt.hh" #include "misc/bddlt.hh"
@ -426,7 +427,7 @@ namespace spot
if (product(det, neg_aut)->is_empty()) if (product(det, neg_aut)->is_empty())
// Complement the DBA. // Complement the DBA.
if (product(aut, dtgba_complement(det))->is_empty()) if (product(aut, remove_fin(dtwa_complement(det)))->is_empty())
// Finally, we are now sure that it was safe // Finally, we are now sure that it was safe
// to determinize the automaton. // to determinize the automaton.
return det; return det;

View file

@ -22,6 +22,7 @@
#include <iostream> #include <iostream>
#include "cleanacc.hh" #include "cleanacc.hh"
#include "totgba.hh" #include "totgba.hh"
#include "isdet.hh"
#include "mask.hh" #include "mask.hh"
//#define TRACE //#define TRACE
@ -450,6 +451,54 @@ namespace spot
return res; return res;
} }
static twa_graph_ptr
remove_fin_det_weak(const const_twa_graph_ptr& aut)
{
// Clone the original automaton.
auto res = make_twa_graph(aut,
{
true, // state based
true, // inherently weak
true, // determinisitic
true, // stutter inv.
});
scc_info si(res);
// We will modify res in place, and the resulting
// automaton will only have one acceptance set.
acc_cond::mark_t all_acc = res->set_buchi();
res->prop_state_based_acc();
res->prop_deterministic();
unsigned sink = res->num_states();
for (unsigned src = 0; src < sink; ++src)
{
acc_cond::mark_t acc = 0U;
unsigned scc = si.scc_of(src);
if (si.is_accepting_scc(scc) && !si.is_trivial(scc))
acc = all_acc;
// Keep track of all conditions on edge leaving state
// SRC, so we can complete it.
bdd missingcond = bddtrue;
for (auto& t: res->out(src))
{
missingcond -= t.cond;
t.acc = acc;
}
// Complete the original automaton.
if (missingcond != bddfalse)
{
if (res->num_states() == sink)
{
res->new_state();
res->new_acc_edge(sink, sink, bddtrue);
}
res->new_edge(src, sink, missingcond);
}
}
//res->merge_edges();
return res;
}
} }
twa_graph_ptr remove_fin(const const_twa_graph_ptr& aut) twa_graph_ptr remove_fin(const const_twa_graph_ptr& aut)
@ -457,6 +506,10 @@ namespace spot
if (!aut->acc().uses_fin_acceptance()) if (!aut->acc().uses_fin_acceptance())
return std::const_pointer_cast<twa_graph>(aut); return std::const_pointer_cast<twa_graph>(aut);
// FIXME: we should check whether the automaton is weak.
if (aut->is_inherently_weak() && is_deterministic(aut))
return remove_fin_det_weak(aut);
if (auto maybe = streett_to_generalized_buchi_maybe(aut)) if (auto maybe = streett_to_generalized_buchi_maybe(aut))
return maybe; return maybe;
@ -609,13 +662,13 @@ namespace spot
unsigned nst = aut->num_states(); unsigned nst = aut->num_states();
auto res = make_twa_graph(aut->get_dict()); auto res = make_twa_graph(aut->get_dict());
res->copy_ap_of(aut); res->copy_ap_of(aut);
res->prop_copy(aut, { false, false, false, true }); res->prop_copy(aut, { true, false, false, true });
res->new_states(nst); res->new_states(nst);
res->set_acceptance(aut->num_sets() + extra_sets, new_code); res->set_acceptance(aut->num_sets() + extra_sets, new_code);
res->set_init_state(aut->get_init_state_number()); res->set_init_state(aut->get_init_state_number());
bool sbacc = aut->has_state_based_acc();
scc_info si(aut); scc_info si(aut);
unsigned nscc = si.scc_count(); unsigned nscc = si.scc_count();
std::vector<unsigned> state_map(nst); std::vector<unsigned> state_map(nst);
for (unsigned n = 0; n < nscc; ++n) for (unsigned n = 0; n < nscc; ++n)
@ -643,7 +696,12 @@ namespace spot
// Create the main copy // Create the main copy
for (auto s: states) for (auto s: states)
for (auto& t: aut->out(s)) for (auto& t: aut->out(s))
res->new_edge(s, t.dst, t.cond, (t.acc & main_sets) | main_add); {
acc_cond::mark_t a = 0U;
if (sbacc || SPOT_LIKELY(si.scc_of(t.dst) == n))
a = (t.acc & main_sets) | main_add;
res->new_edge(s, t.dst, t.cond, a);
}
// We do not need any other copy if the SCC is non-accepting, // We do not need any other copy if the SCC is non-accepting,
// of if it does not intersect any Fin. // of if it does not intersect any Fin.
@ -673,22 +731,27 @@ namespace spot
// We need only one non-deterministic jump per // We need only one non-deterministic jump per
// cycle. As an approximation, we only do // cycle. As an approximation, we only do
// them on back-links. // them on back-links.
//
// The acceptance marks on these edge
// are useless, but we keep them to preserve
// state-based acceptance if any.
if (t.dst <= s) if (t.dst <= s)
res->new_edge(s, nd, t.cond, {
(t.acc & main_sets) | main_add); acc_cond::mark_t a = 0U;
if (sbacc)
a = (t.acc & main_sets) | main_add;
res->new_edge(s, nd, t.cond, a);
}
} }
} }
} }
} }
// If the input had no Inf, the output is a state-based automaton.
if (allinf == 0U)
res->prop_state_based_acc();
res->purge_dead_states(); res->purge_dead_states();
trace << "before cleanup: " << res->get_acceptance() << '\n'; trace << "before cleanup: " << res->get_acceptance() << '\n';
cleanup_acceptance_here(res); cleanup_acceptance_here(res);
trace << "after cleanup: " << res->get_acceptance() << '\n'; trace << "after cleanup: " << res->get_acceptance() << '\n';
res->merge_edges();
return res; return res;
} }
} }

View file

@ -27,7 +27,8 @@
#include "twaalgos/product.hh" #include "twaalgos/product.hh"
#include "twaalgos/ltl2tgba_fm.hh" #include "twaalgos/ltl2tgba_fm.hh"
#include "twaalgos/isdet.hh" #include "twaalgos/isdet.hh"
#include "twaalgos/dtgbacomp.hh" #include "twaalgos/complement.hh"
#include "twaalgos/remfin.hh"
#include "twa/twaproduct.hh" #include "twa/twaproduct.hh"
#include "twa/bddprint.hh" #include "twa/bddprint.hh"
#include <deque> #include <deque>
@ -635,8 +636,7 @@ namespace spot
aut->prop_deterministic(is_deterministic(aut)); aut->prop_deterministic(is_deterministic(aut));
if (!aut->is_deterministic()) if (!aut->is_deterministic())
return false; return false;
neg = remove_fin(dtwa_complement(aut));
neg = dtgba_complement(aut);
} }
is_stut = is_stutter_invariant(make_twa_graph(aut, twa::prop_set::all()), is_stut = is_stutter_invariant(make_twa_graph(aut, twa::prop_set::all()),

View file

@ -113,6 +113,7 @@
#include "twaalgos/degen.hh" #include "twaalgos/degen.hh"
#include "twaalgos/copy.hh" #include "twaalgos/copy.hh"
#include "twaalgos/complete.hh" #include "twaalgos/complete.hh"
#include "twaalgos/complement.hh"
#include "twaalgos/emptiness.hh" #include "twaalgos/emptiness.hh"
#include "twaalgos/gtec/gtec.hh" #include "twaalgos/gtec/gtec.hh"
#include "twaalgos/lbtt.hh" #include "twaalgos/lbtt.hh"
@ -266,6 +267,7 @@ namespace std {
%include "twaalgos/dot.hh" %include "twaalgos/dot.hh"
%include "twaalgos/copy.hh" %include "twaalgos/copy.hh"
%include "twaalgos/complete.hh" %include "twaalgos/complete.hh"
%include "twaalgos/complement.hh"
%include "twaalgos/emptiness.hh" %include "twaalgos/emptiness.hh"
%include "twaalgos/gtec/gtec.hh" %include "twaalgos/gtec/gtec.hh"
%include "twaalgos/lbtt.hh" %include "twaalgos/lbtt.hh"