Improve SCC simplification by removing implied acceptance conditions.
Spot 0.7.1 used to need 190 acceptance conditions to translate the 188 literature formulae. With this patch we are down to 185. That's not an impressive, but there are only ~20 formulae that require more than 1 acceptance conditions; hence little room for improvement. * src/misc/bddlt.hh (bdd_hash): New function. * src/misc/accconv.hh, src/misc/accconv.cc: New files. * src/misc/Makefile.am: Add them. * src/tgbaalgos/scc.cc (scc_map::build_map): Adjust to record all combination of acceptance conditions occurring in a SCC. * src/tgbaalgos/scc.hh (scc_map::scc::useful_acc): Update description. * src/tgbaalgos/sccfilter.cc (scc_filter): Simplify acceptance conditions that are always implied by another acceptance conditions. Previously, we only removed acceptance conditions that where always present in accepting SCCs. * src/tgbatest/sccsimpl.test: New file. * src/tgbatest/Makefile.am (TESTS): Add it.
This commit is contained in:
parent
9d232af82f
commit
d9fc75e94e
10 changed files with 401 additions and 28 deletions
|
|
@ -25,6 +25,7 @@
|
|||
#include "scc.hh"
|
||||
#include "tgba/bddprint.hh"
|
||||
#include "misc/escape.hh"
|
||||
#include "misc/accconv.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -139,6 +140,8 @@ namespace spot
|
|||
void
|
||||
scc_map::build_map()
|
||||
{
|
||||
acceptance_convertor conv(aut_->neg_acceptance_conditions());
|
||||
|
||||
// Setup depth-first search from the initial state.
|
||||
{
|
||||
self_loops_ = 0;
|
||||
|
|
@ -267,7 +270,7 @@ namespace spot
|
|||
conds.insert(cond);
|
||||
bdd supp = bdd_support(cond);
|
||||
bdd all = aut_->all_acceptance_conditions();
|
||||
bdd useful = all - acc;
|
||||
bdd useful = conv.as_full_product(acc);
|
||||
while (threshold > root_.front().index)
|
||||
{
|
||||
assert(!root_.empty());
|
||||
|
|
@ -276,7 +279,7 @@ namespace spot
|
|||
acc |= root_.front().acc;
|
||||
bdd lacc = arc_acc_.top();
|
||||
acc |= lacc;
|
||||
useful |= (all - lacc) | root_.front().useful_acc;
|
||||
useful |= conv.as_full_product(lacc) | root_.front().useful_acc;
|
||||
states.splice(states.end(), root_.front().states);
|
||||
succs.insert(root_.front().succ.begin(),
|
||||
root_.front().succ.end());
|
||||
|
|
@ -447,15 +450,13 @@ namespace spot
|
|||
res.dead_paths = d.dead_paths[init];
|
||||
|
||||
res.useless_scc_map.reserve(res.scc_total);
|
||||
bdd useful_acc = bddfalse;
|
||||
res.useful_acc = bddfalse;
|
||||
for (unsigned n = 0; n < res.scc_total; ++n)
|
||||
{
|
||||
res.useless_scc_map[n] = !d.acc_paths[n];
|
||||
if (m.accepting(n))
|
||||
useful_acc |= m.useful_acc_of(n);
|
||||
res.useful_acc |= m.useful_acc_of(n);
|
||||
}
|
||||
res.useful_acc = useful_acc;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -200,7 +200,16 @@ namespace spot
|
|||
succ_type succ;
|
||||
/// Trivial SCC have one state and no self-loops.
|
||||
bool trivial;
|
||||
/// Useful acceptance conditions.
|
||||
/// \brief Set of acceptance combinations used in the SCC.
|
||||
///
|
||||
/// Note that the encoding used here differs from the
|
||||
/// encoding used in automata.
|
||||
/// If some transitions of the automaton are labeled by
|
||||
/// Acc[a]&!Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&!Acc[c]
|
||||
/// an other transitions are labeled by
|
||||
/// !Acc[a]&Acc[b]&!Acc[c] | !Acc[a]&!Acc[b]&Acc[c]
|
||||
/// then useful_acc will contain
|
||||
/// Acc[a]&Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&Acc[c]
|
||||
bdd useful_acc;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (C) 2009, 2010 Laboratoire de Recherche et Developpement
|
||||
// Copyright (C) 2009, 2010, 2011 Laboratoire de Recherche et Developpement
|
||||
// de l'Epita (LRDE).
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#include "tgba/tgbaexplicit.hh"
|
||||
#include "reachiter.hh"
|
||||
#include "tgbaalgos/scc.hh"
|
||||
#include "misc/bddop.hh"
|
||||
#include <sstream>
|
||||
|
||||
namespace spot
|
||||
|
|
@ -131,31 +132,47 @@ namespace spot
|
|||
scc_stats ss = build_scc_stats(sm);
|
||||
|
||||
bdd useful = ss.useful_acc;
|
||||
if (useful == bddfalse)
|
||||
// Even if no acceptance conditions are useful in a SCC,
|
||||
// we need to keep at least one acceptance conditions
|
||||
useful = bdd_satone(aut->all_acceptance_conditions());
|
||||
|
||||
bdd positive = bddtrue;
|
||||
bdd cur = useful;
|
||||
while (cur != bddfalse)
|
||||
bdd negall = aut->neg_acceptance_conditions();
|
||||
// Compute a set of useless acceptance conditions.
|
||||
// If the acceptance combinations occurring in
|
||||
// the automata are { a, ab, abc, bd }, then
|
||||
// USEFUL 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
|
||||
// they always occur with 'c'.
|
||||
// The way we check if 'a' is useless that is to look whether
|
||||
// USEFUL & (x -> a) == USEFUL for some other acceptance
|
||||
// condition x.
|
||||
bdd allconds = bdd_support(negall);
|
||||
bdd allcondscopy = allconds;
|
||||
bdd useless = bddtrue;
|
||||
while (allconds != bddtrue)
|
||||
{
|
||||
bdd a = bdd_satone(cur);
|
||||
cur -= a;
|
||||
for (;;)
|
||||
bdd a = bdd_ithvar(bdd_var(allconds));
|
||||
bdd others = allcondscopy;
|
||||
|
||||
while (others != bddtrue)
|
||||
{
|
||||
if (bdd_low(a) == bddfalse)
|
||||
bdd x = bdd_ithvar(bdd_var(others));
|
||||
if (x != a)
|
||||
{
|
||||
positive &= bdd_ithvar(bdd_var(a));
|
||||
break;
|
||||
if ((useful & (x >> a)) == useful)
|
||||
{
|
||||
// a is useless
|
||||
useful = bdd_exist(useful, a);
|
||||
useless &= a;
|
||||
allcondscopy = bdd_exist(allcondscopy, a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
a = bdd_low(a);
|
||||
others = bdd_high(others);
|
||||
}
|
||||
allconds = bdd_high(allconds);
|
||||
}
|
||||
|
||||
bdd strip = bdd_exist(bdd_support(aut->all_acceptance_conditions()),
|
||||
positive);
|
||||
useful = bdd_exist(useful, strip);
|
||||
// We never remove ALL acceptance conditions.
|
||||
assert(negall == bddtrue || useless != bdd_support(negall));
|
||||
|
||||
useful = compute_all_acceptance_conditions(bdd_exist(negall, useless));
|
||||
|
||||
// In most cases we will create a tgba_explicit_string copy of the
|
||||
// initial tgba, but this is not very space efficient as the
|
||||
|
|
@ -168,7 +185,7 @@ namespace spot
|
|||
if (af)
|
||||
{
|
||||
filter_iter<tgba_explicit_formula> fi(af, sm, ss.useless_scc_map,
|
||||
useful, strip,
|
||||
useful, useless,
|
||||
remove_all_useless);
|
||||
fi.run();
|
||||
tgba_explicit_formula* res = fi.result();
|
||||
|
|
@ -178,7 +195,7 @@ namespace spot
|
|||
else
|
||||
{
|
||||
filter_iter<tgba_explicit_string> fi(aut, sm, ss.useless_scc_map,
|
||||
useful, strip,
|
||||
useful, useless,
|
||||
remove_all_useless);
|
||||
fi.run();
|
||||
tgba_explicit_string* res = fi.result();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue