Fix "BDD Error" in scc_filter().
If all the acceptance set of an SCC but the first one were useless, the scc_filter() algorithm could abort with a BDD error because of a bug in the logic. * src/tgbaalgos/sccfilter.cc (scc_filter): Fix. * src/tgbatest/sccsimpl.test: Add a test case supplied by Étienne Renault.
This commit is contained in:
parent
372a086cb7
commit
fc5d4e1a41
2 changed files with 44 additions and 18 deletions
|
|
@ -351,20 +351,31 @@ namespace spot
|
||||||
|
|
||||||
//std::cerr << "SCC #" << n << "; used = " << all << std::endl;
|
//std::cerr << "SCC #" << n << "; used = " << all << std::endl;
|
||||||
|
|
||||||
// Compute a set of useless acceptance conditions.
|
// Compute a set of useless acceptance sets.
|
||||||
// If the acceptance combinations occurring in
|
// If the acceptance combinations occurring in
|
||||||
// the automata are { a, ab, abc, bd }, then
|
// the automata are { a, ab, abc, bd }, then
|
||||||
// ALL contains (a&!b&!c&!d)|(a&b&!c&!d)|(a&b&c&!d)|(!a&b&!c&d)
|
// ALL contains (a&!b&!c&!d)|(a&b&!c&!d)|(a&b&c&!d)|(!a&b&!c&d)
|
||||||
// and we want to find that 'a' and 'b' are useless because
|
// and we want to find that 'a' and 'b' are useless because
|
||||||
// they always occur with 'c'.
|
// they always occur with 'c'.
|
||||||
// The way we check if 'a' is useless is to look whether ALL
|
// The way we check if 'a' is useless is to look whether ALL
|
||||||
// implies (x -> a) for some other acceptance condition x.
|
// implies (x -> a) for some other acceptance set x.
|
||||||
bdd allconds = bdd_support(negall);
|
//
|
||||||
bdd allcondscopy = allconds;
|
// The two while() loops in the code perform the equivalent of
|
||||||
|
// for all a in allconds_a:
|
||||||
|
// for all x in allconds_x:
|
||||||
|
// check whether x -> a
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// Initially allconds_a = allconds_x contains all acceptance
|
||||||
|
// sets. However when an acceptance set 'a' is determined to
|
||||||
|
// be useless, it can be removed from allconds_x from future
|
||||||
|
// iterations.
|
||||||
|
bdd allconds_a = bdd_support(negall);
|
||||||
|
bdd allconds_x = allconds_a;
|
||||||
bdd useless = bddtrue;
|
bdd useless = bddtrue;
|
||||||
while (allconds != bddtrue)
|
while (allconds_a != bddtrue)
|
||||||
{
|
{
|
||||||
// Speed-up the computation of implied acceptance by
|
// Speed-up the computation of implied acceptance sets by
|
||||||
// removing those that are always present. We detect
|
// removing those that are always present. We detect
|
||||||
// those that appear as conjunction of positive variables
|
// those that appear as conjunction of positive variables
|
||||||
// at the start of ALL.
|
// at the start of ALL.
|
||||||
|
|
@ -372,8 +383,8 @@ namespace spot
|
||||||
if (prefix != bddtrue)
|
if (prefix != bddtrue)
|
||||||
{
|
{
|
||||||
assert(prefix == bdd_support(prefix));
|
assert(prefix == bdd_support(prefix));
|
||||||
allcondscopy = bdd_exist(allcondscopy, prefix);
|
allconds_a = bdd_exist(allconds_a, prefix);
|
||||||
if (allcondscopy != bddtrue)
|
if (allconds_a != bddtrue)
|
||||||
{
|
{
|
||||||
useless &= prefix;
|
useless &= prefix;
|
||||||
}
|
}
|
||||||
|
|
@ -383,34 +394,34 @@ namespace spot
|
||||||
useless &= bdd_high(prefix);
|
useless &= bdd_high(prefix);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
allconds = bdd_exist(allconds, prefix);
|
allconds_x = bdd_exist(allconds_x, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick a non-useless acceptance condition a.
|
// Pick an acceptance set 'a'.
|
||||||
bdd a = bdd_ithvar(bdd_var(allconds));
|
bdd a = bdd_ithvar(bdd_var(allconds_a));
|
||||||
// For all acceptance condition x that is not already useless...
|
// For all acceptance sets 'x' that are not already
|
||||||
bdd others = allcondscopy;
|
// useless...
|
||||||
|
bdd others = allconds_x;
|
||||||
while (others != bddtrue)
|
while (others != bddtrue)
|
||||||
{
|
{
|
||||||
bdd x = bdd_ithvar(bdd_var(others));
|
bdd x = bdd_ithvar(bdd_var(others));
|
||||||
// ... check whether it always implies a.
|
// ... check whether 'x' always implies 'a'.
|
||||||
if (x != a && bdd_implies(all, x >> a))
|
if (x != a && bdd_implies(all, x >> a))
|
||||||
{
|
{
|
||||||
// If so, a is useless.
|
// If so, 'a' is useless.
|
||||||
all = bdd_exist(all, a);
|
all = bdd_exist(all, a);
|
||||||
useless &= a;
|
useless &= a;
|
||||||
allcondscopy = bdd_exist(allcondscopy, a);
|
allconds_x = bdd_exist(allconds_x, a);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
others = bdd_high(others);
|
others = bdd_high(others);
|
||||||
}
|
}
|
||||||
allconds = bdd_high(allconds);
|
allconds_a = bdd_high(allconds_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We never remove ALL acceptance marks.
|
// We never remove ALL acceptance marks.
|
||||||
assert(negall == bddtrue || useless != bdd_support(negall));
|
assert(negall == bddtrue || useless != bdd_support(negall));
|
||||||
|
|
||||||
|
|
||||||
useless_table[n] = useless;
|
useless_table[n] = useless;
|
||||||
bdd useful = bdd_exist(negall, useless);
|
bdd useful = bdd_exist(negall, useless);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -170,3 +170,18 @@ test `grep '^acc' out8.txt | wc -w` = 4
|
||||||
run 0 ../ltl2tgba -R3 -s -RDS -ks \
|
run 0 ../ltl2tgba -R3 -s -RDS -ks \
|
||||||
'(G(!((b) R (a)))) R (((c) R (!(d))) U (G((a) | (!(G(e))))))' > out9.txt
|
'(G(!((b) R (a)))) R (((c) R (!(d))) U (G((a) | (!(G(e))))))' > out9.txt
|
||||||
grep 'states: 6$' out9.txt
|
grep 'states: 6$' out9.txt
|
||||||
|
|
||||||
|
|
||||||
|
# From Spot 1.1 to 1.1.2, this failed with a BDD error because of
|
||||||
|
# a bug in scc_filter().
|
||||||
|
run 0 ../ltl2tgba -R3 -k '(a) <-> F(Ga <-> F!(b -> a))' >stdout
|
||||||
|
cat >expected <<EOF
|
||||||
|
transitions: 21
|
||||||
|
states: 8
|
||||||
|
total SCCs: 6
|
||||||
|
accepting SCCs: 3
|
||||||
|
dead SCCs: 0
|
||||||
|
accepting paths: 4
|
||||||
|
dead paths: 0
|
||||||
|
EOF
|
||||||
|
diff stdout expected
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue