sanity: Replace tabulars by spaces in *.cc *.hh *.hxx

* bin/autfilt.cc, bin/common_aoutput.cc, bin/common_aoutput.hh,
bin/common_finput.cc, bin/common_finput.hh, bin/common_hoaread.cc,
bin/common_output.cc, bin/common_output.hh, bin/common_post.cc,
bin/common_post.hh, bin/common_r.hh, bin/common_range.cc,
bin/common_range.hh, bin/common_setup.cc, bin/common_trans.cc,
bin/common_trans.hh, bin/dstar2tgba.cc, bin/genltl.cc,
bin/ltl2tgba.cc, bin/ltl2tgta.cc, bin/ltlcross.cc, bin/ltldo.cc,
bin/ltlfilt.cc, bin/ltlgrind.cc, bin/randaut.cc, bin/randltl.cc,
bin/spot-x.cc, spot/graph/graph.hh, spot/graph/ngraph.hh,
spot/kripke/kripkegraph.hh, spot/ltsmin/ltsmin.cc,
spot/ltsmin/ltsmin.hh, spot/misc/bareword.cc, spot/misc/bitvect.cc,
spot/misc/bitvect.hh, spot/misc/common.hh, spot/misc/escape.cc,
spot/misc/fixpool.hh, spot/misc/formater.cc, spot/misc/hash.hh,
spot/misc/intvcmp2.cc, spot/misc/intvcmp2.hh, spot/misc/intvcomp.cc,
spot/misc/intvcomp.hh, spot/misc/location.hh, spot/misc/minato.cc,
spot/misc/minato.hh, spot/misc/mspool.hh, spot/misc/optionmap.cc,
spot/misc/optionmap.hh, spot/misc/random.cc, spot/misc/random.hh,
spot/misc/satsolver.cc, spot/misc/satsolver.hh, spot/misc/timer.cc,
spot/misc/timer.hh, spot/misc/tmpfile.cc, spot/misc/trival.hh,
spot/parseaut/fmterror.cc, spot/parseaut/parsedecl.hh,
spot/parseaut/public.hh, spot/parsetl/fmterror.cc,
spot/parsetl/parsedecl.hh, spot/priv/accmap.hh, spot/priv/bddalloc.cc,
spot/priv/freelist.cc, spot/priv/trim.cc, spot/priv/weight.cc,
spot/priv/weight.hh, spot/ta/taexplicit.cc, spot/ta/taexplicit.hh,
spot/ta/taproduct.cc, spot/ta/taproduct.hh, spot/ta/tgtaexplicit.cc,
spot/ta/tgtaexplicit.hh, spot/ta/tgtaproduct.cc,
spot/ta/tgtaproduct.hh, spot/taalgos/dot.cc, spot/taalgos/dot.hh,
spot/taalgos/emptinessta.cc, spot/taalgos/emptinessta.hh,
spot/taalgos/minimize.cc, spot/taalgos/tgba2ta.cc,
spot/taalgos/tgba2ta.hh, spot/tl/apcollect.cc, spot/tl/contain.cc,
spot/tl/contain.hh, spot/tl/dot.cc, spot/tl/exclusive.cc,
spot/tl/exclusive.hh, spot/tl/formula.cc, spot/tl/formula.hh,
spot/tl/length.cc, spot/tl/mark.cc, spot/tl/mutation.cc,
spot/tl/mutation.hh, spot/tl/parse.hh, spot/tl/print.cc,
spot/tl/print.hh, spot/tl/randomltl.cc, spot/tl/randomltl.hh,
spot/tl/relabel.cc, spot/tl/relabel.hh, spot/tl/remove_x.cc,
spot/tl/simplify.cc, spot/tl/simplify.hh, spot/tl/snf.cc,
spot/tl/snf.hh, spot/tl/unabbrev.cc, spot/tl/unabbrev.hh,
spot/twa/acc.cc, spot/twa/acc.hh, spot/twa/bdddict.cc,
spot/twa/bdddict.hh, spot/twa/bddprint.cc, spot/twa/formula2bdd.cc,
spot/twa/formula2bdd.hh, spot/twa/taatgba.cc, spot/twa/taatgba.hh,
spot/twa/twa.cc, spot/twa/twa.hh, spot/twa/twagraph.cc,
spot/twa/twagraph.hh, spot/twa/twaproduct.cc, spot/twa/twaproduct.hh,
spot/twaalgos/are_isomorphic.cc, spot/twaalgos/are_isomorphic.hh,
spot/twaalgos/bfssteps.cc, spot/twaalgos/bfssteps.hh,
spot/twaalgos/cleanacc.cc, spot/twaalgos/complete.cc,
spot/twaalgos/compsusp.cc, spot/twaalgos/compsusp.hh,
spot/twaalgos/copy.cc, spot/twaalgos/cycles.cc,
spot/twaalgos/cycles.hh, spot/twaalgos/degen.cc,
spot/twaalgos/degen.hh, spot/twaalgos/determinize.cc,
spot/twaalgos/determinize.hh, spot/twaalgos/dot.cc,
spot/twaalgos/dot.hh, spot/twaalgos/dtbasat.cc,
spot/twaalgos/dtbasat.hh, spot/twaalgos/dtwasat.cc,
spot/twaalgos/dtwasat.hh, spot/twaalgos/emptiness.cc,
spot/twaalgos/emptiness.hh, spot/twaalgos/emptiness_stats.hh,
spot/twaalgos/gtec/ce.cc, spot/twaalgos/gtec/ce.hh,
spot/twaalgos/gtec/gtec.cc, spot/twaalgos/gtec/gtec.hh,
spot/twaalgos/gtec/sccstack.cc, spot/twaalgos/gtec/status.cc,
spot/twaalgos/gv04.cc, spot/twaalgos/hoa.cc, spot/twaalgos/hoa.hh,
spot/twaalgos/isdet.cc, spot/twaalgos/isunamb.cc,
spot/twaalgos/isweakscc.cc, spot/twaalgos/lbtt.cc,
spot/twaalgos/lbtt.hh, spot/twaalgos/ltl2taa.cc,
spot/twaalgos/ltl2taa.hh, spot/twaalgos/ltl2tgba_fm.cc,
spot/twaalgos/ltl2tgba_fm.hh, spot/twaalgos/magic.cc,
spot/twaalgos/magic.hh, spot/twaalgos/mask.cc, spot/twaalgos/mask.hh,
spot/twaalgos/minimize.cc, spot/twaalgos/minimize.hh,
spot/twaalgos/ndfs_result.hxx, spot/twaalgos/neverclaim.cc,
spot/twaalgos/neverclaim.hh, spot/twaalgos/postproc.cc,
spot/twaalgos/postproc.hh, spot/twaalgos/powerset.cc,
spot/twaalgos/powerset.hh, spot/twaalgos/product.cc,
spot/twaalgos/product.hh, spot/twaalgos/projrun.cc,
spot/twaalgos/projrun.hh, spot/twaalgos/randomgraph.cc,
spot/twaalgos/randomgraph.hh, spot/twaalgos/randomize.cc,
spot/twaalgos/randomize.hh, spot/twaalgos/reachiter.cc,
spot/twaalgos/reachiter.hh, spot/twaalgos/relabel.cc,
spot/twaalgos/relabel.hh, spot/twaalgos/remfin.cc,
spot/twaalgos/remprop.cc, spot/twaalgos/sbacc.cc,
spot/twaalgos/sccfilter.cc, spot/twaalgos/sccfilter.hh,
spot/twaalgos/sccinfo.cc, spot/twaalgos/sccinfo.hh,
spot/twaalgos/se05.cc, spot/twaalgos/se05.hh,
spot/twaalgos/sepsets.cc, spot/twaalgos/simulation.cc,
spot/twaalgos/simulation.hh, spot/twaalgos/stats.cc,
spot/twaalgos/stats.hh, spot/twaalgos/strength.cc,
spot/twaalgos/strength.hh, spot/twaalgos/stripacc.cc,
spot/twaalgos/stutter.cc, spot/twaalgos/stutter.hh,
spot/twaalgos/tau03.cc, spot/twaalgos/tau03opt.cc,
spot/twaalgos/tau03opt.hh, spot/twaalgos/totgba.cc,
spot/twaalgos/translate.cc, spot/twaalgos/word.cc, tests/core/acc.cc,
tests/core/bitvect.cc, tests/core/checkpsl.cc, tests/core/checkta.cc,
tests/core/consterm.cc, tests/core/emptchk.cc, tests/core/equalsf.cc,
tests/core/graph.cc, tests/core/ikwiad.cc, tests/core/intvcmp2.cc,
tests/core/intvcomp.cc, tests/core/kind.cc, tests/core/kripkecat.cc,
tests/core/ltlrel.cc, tests/core/ngraph.cc, tests/core/randtgba.cc,
tests/core/readltl.cc, tests/core/reduc.cc, tests/core/safra.cc,
tests/core/syntimpl.cc, tests/ltsmin/modelcheck.cc: Replace tabulars by
8 spaces.
* tests/sanity/style.test: Add checks for no tabulars in *.cc *.hh *.hxx
This commit is contained in:
Laurent XU 2016-03-09 00:23:20 +01:00 committed by Alexandre Duret-Lutz
parent 1eee12b8b4
commit f7e7b4f14e
239 changed files with 25359 additions and 25355 deletions

View file

@ -116,13 +116,13 @@ namespace spot
trival prop_det = ref_->prop_deterministic();
if (prop_det)
{
ref_deterministic_ = true;
ref_deterministic_ = true;
}
else
{
// Count the number of state even if we know that the
// automaton is non-deterministic, as this can be used to
// decide if two automata are non-isomorphic.
// Count the number of state even if we know that the
// automaton is non-deterministic, as this can be used to
// decide if two automata are non-isomorphic.
nondet_states_ = spot::count_nondet_states(ref_);
ref_deterministic_ = (nondet_states_ == 0);
}
@ -136,12 +136,12 @@ namespace spot
if (ref_deterministic_)
{
if (autdet || (!autdet && spot::is_deterministic(aut)))
return are_isomorphic_det(ref_, aut);
return are_isomorphic_det(ref_, aut);
}
else
{
if (autdet || nondet_states_ != spot::count_nondet_states(aut))
return false;
return false;
}
auto tmp = make_twa_graph(aut, twa::prop_set::all());
@ -159,7 +159,7 @@ namespace spot
bool
isomorphism_checker::are_isomorphic(const const_twa_graph_ptr ref,
const const_twa_graph_ptr aut)
const const_twa_graph_ptr aut)
{
if (trivially_different(ref, aut))
return false;

View file

@ -49,7 +49,7 @@ namespace spot
/// \ingroup twa_misc
/// \brief Check whether two automata are isomorphic.
static bool are_isomorphic(const const_twa_graph_ptr ref,
const const_twa_graph_ptr aut);
const const_twa_graph_ptr aut);
private:
bool is_isomorphic_(const const_twa_graph_ptr aut);

View file

@ -73,34 +73,34 @@ namespace spot
while (!todo.empty())
{
const state* src = todo.front();
todo.pop_front();
for (auto i: a_->succ(src))
{
const state* dest = filter(i->dst());
const state* src = todo.front();
todo.pop_front();
for (auto i: a_->succ(src))
{
const state* dest = filter(i->dst());
if (!dest)
continue;
if (!dest)
continue;
bdd cond = i->cond();
acc_cond::mark_t acc = i->acc();
twa_run::step s = { src, cond, acc };
bdd cond = i->cond();
acc_cond::mark_t acc = i->acc();
twa_run::step s = { src, cond, acc };
if (match(s, dest))
{
// Found it!
if (match(s, dest))
{
// Found it!
finalize(father, s, start, l);
return dest;
}
return dest;
}
// Common case: record backlinks and continue BFS
// for unvisited states.
if (father.find(dest) == father.end())
{
todo.push_back(dest);
father[dest] = s;
}
}
// Common case: record backlinks and continue BFS
// for unvisited states.
if (father.find(dest) == father.end())
{
todo.push_back(dest);
father[dest] = s;
}
}
}
return nullptr;
}

View file

@ -91,12 +91,12 @@ namespace spot
/// unless you do not want \a l to be updated (in which case an empty
/// finalize() will do).
virtual void finalize(const std::map<const state*, twa_run::step,
state_ptr_less_than>& father,
const twa_run::step& s,
const state* start,
twa_run::steps& l);
state_ptr_less_than>& father,
const twa_run::step& s,
const state* start,
twa_run::steps& l);
protected:
const_twa_ptr a_; ///< The spot::tgba we are searching into.
const_twa_ptr a_; ///< The spot::tgba we are searching into.
};
}

View file

@ -56,7 +56,7 @@ namespace spot
twa_graph_ptr cleanup_acceptance(const_twa_graph_ptr aut)
{
return cleanup_acceptance_here(make_twa_graph(aut,
twa::prop_set::all()));
twa::prop_set::all()));
}

View file

@ -37,50 +37,50 @@ namespace spot
auto um = aut->acc().unsat_mark();
if (!um.first)
{
// We cannot safely complete an automaton if its
// acceptance is always satisfiable.
auto acc = aut->set_buchi();
for (auto& t: aut->edge_vector())
t.acc = acc;
// We cannot safely complete an automaton if its
// acceptance is always satisfiable.
auto acc = aut->set_buchi();
for (auto& t: aut->edge_vector())
t.acc = acc;
}
else
{
// Loop over the states and search a state that has only self
// loop labeled by the same non-accepting mark. This will be
// our sink state. Note that we do not even have to ensure
// that the state is complete as we will complete the whole
// automaton in a second pass.
for (unsigned i = 0; i < n; ++i)
{
bool sinkable = true;
bool first = true;
acc_cond::mark_t commonacc = 0U;
for (auto& t: aut->out(i))
{
if (t.dst != i) // Not a self-loop
{
sinkable = false;
break;
}
if (first)
{
commonacc = t.acc;
first = false;
}
else if (t.acc != commonacc)
{
sinkable = false;
break;
}
}
if (sinkable && !aut->acc().accepting(commonacc))
{
// We have found a sink!
um.second = commonacc;
sink = i;
break;
}
}
// Loop over the states and search a state that has only self
// loop labeled by the same non-accepting mark. This will be
// our sink state. Note that we do not even have to ensure
// that the state is complete as we will complete the whole
// automaton in a second pass.
for (unsigned i = 0; i < n; ++i)
{
bool sinkable = true;
bool first = true;
acc_cond::mark_t commonacc = 0U;
for (auto& t: aut->out(i))
{
if (t.dst != i) // Not a self-loop
{
sinkable = false;
break;
}
if (first)
{
commonacc = t.acc;
first = false;
}
else if (t.acc != commonacc)
{
sinkable = false;
break;
}
}
if (sinkable && !aut->acc().accepting(commonacc))
{
// We have found a sink!
um.second = commonacc;
sink = i;
break;
}
}
}
unsigned t = aut->num_edges();
@ -92,42 +92,42 @@ namespace spot
// Now complete all states (excluding any newly added the sink).
for (unsigned i = 0; i < n; ++i)
{
bdd missingcond = bddtrue;
acc_cond::mark_t acc = 0U;
for (auto& t: aut->out(i))
{
missingcond -= t.cond;
// FIXME: This is ugly.
//
// In case the automaton uses state-based acceptance, we
// need to put the new edge in the same set as all
// the other.
//
// In case the automaton uses edge-based acceptance,
// it does not matter what acceptance set we put the new
// edge into.
//
// So in both cases, we put the edge in the same
// acceptance sets as the last outgoing edge of the
// state.
acc = t.acc;
}
// If the state has incomplete successors, we need to add a
// edge to some sink state.
if (missingcond != bddfalse)
{
// If we haven't found any sink, simply add one.
if (sink == -1U)
{
sink = aut->new_state();
aut->new_edge(sink, sink, bddtrue, um.second);
}
// In case the automaton use state-based acceptance, propagate
// the acceptance of the first edge to the one we add.
if (aut->prop_state_acc() != true)
acc = 0U;
aut->new_edge(i, sink, missingcond, acc);
}
bdd missingcond = bddtrue;
acc_cond::mark_t acc = 0U;
for (auto& t: aut->out(i))
{
missingcond -= t.cond;
// FIXME: This is ugly.
//
// In case the automaton uses state-based acceptance, we
// need to put the new edge in the same set as all
// the other.
//
// In case the automaton uses edge-based acceptance,
// it does not matter what acceptance set we put the new
// edge into.
//
// So in both cases, we put the edge in the same
// acceptance sets as the last outgoing edge of the
// state.
acc = t.acc;
}
// If the state has incomplete successors, we need to add a
// edge to some sink state.
if (missingcond != bddfalse)
{
// If we haven't found any sink, simply add one.
if (sink == -1U)
{
sink = aut->new_state();
aut->new_edge(sink, sink, bddtrue, um.second);
}
// In case the automaton use state-based acceptance, propagate
// the acceptance of the first edge to the one we add.
if (aut->prop_state_acc() != true)
acc = 0U;
aut->new_edge(i, sink, missingcond, acc);
}
}
// Get rid of any named property if the automaton changed.
@ -142,11 +142,11 @@ namespace spot
twa_graph_ptr complete(const const_twa_ptr& aut)
{
auto res = make_twa_graph(aut, {
true, // state based
true, // inherently_weak
true, // deterministic
true, // stutter inv.
});
true, // state based
true, // inherently_weak
true, // deterministic
true, // stutter inv.
});
complete_here(res);
return res;
}

View file

@ -46,104 +46,104 @@ namespace spot
public:
typedef std::map<formula, formula> fmap_t;
ltl_suspender_visitor(fmap_t& g2s, fmap_t& a2o, bool oblig)
: g2s_(g2s), a2o_(a2o), oblig_(oblig)
: g2s_(g2s), a2o_(a2o), oblig_(oblig)
{
}
formula
visit(formula f)
{
switch (op o = f.kind())
{
case op::Or:
case op::And:
{
vec res;
vec oblig;
vec susp;
unsigned mos = f.size();
for (unsigned i = 0; i < mos; ++i)
{
formula c = f[i];
if (c.is_boolean())
res.push_back(c);
else if (oblig_ && c.is_syntactic_obligation())
oblig.push_back(c);
else if (c.is_eventual() && c.is_universal())
susp.push_back(c);
else
res.push_back(recurse(c));
}
if (!oblig.empty())
{
res.push_back(recurse(formula::multop(o, oblig)));
}
if (!susp.empty())
{
formula x = formula::multop(o, susp);
// Rewrite 'x' as 'G"x"'
formula g = recurse(x);
if (o == op::And)
{
res.push_back(g);
}
else
{
// res || susp -> (res && G![susp]) || G[susp])
auto r = formula::multop(o, res);
auto gn = formula::G(formula::Not(g[0]));
return formula::Or({formula::And({r, gn}), g});
}
}
return formula::multop(o, res);
}
break;
default:
return f.map([this](formula f)
{
return this->recurse(f);
});
}
switch (op o = f.kind())
{
case op::Or:
case op::And:
{
vec res;
vec oblig;
vec susp;
unsigned mos = f.size();
for (unsigned i = 0; i < mos; ++i)
{
formula c = f[i];
if (c.is_boolean())
res.push_back(c);
else if (oblig_ && c.is_syntactic_obligation())
oblig.push_back(c);
else if (c.is_eventual() && c.is_universal())
susp.push_back(c);
else
res.push_back(recurse(c));
}
if (!oblig.empty())
{
res.push_back(recurse(formula::multop(o, oblig)));
}
if (!susp.empty())
{
formula x = formula::multop(o, susp);
// Rewrite 'x' as 'G"x"'
formula g = recurse(x);
if (o == op::And)
{
res.push_back(g);
}
else
{
// res || susp -> (res && G![susp]) || G[susp])
auto r = formula::multop(o, res);
auto gn = formula::G(formula::Not(g[0]));
return formula::Or({formula::And({r, gn}), g});
}
}
return formula::multop(o, res);
}
break;
default:
return f.map([this](formula f)
{
return this->recurse(f);
});
}
}
formula
recurse(formula f)
{
formula res;
if (f.is_boolean())
return f;
if (oblig_ && f.is_syntactic_obligation())
{
fmap_t::const_iterator i = assoc_.find(f);
if (i != assoc_.end())
return i->second;
formula res;
if (f.is_boolean())
return f;
if (oblig_ && f.is_syntactic_obligation())
{
fmap_t::const_iterator i = assoc_.find(f);
if (i != assoc_.end())
return i->second;
std::ostringstream s;
print_psl(s << "", f) << "";
res = formula::ap(s.str());
a2o_[res] = f;
assoc_[f] = res;
return res;
}
if (f.is_eventual() && f.is_universal())
{
fmap_t::const_iterator i = assoc_.find(f);
if (i != assoc_.end())
return formula::G(i->second);
std::ostringstream s;
print_psl(s << "", f) << "";
res = formula::ap(s.str());
a2o_[res] = f;
assoc_[f] = res;
return res;
}
if (f.is_eventual() && f.is_universal())
{
fmap_t::const_iterator i = assoc_.find(f);
if (i != assoc_.end())
return formula::G(i->second);
std::ostringstream s;
print_psl(s << '[', f) << "]$";
res = formula::ap(s.str());
g2s_[res] = f;
assoc_[f] = res;
return formula::G(res);
}
return visit(f);
std::ostringstream s;
print_psl(s << '[', f) << "]$";
res = formula::ap(s.str());
g2s_[res] = f;
assoc_[f] = res;
return formula::G(res);
}
return visit(f);
}
private:
fmap_t& g2s_;
fmap_t assoc_; // This one is only needed by the visitor.
fmap_t assoc_; // This one is only needed by the visitor.
fmap_t& a2o_;
bool oblig_;
};
@ -160,22 +160,22 @@ namespace spot
{
bdd_dict_ptr dict = left->get_dict();
auto right =
iterated_simulations(scc_filter(ltl_to_tgba_fm(f, dict, true, true),
false));
iterated_simulations(scc_filter(ltl_to_tgba_fm(f, dict, true, true),
false));
twa_graph_ptr res = make_twa_graph(dict);
{
// Copy all atomic propositions, except the one corresponding
// to the variable v used for synchronization.
int vn = bdd_var(v);
assert(dict->bdd_map[vn].type = bdd_dict::var);
formula vf = dict->bdd_map[vn].f;
for (auto a: left->ap())
if (a != vf)
res->register_ap(a);
for (auto a: right->ap())
if (a != vf)
res->register_ap(a);
// Copy all atomic propositions, except the one corresponding
// to the variable v used for synchronization.
int vn = bdd_var(v);
assert(dict->bdd_map[vn].type = bdd_dict::var);
formula vf = dict->bdd_map[vn].f;
for (auto a: left->ap())
if (a != vf)
res->register_ap(a);
for (auto a: right->ap())
if (a != vf)
res->register_ap(a);
}
unsigned lsets = left->num_sets();
@ -195,78 +195,78 @@ namespace spot
res->set_init_state(i);
while (!todo.empty())
{
p = todo.front();
todo.pop_front();
const state* ls = p.first;
const state* rs = p.second;
int src = seen[p];
{
p = todo.front();
todo.pop_front();
const state* ls = p.first;
const state* rs = p.second;
int src = seen[p];
for (auto li: left->succ(ls))
{
state_pair d(li->dst(), ris);
bdd lc = li->cond();
for (auto li: left->succ(ls))
{
state_pair d(li->dst(), ris);
bdd lc = li->cond();
twa_succ_iterator* ri = nullptr;
// Should we reset the right automaton?
if ((lc & v) == lc)
{
// No.
ri = right->succ_iter(rs);
ri->first();
}
// Yes. Reset the right automaton.
else
{
p.second = ris;
}
twa_succ_iterator* ri = nullptr;
// Should we reset the right automaton?
if ((lc & v) == lc)
{
// No.
ri = right->succ_iter(rs);
ri->first();
}
// Yes. Reset the right automaton.
else
{
p.second = ris;
}
// This loops over all the right edges
// if RI is defined. Otherwise this just makes
// one iteration as if the right automaton was
// looping in state 0 with "true".
while (!ri || !ri->done())
{
bdd cond = lc;
acc_cond::mark_t racc = radd;
if (ri)
{
cond = lc & ri->cond();
// Skip incompatible edges.
if (cond == bddfalse)
{
ri->next();
continue;
}
d.second = ri->dst();
racc = ri->acc();
}
// This loops over all the right edges
// if RI is defined. Otherwise this just makes
// one iteration as if the right automaton was
// looping in state 0 with "true".
while (!ri || !ri->done())
{
bdd cond = lc;
acc_cond::mark_t racc = radd;
if (ri)
{
cond = lc & ri->cond();
// Skip incompatible edges.
if (cond == bddfalse)
{
ri->next();
continue;
}
d.second = ri->dst();
racc = ri->acc();
}
int dest;
pair_map::const_iterator i = seen.find(d);
if (i != seen.end()) // Is this an existing state?
{
dest = i->second;
}
else
{
dest = res->new_state();
seen[d] = dest;
todo.push_back(d);
}
int dest;
pair_map::const_iterator i = seen.find(d);
if (i != seen.end()) // Is this an existing state?
{
dest = i->second;
}
else
{
dest = res->new_state();
seen[d] = dest;
todo.push_back(d);
}
acc_cond::mark_t a = li->acc() | (racc << lsets);
res->new_edge(src, dest, bdd_exist(cond, v), a);
acc_cond::mark_t a = li->acc() | (racc << lsets);
res->new_edge(src, dest, bdd_exist(cond, v), a);
if (ri)
ri->next();
else
break;
}
if (ri)
right->release_iter(ri);
}
}
if (ri)
ri->next();
else
break;
}
if (ri)
right->release_iter(ri);
}
}
return res;
}
}
@ -274,9 +274,9 @@ namespace spot
twa_graph_ptr
compsusp(formula f, const bdd_dict_ptr& dict,
bool no_wdba, bool no_simulation,
bool early_susp, bool no_susp_product, bool wdba_smaller,
bool oblig)
bool no_wdba, bool no_simulation,
bool early_susp, bool no_susp_product, bool wdba_smaller,
bool oblig)
{
ltl_suspender_visitor::fmap_t g2s;
ltl_suspender_visitor::fmap_t a2o;
@ -286,18 +286,18 @@ namespace spot
// Translate the patched formula, and remove useless SCCs.
twa_graph_ptr res =
scc_filter(ltl_to_tgba_fm(g, dict, true, true, false, false,
nullptr, nullptr),
false);
nullptr, nullptr),
false);
if (!no_wdba)
{
twa_graph_ptr min = minimize_obligation(res, g,
nullptr, wdba_smaller);
if (min != res)
{
res = min;
no_simulation = true;
}
twa_graph_ptr min = minimize_obligation(res, g,
nullptr, wdba_smaller);
if (min != res)
{
res = min;
no_simulation = true;
}
}
if (!no_simulation)
@ -307,21 +307,21 @@ namespace spot
spot::formula_bdd_map susp;
for (auto& it: g2s)
{
auto j = dict->var_map.find(it.first);
// If no BDD variable of this suspended formula exist in the
// BDD dict, it means the suspended subformulae was never
// actually used in the automaton. Just skip it. FIXME: It
// would be better if we had a way to check that the variable
// is used in this automaton, and not in some automaton
// (sharing the same dictionary.)
if (j != dict->var_map.end())
susp[it.second] = bdd_ithvar(j->second);
auto j = dict->var_map.find(it.first);
// If no BDD variable of this suspended formula exist in the
// BDD dict, it means the suspended subformulae was never
// actually used in the automaton. Just skip it. FIXME: It
// would be better if we had a way to check that the variable
// is used in this automaton, and not in some automaton
// (sharing the same dictionary.)
if (j != dict->var_map.end())
susp[it.second] = bdd_ithvar(j->second);
}
// Remove suspendable formulae from non-accepting SCCs.
bdd suspvars = bddtrue;
for (formula_bdd_map::const_iterator i = susp.begin();
i != susp.end(); ++i)
i != susp.end(); ++i)
suspvars &= i->second;
bdd allaccap = bddtrue; // set of atomic prop used in accepting SCCs.
@ -332,8 +332,8 @@ namespace spot
// in accepting SCC.
unsigned sn = si.scc_count();
for (unsigned n = 0; n < sn; n++)
if (si.is_accepting_scc(n))
allaccap &= si.scc_ap_support(n);
if (si.is_accepting_scc(n))
allaccap &= si.scc_ap_support(n);
bdd ignored = bdd_exist(suspvars, allaccap);
suspvars = bdd_existcomp(suspvars, allaccap);
@ -343,9 +343,9 @@ namespace spot
// Do we need to synchronize any suspended formula?
if (!susp.empty() && !no_susp_product)
for (formula_bdd_map::const_iterator i = susp.begin();
i != susp.end(); ++i)
if ((allaccap & i->second) == allaccap)
res = susp_prod(res, i->first, i->second);
i != susp.end(); ++i)
if ((allaccap & i->second) == allaccap)
res = susp_prod(res, i->first, i->second);
return res;
}

View file

@ -50,7 +50,7 @@ namespace spot
/// spot::translator class instead.
SPOT_API twa_graph_ptr
compsusp(formula f, const bdd_dict_ptr& dict,
bool no_wdba = false, bool no_simulation = false,
bool early_susp = false, bool no_susp_product = false,
bool wdba_smaller = false, bool oblig = false);
bool no_wdba = false, bool no_simulation = false,
bool early_susp = false, bool no_susp_product = false,
bool wdba_smaller = false, bool oblig = false);
}

View file

@ -38,8 +38,8 @@ namespace spot
std::set<unsigned>* incomplete = nullptr;
if (preserve_names)
{
names = new std::vector<std::string>;
out->set_named_prop("state-names", names);
names = new std::vector<std::string>;
out->set_named_prop("state-names", names);
}
// States already seen.
@ -49,59 +49,59 @@ namespace spot
auto new_state = [&](const state* s) -> unsigned
{
auto p = seen.emplace(s, 0);
if (p.second)
{
p.first->second = out->new_state();
todo.push_back(p.first);
if (names)
names->push_back(aut->format_state(s));
}
else
{
s->destroy();
}
return p.first->second;
auto p = seen.emplace(s, 0);
if (p.second)
{
p.first->second = out->new_state();
todo.push_back(p.first);
if (names)
names->push_back(aut->format_state(s));
}
else
{
s->destroy();
}
return p.first->second;
};
out->set_init_state(new_state(aut->get_init_state()));
while (!todo.empty())
{
const state* src1;
unsigned src2;
std::tie(src1, src2) = *todo.front();
todo.pop_front();
for (auto* t: aut->succ(src1))
{
if (SPOT_UNLIKELY(max_states < out->num_states()))
{
// If we have reached the max number of state, never try
// to create a new one.
auto i = seen.find(t->dst());
if (i == seen.end())
{
if (!incomplete)
incomplete = new std::set<unsigned>;
incomplete->insert(src2);
continue;
}
out->new_edge(src2, i->second, t->cond(), t->acc());
}
else
{
out->new_edge(src2, new_state(t->dst()), t->cond(), t->acc());
}
}
const state* src1;
unsigned src2;
std::tie(src1, src2) = *todo.front();
todo.pop_front();
for (auto* t: aut->succ(src1))
{
if (SPOT_UNLIKELY(max_states < out->num_states()))
{
// If we have reached the max number of state, never try
// to create a new one.
auto i = seen.find(t->dst());
if (i == seen.end())
{
if (!incomplete)
incomplete = new std::set<unsigned>;
incomplete->insert(src2);
continue;
}
out->new_edge(src2, i->second, t->cond(), t->acc());
}
else
{
out->new_edge(src2, new_state(t->dst()), t->cond(), t->acc());
}
}
}
auto s = seen.begin();
while (s != seen.end())
{
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
}
if (incomplete)

View file

@ -46,21 +46,21 @@ namespace spot
while (!q.empty())
{
y = q.back();
q.pop_back();
y = q.back();
q.pop_back();
info_[y].mark = false;
for (auto x: info_[y].b)
{
assert(info_[x].seen);
// insert y in A(x)
info_[x].del[y] = false;
// unmark x recursively if marked
if (info_[x].mark)
q.push_back(x);
}
// empty B(y)
info_[y].b.clear();
info_[y].mark = false;
for (auto x: info_[y].b)
{
assert(info_[x].seen);
// insert y in A(x)
info_[x].del[y] = false;
// unmark x recursively if marked
if (info_[x].mark)
q.push_back(x);
}
// empty B(y)
info_[y].b.clear();
}
}
@ -84,57 +84,57 @@ namespace spot
while (keep_going && !dfs_.empty())
{
dfs_entry& cur = dfs_.back();
if (cur.succ == 0)
cur.succ = aut_->get_graph().state_storage(cur.s).succ;
else
cur.succ = aut_->edge_storage(cur.succ).next_succ;
if (cur.succ)
{
// Explore one successor.
dfs_entry& cur = dfs_.back();
if (cur.succ == 0)
cur.succ = aut_->get_graph().state_storage(cur.s).succ;
else
cur.succ = aut_->edge_storage(cur.succ).next_succ;
if (cur.succ)
{
// Explore one successor.
// Ignore those that are not on the SCC, or destination
// that have been "virtually" deleted from A(v).
unsigned s = aut_->edge_storage(cur.succ).dst;
// Ignore those that are not on the SCC, or destination
// that have been "virtually" deleted from A(v).
unsigned s = aut_->edge_storage(cur.succ).dst;
if ((sm_.scc_of(s) != scc) || (info_[cur.s].del[s]))
continue;
if ((sm_.scc_of(s) != scc) || (info_[cur.s].del[s]))
continue;
info_[s].seen = true;
if (!info_[s].mark)
{
push_state(s);
}
else if (!info_[s].reach)
{
keep_going = cycle_found(s);
cur.f = true;
}
else
{
nocycle(cur.s, s);
}
}
else
{
// No more successors.
bool f = cur.f;
unsigned v = cur.s;
info_[s].seen = true;
if (!info_[s].mark)
{
push_state(s);
}
else if (!info_[s].reach)
{
keep_going = cycle_found(s);
cur.f = true;
}
else
{
nocycle(cur.s, s);
}
}
else
{
// No more successors.
bool f = cur.f;
unsigned v = cur.s;
dfs_.pop_back();
if (f)
unmark(v);
info_[v].reach = true;
dfs_.pop_back();
if (f)
unmark(v);
info_[v].reach = true;
// Update the predecessor in the stack if there is one.
if (!dfs_.empty())
{
if (f)
dfs_.back().f = true;
else
nocycle(dfs_.back().s, v);
}
}
// Update the predecessor in the stack if there is one.
if (!dfs_.empty())
{
if (f)
dfs_.back().f = true;
else
nocycle(dfs_.back().s, v);
}
}
}
// Purge the dfs_ stack, in case we aborted because cycle_found()
@ -150,8 +150,8 @@ namespace spot
++i;
do
{
std::cout << i->s << ' ';
++i;
std::cout << i->s << ' ';
++i;
}
while (i != dfs_.end());
std::cout << '\n';

View file

@ -35,7 +35,7 @@ namespace spot
title = {Enumerating the Cycles of a Digraph: A New
Preprocessing Strategy},
journal = {Information Sciences},
year = {1982},
year = {1982},
volume = {27},
number = {3},
pages = {163--182},
@ -80,7 +80,7 @@ namespace spot
struct state_info
{
state_info(unsigned num)
: seen(false), reach(false), mark(false), del(num)
: seen(false), reach(false), mark(false), del(num)
{
}
bool seen;

View file

@ -61,66 +61,66 @@ namespace spot
{
const_twa_graph_ptr a_;
typedef std::tuple<acc_cond::mark_t,
acc_cond::mark_t,
bool> cache_entry;
acc_cond::mark_t,
bool> cache_entry;
std::vector<cache_entry> cache_;
const scc_info* sm_;
void fill_cache(unsigned s)
{
unsigned s1 = sm_ ? sm_->scc_of(s) : 0;
acc_cond::mark_t common = a_->acc().all_sets();
unsigned s1 = sm_ ? sm_->scc_of(s) : 0;
acc_cond::mark_t common = a_->acc().all_sets();
acc_cond::mark_t union_ = 0U;
bool has_acc_self_loop = false;
bool seen = false;
for (auto& t: a_->out(s))
bool has_acc_self_loop = false;
bool seen = false;
for (auto& t: a_->out(s))
{
// Ignore edges that leave the SCC of s.
unsigned d = t.dst;
unsigned s2 = sm_ ? sm_->scc_of(d) : 0;
if (s2 != s1)
continue;
// Ignore edges that leave the SCC of s.
unsigned d = t.dst;
unsigned s2 = sm_ ? sm_->scc_of(d) : 0;
if (s2 != s1)
continue;
common &= t.acc;
union_ |= t.acc;
// an accepting self-loop?
has_acc_self_loop |= (t.dst == s) && a_->acc().accepting(t.acc);
seen = true;
// an accepting self-loop?
has_acc_self_loop |= (t.dst == s) && a_->acc().accepting(t.acc);
seen = true;
}
if (!seen)
common = 0U;
if (!seen)
common = 0U;
cache_[s] = std::make_tuple(common, union_, has_acc_self_loop);
}
public:
outgoing_acc(const const_twa_graph_ptr& a, const scc_info* sm):
a_(a), cache_(a->num_states()), sm_(sm)
a_(a), cache_(a->num_states()), sm_(sm)
{
unsigned n = a->num_states();
for (unsigned s = 0; s < n; ++s)
fill_cache(s);
unsigned n = a->num_states();
for (unsigned s = 0; s < n; ++s)
fill_cache(s);
}
// Intersection of all outgoing acceptance sets
acc_cond::mark_t common_acc(unsigned s)
{
assert(s < cache_.size());
return std::get<0>(cache_[s]);
assert(s < cache_.size());
return std::get<0>(cache_[s]);
}
// Union of all outgoing acceptance sets
acc_cond::mark_t union_acc(unsigned s)
{
assert(s < cache_.size());
return std::get<1>(cache_[s]);
assert(s < cache_.size());
return std::get<1>(cache_[s]);
}
// Has an accepting self-loop
bool has_acc_selfloop(unsigned s)
{
assert(s < cache_.size());
return std::get<2>(cache_[s]);
assert(s < cache_.size());
return std::get<2>(cache_[s]);
}
};
@ -134,20 +134,20 @@ namespace spot
unsigned
next_level(int slevel, acc_cond::mark_t set, bool skip_levels)
{
// Update the order with any new set we discover
if (auto newsets = set - found_)
{
newsets.fill(std::back_inserter(order_));
found_ |= newsets;
}
// Update the order with any new set we discover
if (auto newsets = set - found_)
{
newsets.fill(std::back_inserter(order_));
found_ |= newsets;
}
unsigned next = slevel;
while (next < order_.size() && set.has(order_[next]))
{
++next;
if (!skip_levels)
break;
}
{
++next;
if (!skip_levels)
break;
}
return next;
}
@ -156,7 +156,7 @@ namespace spot
{
std::cout << "Order_" << scc << ":\t";
for (auto i: order_)
std::cout << i << ", ";
std::cout << i << ", ";
std::cout << '\n';
}
};
@ -169,7 +169,7 @@ namespace spot
public:
scc_orders(bool skip_levels):
skip_levels_(skip_levels)
skip_levels_(skip_levels)
{
}
@ -191,12 +191,12 @@ namespace spot
template<bool want_sba>
twa_graph_ptr
degeneralize_aux(const const_twa_graph_ptr& a, bool use_z_lvl,
bool use_cust_acc_orders, int use_lvl_cache,
bool skip_levels, bool ignaccsl)
bool use_cust_acc_orders, int use_lvl_cache,
bool skip_levels, bool ignaccsl)
{
if (!a->acc().is_generalized_buchi())
throw std::runtime_error
("degeneralize() can only works with generalized Büchi acceptance");
throw std::runtime_error
("degeneralize() can only works with generalized Büchi acceptance");
bool use_scc = use_lvl_cache || use_cust_acc_orders || use_z_lvl;
@ -207,7 +207,7 @@ namespace spot
res->copy_ap_of(a);
res->set_buchi();
if (want_sba)
res->prop_state_acc(true);
res->prop_state_acc(true);
// Preserve determinism, weakness, and stutter-invariance
res->prop_copy(a, { false, true, true, true });
@ -218,17 +218,17 @@ namespace spot
// denote accepting states.
std::vector<unsigned> order;
{
// FIXME: revisit this comment once everything compiles again.
//
// The order is arbitrary, but it turns out that using push_back
// instead of push_front often gives better results because
// acceptance sets at the beginning if the cycle are more often
// used in the automaton. (This surprising fact is probably
// related to the order in which we declare the BDD variables
// during the translation.)
unsigned n = a->num_sets();
for (unsigned i = n; i > 0; --i)
order.push_back(i - 1);
// FIXME: revisit this comment once everything compiles again.
//
// The order is arbitrary, but it turns out that using push_back
// instead of push_front often gives better results because
// acceptance sets at the beginning if the cycle are more often
// used in the automaton. (This surprising fact is probably
// related to the order in which we declare the BDD variables
// during the translation.)
unsigned n = a->num_sets();
for (unsigned i = n; i > 0; --i)
order.push_back(i - 1);
}
// Initialize scc_orders
@ -255,7 +255,7 @@ namespace spot
// Compute SCCs in order to use any optimization.
scc_info* m = nullptr;
if (use_scc)
m = new scc_info(a);
m = new scc_info(a);
// Cache for common outgoing acceptances.
outgoing_acc outgoing(a, m);
@ -266,27 +266,27 @@ namespace spot
// least one accepting self-loop, start the degeneralization on
// the accepting level.
if (want_sba && !ignaccsl && outgoing.has_acc_selfloop(s.first))
s.second = order.size();
s.second = order.size();
// Otherwise, check for acceptance conditions common to all
// outgoing edges, and assume we have already seen these and
// start on the associated level.
if (s.second == 0)
{
auto set = outgoing.common_acc(s.first);
if (use_cust_acc_orders)
s.second = orders.next_level(m->initial(), s.second, set);
else
while (s.second < order.size()
&& set.has(order[s.second]))
{
++s.second;
if (!skip_levels)
break;
}
// There is not accepting level for TBA, let reuse level 0.
if (!want_sba && s.second == order.size())
s.second = 0;
}
{
auto set = outgoing.common_acc(s.first);
if (use_cust_acc_orders)
s.second = orders.next_level(m->initial(), s.second, set);
else
while (s.second < order.size()
&& set.has(order[s.second]))
{
++s.second;
if (!skip_levels)
break;
}
// There is not accepting level for TBA, let reuse level 0.
if (!want_sba && s.second == order.size())
s.second = 0;
}
ds2num[s] = res->new_state();
todo.push_back(s);
@ -297,249 +297,249 @@ namespace spot
// If such state exists level from chache is used.
// If not, a new level (starting with 0) is computed.
if (use_lvl_cache)
lvl_cache[s.first] = std::make_pair(s.second, true);
lvl_cache[s.first] = std::make_pair(s.second, true);
while (!todo.empty())
{
s = todo.front();
todo.pop_front();
int src = ds2num[s];
unsigned slevel = s.second;
{
s = todo.front();
todo.pop_front();
int src = ds2num[s];
unsigned slevel = s.second;
// If we have a state on the last level, it should be accepting.
bool is_acc = slevel == order.size();
// On the accepting level, start again from level 0.
if (want_sba && is_acc)
slevel = 0;
// If we have a state on the last level, it should be accepting.
bool is_acc = slevel == order.size();
// On the accepting level, start again from level 0.
if (want_sba && is_acc)
slevel = 0;
// Check SCC for state s
int s_scc = -1;
if (use_scc)
s_scc = m->scc_of(s.first);
// Check SCC for state s
int s_scc = -1;
if (use_scc)
s_scc = m->scc_of(s.first);
for (auto& i: a->out(s.first))
{
degen_state d(i.dst, 0);
for (auto& i: a->out(s.first))
{
degen_state d(i.dst, 0);
// Check whether the target SCC is accepting
bool is_scc_acc;
int scc;
if (use_scc)
{
scc = m->scc_of(d.first);
is_scc_acc = m->is_accepting_scc(scc);
}
else
{
// If we have no SCC information, treat all SCCs as
// accepting.
scc = -1;
is_scc_acc = true;
}
// Check whether the target SCC is accepting
bool is_scc_acc;
int scc;
if (use_scc)
{
scc = m->scc_of(d.first);
is_scc_acc = m->is_accepting_scc(scc);
}
else
{
// If we have no SCC information, treat all SCCs as
// accepting.
scc = -1;
is_scc_acc = true;
}
// The old level is slevel. What should be the new one?
auto acc = i.acc;
auto otheracc = outgoing.common_acc(d.first);
// The old level is slevel. What should be the new one?
auto acc = i.acc;
auto otheracc = outgoing.common_acc(d.first);
if (want_sba && is_acc)
{
// Ignore the last expected acceptance set (the value of
// prev below) if it is common to all other outgoing
// edges (of the current state) AND if it is not
// used by any outgoing edge of the destination
// state.
//
// 1) It's correct to do that, because this acceptance
// set is common to other outgoing edges.
// Therefore if we make a cycle to this state we
// will eventually see that acceptance set thanks
// to the "pulling" of the common acceptance sets
// of the destination state (d.first).
//
// 2) It's also desirable because it makes the
// degeneralization idempotent (up to a renaming
// of states). Consider the following automaton
// where 1 is initial and => marks accepting
// edges: 1=>1, 1=>2, 2->2, 2->1. This is
// already an SBA, with 1 as accepting state.
// However if you try degeralize it without
// ignoring *prev, you'll get two copies of state
// 2, depending on whether we reach it using 1=>2
// or from 2->2. If this example was not clear,
// play with the "degenid.test" test case.
//
// 3) Ignoring all common acceptance sets would also
// be correct, but it would make the
// degeneralization produce larger automata in some
// cases. The current condition to ignore only one
// acceptance set if is this not used by the next
// state is a heuristic that is compatible with
// point 2) above while not causing more states to
// be generated in our benchmark of 188 formulae
// from the literature.
if (!order.empty())
{
unsigned prev = order.size() - 1;
auto common = outgoing.common_acc(s.first);
if (common.has(order[prev]))
{
auto u = outgoing.union_acc(d.first);
if (!u.has(order[prev]))
acc -= a->acc().mark(order[prev]);
}
}
}
// A edge in the SLEVEL acceptance set should
// be directed to the next acceptance set. If the
// current edge is also in the next acceptance
// set, then go to the one after, etc.
//
// See Denis Oddoux's PhD thesis for a nice
// explanation (in French).
// @PhDThesis{ oddoux.03.phd,
// author = {Denis Oddoux},
// title = {Utilisation des automates alternants pour un
// model-checking efficace des logiques
// temporelles lin{\'e}aires.},
// school = {Universit{\'e}e Paris 7},
// year = {2003},
// address= {Paris, France},
// month = {December}
// }
if (is_scc_acc)
{
// If lvl_cache is used and switching SCCs, use level
// from cache
if (use_lvl_cache && s_scc != scc
&& lvl_cache[d.first].second)
{
d.second = lvl_cache[d.first].first;
}
else
{
// Complete (or replace) the acceptance sets of
// this link with the acceptance sets common to
// all edges leaving the destination state.
if (s_scc == scc)
acc |= otheracc;
else
acc = otheracc;
if (want_sba && is_acc)
{
// Ignore the last expected acceptance set (the value of
// prev below) if it is common to all other outgoing
// edges (of the current state) AND if it is not
// used by any outgoing edge of the destination
// state.
//
// 1) It's correct to do that, because this acceptance
// set is common to other outgoing edges.
// Therefore if we make a cycle to this state we
// will eventually see that acceptance set thanks
// to the "pulling" of the common acceptance sets
// of the destination state (d.first).
//
// 2) It's also desirable because it makes the
// degeneralization idempotent (up to a renaming
// of states). Consider the following automaton
// where 1 is initial and => marks accepting
// edges: 1=>1, 1=>2, 2->2, 2->1. This is
// already an SBA, with 1 as accepting state.
// However if you try degeralize it without
// ignoring *prev, you'll get two copies of state
// 2, depending on whether we reach it using 1=>2
// or from 2->2. If this example was not clear,
// play with the "degenid.test" test case.
//
// 3) Ignoring all common acceptance sets would also
// be correct, but it would make the
// degeneralization produce larger automata in some
// cases. The current condition to ignore only one
// acceptance set if is this not used by the next
// state is a heuristic that is compatible with
// point 2) above while not causing more states to
// be generated in our benchmark of 188 formulae
// from the literature.
if (!order.empty())
{
unsigned prev = order.size() - 1;
auto common = outgoing.common_acc(s.first);
if (common.has(order[prev]))
{
auto u = outgoing.union_acc(d.first);
if (!u.has(order[prev]))
acc -= a->acc().mark(order[prev]);
}
}
}
// A edge in the SLEVEL acceptance set should
// be directed to the next acceptance set. If the
// current edge is also in the next acceptance
// set, then go to the one after, etc.
//
// See Denis Oddoux's PhD thesis for a nice
// explanation (in French).
// @PhDThesis{ oddoux.03.phd,
// author = {Denis Oddoux},
// title = {Utilisation des automates alternants pour un
// model-checking efficace des logiques
// temporelles lin{\'e}aires.},
// school = {Universit{\'e}e Paris 7},
// year = {2003},
// address= {Paris, France},
// month = {December}
// }
if (is_scc_acc)
{
// If lvl_cache is used and switching SCCs, use level
// from cache
if (use_lvl_cache && s_scc != scc
&& lvl_cache[d.first].second)
{
d.second = lvl_cache[d.first].first;
}
else
{
// Complete (or replace) the acceptance sets of
// this link with the acceptance sets common to
// all edges leaving the destination state.
if (s_scc == scc)
acc |= otheracc;
else
acc = otheracc;
// If use_z_lvl is on, start with level zero 0 when
// switching SCCs
unsigned next = (!use_z_lvl || s_scc == scc) ? slevel : 0;
// If use_z_lvl is on, start with level zero 0 when
// switching SCCs
unsigned next = (!use_z_lvl || s_scc == scc) ? slevel : 0;
// If using custom acc orders, get next level
// for this scc
if (use_cust_acc_orders)
{
d.second = orders.next_level(scc, next, acc);
}
// Else compute level according the global acc order
else
{
// As a heuristic, if we enter the SCC on a
// state that has at least one accepting
// self-loop, start the degeneralization on
// the accepting level.
if (s_scc != scc
&& !ignaccsl
&& outgoing.has_acc_selfloop(d.first))
{
d.second = order.size();
}
else
{
// Consider both the current acceptance
// sets, and the acceptance sets common to
// the outgoing edges of the
// destination state. But don't do
// that if the state is accepting and we
// are not skipping levels.
if (skip_levels || !is_acc)
while (next < order.size()
&& acc.has(order[next]))
{
++next;
if (!skip_levels)
break;
}
d.second = next;
}
}
}
}
// If using custom acc orders, get next level
// for this scc
if (use_cust_acc_orders)
{
d.second = orders.next_level(scc, next, acc);
}
// Else compute level according the global acc order
else
{
// As a heuristic, if we enter the SCC on a
// state that has at least one accepting
// self-loop, start the degeneralization on
// the accepting level.
if (s_scc != scc
&& !ignaccsl
&& outgoing.has_acc_selfloop(d.first))
{
d.second = order.size();
}
else
{
// Consider both the current acceptance
// sets, and the acceptance sets common to
// the outgoing edges of the
// destination state. But don't do
// that if the state is accepting and we
// are not skipping levels.
if (skip_levels || !is_acc)
while (next < order.size()
&& acc.has(order[next]))
{
++next;
if (!skip_levels)
break;
}
d.second = next;
}
}
}
}
// In case we are building a TBA is_acc has to be
// set differently for each edge, and
// we do not need to stay use final level.
if (!want_sba)
{
is_acc = d.second == order.size();
if (is_acc) // The edge is accepting
{
d.second = 0; // Make it go to the first level.
// Skip levels as much as possible.
if (!a->acc().accepting(acc) && !skip_levels)
{
if (use_cust_acc_orders)
{
d.second = orders.next_level(scc, d.second, acc);
}
else
{
while (d.second < order.size() &&
acc.has(order[d.second]))
++d.second;
}
}
}
}
// In case we are building a TBA is_acc has to be
// set differently for each edge, and
// we do not need to stay use final level.
if (!want_sba)
{
is_acc = d.second == order.size();
if (is_acc) // The edge is accepting
{
d.second = 0; // Make it go to the first level.
// Skip levels as much as possible.
if (!a->acc().accepting(acc) && !skip_levels)
{
if (use_cust_acc_orders)
{
d.second = orders.next_level(scc, d.second, acc);
}
else
{
while (d.second < order.size() &&
acc.has(order[d.second]))
++d.second;
}
}
}
}
// Have we already seen this destination?
int dest;
ds2num_map::const_iterator di = ds2num.find(d);
if (di != ds2num.end())
{
dest = di->second;
}
else
{
dest = res->new_state();
ds2num[d] = dest;
todo.push_back(d);
// Insert new state to cache
// Have we already seen this destination?
int dest;
ds2num_map::const_iterator di = ds2num.find(d);
if (di != ds2num.end())
{
dest = di->second;
}
else
{
dest = res->new_state();
ds2num[d] = dest;
todo.push_back(d);
// Insert new state to cache
if (use_lvl_cache)
{
auto lvl = d.second;
if (lvl_cache[d.first].second)
{
if (use_lvl_cache == 3)
lvl = std::max(lvl_cache[d.first].first, lvl);
else if (use_lvl_cache == 2)
lvl = std::min(lvl_cache[d.first].first, lvl);
}
lvl_cache[d.first] = std::make_pair(lvl, true);
}
}
if (use_lvl_cache)
{
auto lvl = d.second;
if (lvl_cache[d.first].second)
{
if (use_lvl_cache == 3)
lvl = std::max(lvl_cache[d.first].first, lvl);
else if (use_lvl_cache == 2)
lvl = std::min(lvl_cache[d.first].first, lvl);
}
lvl_cache[d.first] = std::make_pair(lvl, true);
}
}
unsigned& t = tr_cache[dest * 2 + is_acc];
unsigned& t = tr_cache[dest * 2 + is_acc];
if (t == 0) // Create edge.
t = res->new_acc_edge(src, dest, i.cond, is_acc);
else // Update existing edge.
res->edge_data(t).cond |= i.cond;
}
tr_cache.clear();
}
if (t == 0) // Create edge.
t = res->new_acc_edge(src, dest, i.cond, is_acc);
else // Update existing edge.
res->edge_data(t).cond |= i.cond;
}
tr_cache.clear();
}
#ifdef DEGEN_DEBUG
std::cout << "Orig. order: \t";
for (auto i: order)
{
std::cout << i << ", ";
}
{
std::cout << i << ", ";
}
std::cout << '\n';
orders.print();
#endif
@ -553,7 +553,7 @@ namespace spot
twa_graph_ptr
degeneralize(const const_twa_graph_ptr& a,
bool use_z_lvl, bool use_cust_acc_orders,
bool use_z_lvl, bool use_cust_acc_orders,
int use_lvl_cache, bool skip_levels, bool ignaccsl)
{
// If this already a degeneralized digraph, there is nothing we
@ -562,13 +562,13 @@ namespace spot
return std::const_pointer_cast<twa_graph>(a);
return degeneralize_aux<true>(a, use_z_lvl, use_cust_acc_orders,
use_lvl_cache, skip_levels, ignaccsl);
use_lvl_cache, skip_levels, ignaccsl);
}
twa_graph_ptr
degeneralize_tba(const const_twa_graph_ptr& a,
bool use_z_lvl, bool use_cust_acc_orders,
int use_lvl_cache, bool skip_levels, bool ignaccsl)
bool use_z_lvl, bool use_cust_acc_orders,
int use_lvl_cache, bool skip_levels, bool ignaccsl)
{
// If this already a degeneralized digraph, there is nothing we
// can improve.
@ -576,6 +576,6 @@ namespace spot
return std::const_pointer_cast<twa_graph>(a);
return degeneralize_aux<false>(a, use_z_lvl, use_cust_acc_orders,
use_lvl_cache, skip_levels, ignaccsl);
use_lvl_cache, skip_levels, ignaccsl);
}
}

View file

@ -51,16 +51,16 @@ namespace spot
/// \@{
SPOT_API twa_graph_ptr
degeneralize(const const_twa_graph_ptr& a, bool use_z_lvl = true,
bool use_cust_acc_orders = false,
int use_lvl_cache = 1,
bool skip_levels = true,
bool ignaccsl = false);
bool use_cust_acc_orders = false,
int use_lvl_cache = 1,
bool skip_levels = true,
bool ignaccsl = false);
SPOT_API twa_graph_ptr
degeneralize_tba(const const_twa_graph_ptr& a, bool use_z_lvl = true,
bool use_cust_acc_orders = false,
int use_lvl_cache = 1,
bool skip_levels = true,
bool ignaccsl = false);
bool use_cust_acc_orders = false,
int use_lvl_cache = 1,
bool skip_levels = true,
bool ignaccsl = false);
/// \@}
}

View file

@ -112,16 +112,16 @@ namespace spot
using power_set = std::map<safra_state, int>;
const char* const sub[10] =
{
"\u2080",
"\u2081",
"\u2082",
"\u2083",
"\u2084",
"\u2085",
"\u2086",
"\u2087",
"\u2088",
"\u2089",
"\u2080",
"\u2081",
"\u2082",
"\u2083",
"\u2084",
"\u2085",
"\u2086",
"\u2087",
"\u2088",
"\u2089",
};
std::string subscript(unsigned start)
@ -157,18 +157,18 @@ namespace spot
assert(max_acc < 32);
unsigned mask = (1 << max_acc) - 1;
for (auto& t: aut->edges())
{
t.acc &= mask;
}
{
t.acc &= mask;
}
}
struct compare
{
bool
operator() (const safra_state::safra_node_t& lhs,
const safra_state::safra_node_t& rhs)
const safra_state::safra_node_t& rhs)
{
return lhs.second < rhs.second;
return lhs.second < rhs.second;
}
};
@ -178,7 +178,7 @@ namespace spot
{
std::vector<safra_state::safra_node_t> res;
for (auto& n: nodes)
res.emplace_back(n.first, n.second);
res.emplace_back(n.first, n.second);
std::sort(res.begin(), res.end(), compare());
return res;
}
@ -191,46 +191,46 @@ namespace spot
std::stack<unsigned> s;
bool first = true;
for (auto& n: copy)
{
auto it = n.second.begin();
// Find brace on top of stack in vector
// If brace is not present, then we close it as no other ones of that
// type will be found since we ordered our vector
while (!s.empty())
{
it = std::lower_bound(n.second.begin(), n.second.end(),
s.top());
if (it == n.second.end() || *it != s.top())
{
os << subscript(s.top()) << '}';
s.pop();
}
else
{
if (*it == s.top())
++it;
break;
}
}
// Add new braces
while (it != n.second.end())
{
os << '{' << subscript(*it);
s.push(*it);
++it;
first = true;
}
if (!first)
os << ' ';
os << n.first;
first = false;
}
{
auto it = n.second.begin();
// Find brace on top of stack in vector
// If brace is not present, then we close it as no other ones of that
// type will be found since we ordered our vector
while (!s.empty())
{
it = std::lower_bound(n.second.begin(), n.second.end(),
s.top());
if (it == n.second.end() || *it != s.top())
{
os << subscript(s.top()) << '}';
s.pop();
}
else
{
if (*it == s.top())
++it;
break;
}
}
// Add new braces
while (it != n.second.end())
{
os << '{' << subscript(*it);
s.push(*it);
++it;
first = true;
}
if (!first)
os << ' ';
os << n.first;
first = false;
}
// Finish unwinding stack to print last braces
while (!s.empty())
{
os << subscript(s.top()) << '}';
s.pop();
}
{
os << subscript(s.top()) << '}';
s.pop();
}
return os.str();
}
@ -239,7 +239,7 @@ namespace spot
{
auto res = new std::vector<std::string>(states.size());
for (auto& p: states)
(*res)[p.second] = nodes_to_string(p.first.nodes_);
(*res)[p.second] = nodes_to_string(p.first.nodes_);
return res;
}
@ -250,33 +250,33 @@ namespace spot
safra_state
safra_state::compute_succ(const const_twa_graph_ptr& aut,
const bdd& ap,
const scc_info& scc,
const std::map<int, bdd>& implications,
const std::vector<bool>& is_connected,
bool use_scc,
bool use_simulation) const
const bdd& ap,
const scc_info& scc,
const std::map<int, bdd>& implications,
const std::vector<bool>& is_connected,
bool use_scc,
bool use_simulation) const
{
safra_state ss = safra_state(nb_braces_.size());
for (auto& node: nodes_)
{
for (auto& t: aut->out(node.first))
{
if (!bdd_implies(ap, t.cond))
continue;
// Check if we are leaving the SCC, if so we delete all the
// braces as no cycles can be found with that node
if (use_scc && scc.scc_of(node.first) != scc.scc_of(t.dst))
if (scc.is_accepting_scc(scc.scc_of(t.dst)))
for (auto& t: aut->out(node.first))
{
if (!bdd_implies(ap, t.cond))
continue;
// Check if we are leaving the SCC, if so we delete all the
// braces as no cycles can be found with that node
if (use_scc && scc.scc_of(node.first) != scc.scc_of(t.dst))
if (scc.is_accepting_scc(scc.scc_of(t.dst)))
// Entering accepting SCC so add brace
ss.update_succ({ /* no braces */ }, t.dst, { 0 });
else
// When entering non accepting SCC don't create any braces
ss.update_succ({ /* no braces */ }, t.dst, { /* empty */ });
else
ss.update_succ(node.second, t.dst, t.acc);
assert(ss.nb_braces_.size() == ss.is_green_.size());
}
else
// When entering non accepting SCC don't create any braces
ss.update_succ({ /* no braces */ }, t.dst, { /* empty */ });
else
ss.update_succ(node.second, t.dst, t.acc);
assert(ss.nb_braces_.size() == ss.is_green_.size());
}
}
if (use_simulation)
ss.merge_redundant_states(implications, scc, is_connected);
@ -287,52 +287,52 @@ namespace spot
void
safra_state::compute_succs(const const_twa_graph_ptr& aut,
succs_t& res,
const scc_info& scc,
const std::map<int, bdd>& implications,
const std::vector<bool>& is_connected,
std::unordered_map<bdd, unsigned, bdd_hash>&
bdd2num,
std::vector<bdd>& all_bdds,
bool use_scc,
bool use_simulation,
bool use_stutter) const
succs_t& res,
const scc_info& scc,
const std::map<int, bdd>& implications,
const std::vector<bool>& is_connected,
std::unordered_map<bdd, unsigned, bdd_hash>&
bdd2num,
std::vector<bdd>& all_bdds,
bool use_scc,
bool use_simulation,
bool use_stutter) const
{
for (auto& ap: all_bdds)
{
safra_state ss = *this;
safra_state ss = *this;
if (use_stutter && aut->prop_stutter_invariant())
{
std::vector<color_t> colors;
unsigned int counter = 0;
std::map<safra_state, unsigned int> safra2id;
bool stop = false;
while (!stop)
{
auto pair = safra2id.insert({ss, counter++});
// insert should never fail
assert(pair.second);
ss = ss.compute_succ(aut, ap, scc, implications, is_connected,
use_scc, use_simulation);
colors.push_back(ss.color_);
stop = safra2id.find(ss) != safra2id.end();
}
// Add color of final transition that loops back
colors.push_back(ss.color_);
unsigned int loop_start = safra2id[ss];
for (auto& min: safra2id)
{
if (min.second >= loop_start && ss < min.first)
ss = min.first;
}
ss.color_ = *std::min_element(colors.begin(), colors.end());
}
else
ss = compute_succ(aut, ap, scc, implications, is_connected,
use_scc, use_simulation);
unsigned bdd_idx = bdd2num[ap];
res.emplace_back(ss, bdd_idx);
if (use_stutter && aut->prop_stutter_invariant())
{
std::vector<color_t> colors;
unsigned int counter = 0;
std::map<safra_state, unsigned int> safra2id;
bool stop = false;
while (!stop)
{
auto pair = safra2id.insert({ss, counter++});
// insert should never fail
assert(pair.second);
ss = ss.compute_succ(aut, ap, scc, implications, is_connected,
use_scc, use_simulation);
colors.push_back(ss.color_);
stop = safra2id.find(ss) != safra2id.end();
}
// Add color of final transition that loops back
colors.push_back(ss.color_);
unsigned int loop_start = safra2id[ss];
for (auto& min: safra2id)
{
if (min.second >= loop_start && ss < min.first)
ss = min.first;
}
ss.color_ = *std::min_element(colors.begin(), colors.end());
}
else
ss = compute_succ(aut, ap, scc, implications, is_connected,
use_scc, use_simulation);
unsigned bdd_idx = bdd2num[ap];
res.emplace_back(ss, bdd_idx);
}
}
@ -350,12 +350,12 @@ namespace spot
continue;
// index to see if there is a path from scc2 -> scc1
unsigned idx = scc.scc_count() * scc.scc_of(n2.first) +
scc.scc_of(n1.first);
scc.scc_of(n1.first);
if (bdd_implies(implications.at(n1.first),
implications.at(n2.first)) && !is_connected[idx])
{
to_remove.push_back(n1.first);
}
{
to_remove.push_back(n1.first);
}
}
}
for (auto& n: to_remove)
@ -442,8 +442,8 @@ namespace spot
void
node_helper::truncate_braces(std::vector<brace_t>& braces,
const std::vector<unsigned>& rem_succ_of,
std::vector<size_t>& nb_braces)
const std::vector<unsigned>& rem_succ_of,
std::vector<size_t>& nb_braces)
{
for (unsigned idx = 0; idx < braces.size(); ++idx)
{
@ -582,8 +582,8 @@ namespace spot
twa_graph_ptr
tgba_determinize(const const_twa_graph_ptr& a,
bool pretty_print, bool use_scc,
bool use_simulation, bool use_stutter)
bool pretty_print, bool use_scc,
bool use_simulation, bool use_stutter)
{
if (a->prop_deterministic())
return std::const_pointer_cast<twa_graph>(a);
@ -642,10 +642,10 @@ namespace spot
res->copy_ap_of(aut);
res->prop_copy(aut,
{ false, // state based
false, // inherently_weak
false, // deterministic
true // stutter inv
});
false, // inherently_weak
false, // deterministic
true // stutter inv
});
// Given a safra_state get its associated state in output automata.
// Required to create new edges from 2 safra-state
@ -676,13 +676,13 @@ namespace spot
if (s.first.nodes_.empty())
continue;
auto i = seen.find(s.first);
unsigned dst_num;
if (i != seen.end())
{
dst_num = i->second;
}
else
{
unsigned dst_num;
if (i != seen.end())
{
dst_num = i->second;
}
else
{
dst_num = res->new_state();
todo.push_back(s.first);
seen.insert(std::make_pair(s.first, dst_num));
@ -690,7 +690,7 @@ namespace spot
if (s.first.color_ != -1U)
{
res->new_edge(src_num, dst_num, num2bdd[s.second],
{s.first.color_});
{s.first.color_});
// We only care about green acc which are odd
if (s.first.color_ % 2 == 1)
sets = std::max(s.first.color_ + 1, sets);

View file

@ -74,8 +74,8 @@ namespace spot
/// possible.)
SPOT_API twa_graph_ptr
tgba_determinize(const const_twa_graph_ptr& aut,
bool pretty_print = false,
bool use_scc = true,
bool use_simulation = true,
bool use_stutter = true);
bool pretty_print = false,
bool use_scc = true,
bool use_simulation = true,
bool use_stutter = true);
}

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,6 @@ namespace spot
/// 'a' shows the acceptance, 'k' uses state-based labels if possible.
SPOT_API std::ostream&
print_dot(std::ostream& os,
const const_twa_ptr& g,
const char* options = nullptr);
const const_twa_ptr& g,
const char* options = nullptr);
}

File diff suppressed because it is too large Load diff

View file

@ -41,8 +41,8 @@ namespace spot
/// states is found, a null pointer
SPOT_API twa_graph_ptr
dtba_sat_synthetize(const const_twa_graph_ptr& a,
int target_state_number,
bool state_based = false);
int target_state_number,
bool state_based = false);
/// \brief Attempt to minimize a deterministic TBA with a SAT solver.
///
@ -52,8 +52,8 @@ namespace spot
/// If no smaller TBA exist, this returns a null pointer.
SPOT_API twa_graph_ptr
dtba_sat_minimize(const const_twa_graph_ptr& a,
bool state_based = false,
int max_states = -1);
bool state_based = false,
int max_states = -1);
/// \brief Attempt to minimize a deterministic TBA with a SAT solver.
///
@ -63,6 +63,6 @@ namespace spot
/// If no smaller TBA exist, this returns a null pointer.
SPOT_API twa_graph_ptr
dtba_sat_minimize_dichotomy(const const_twa_graph_ptr& a,
bool state_based = false,
int max_states = -1);
bool state_based = false,
int max_states = -1);
}

File diff suppressed because it is too large Load diff

View file

@ -49,11 +49,11 @@ namespace spot
/// returned.
SPOT_API twa_graph_ptr
dtwa_sat_synthetize(const const_twa_graph_ptr& a,
unsigned target_acc_number,
const acc_cond::acc_code& target_acc,
int target_state_number,
bool state_based = false,
bool colored = false);
unsigned target_acc_number,
const acc_cond::acc_code& target_acc,
int target_state_number,
bool state_based = false,
bool colored = false);
/// \brief Attempt to minimize a deterministic TωA with a SAT solver.
///
@ -63,11 +63,11 @@ namespace spot
/// If no smaller TGBA exists, this returns a null pointer.
SPOT_API twa_graph_ptr
dtwa_sat_minimize(const const_twa_graph_ptr& a,
unsigned target_acc_number,
const acc_cond::acc_code& target_acc,
bool state_based = false,
int max_states = -1,
bool colored = false);
unsigned target_acc_number,
const acc_cond::acc_code& target_acc,
bool state_based = false,
int max_states = -1,
bool colored = false);
/// \brief Attempt to minimize a deterministic TωA with a SAT solver.
///
@ -77,11 +77,11 @@ namespace spot
/// If no smaller TBA exist, this returns a null pointer.
SPOT_API twa_graph_ptr
dtwa_sat_minimize_dichotomy(const const_twa_graph_ptr& a,
unsigned target_acc_number,
const acc_cond::acc_code& target_acc,
bool state_based = false,
int max_states = -1,
bool colored = false);
unsigned target_acc_number,
const acc_cond::acc_code& target_acc,
bool state_based = false,
int max_states = -1,
bool colored = false);
/// \brief High-level interface to SAT-based minimization
///

View file

@ -120,24 +120,24 @@ namespace spot
{
const char* name;
emptiness_check_ptr(*construct)(const const_twa_ptr&,
spot::option_map);
spot::option_map);
unsigned int min_acc;
unsigned int max_acc;
};
ec_algo ec_algos[] =
{
{ "Cou99", couvreur99, 0, -1U },
{ "CVWY90", magic_search, 0, 1 },
{ "GV04", explicit_gv04_check, 0, 1 },
{ "SE05", se05, 0, 1 },
{ "Tau03", explicit_tau03_search, 1, -1U },
{ "Tau03_opt", explicit_tau03_opt_search, 0, -1U },
{ "Cou99", couvreur99, 0, -1U },
{ "CVWY90", magic_search, 0, 1 },
{ "GV04", explicit_gv04_check, 0, 1 },
{ "SE05", se05, 0, 1 },
{ "Tau03", explicit_tau03_search, 1, -1U },
{ "Tau03_opt", explicit_tau03_opt_search, 0, -1U },
};
}
emptiness_check_instantiator::emptiness_check_instantiator(option_map o,
void* i)
void* i)
: o_(o), info_(i)
{
}
@ -171,21 +171,21 @@ namespace spot
option_map o;
if (opt_str)
{
const char* opt_start = opt_str + 1;
const char* opt_end = strchr(opt_start, ')');
if (!opt_end)
{
*err = opt_start;
return nullptr;
}
std::string opt(opt_start, opt_end);
const char* opt_start = opt_str + 1;
const char* opt_end = strchr(opt_start, ')');
if (!opt_end)
{
*err = opt_start;
return nullptr;
}
std::string opt(opt_start, opt_end);
const char* res = o.parse_options(opt.c_str());
if (res)
{
*err = opt.c_str() - res + opt_start;
return nullptr;
}
const char* res = o.parse_options(opt.c_str());
if (res)
{
*err = opt.c_str() - res + opt_start;
return nullptr;
}
}
if (!opt_str)
@ -200,19 +200,19 @@ namespace spot
ec_algo* info = ec_algos;
for (unsigned i = 0; i < sizeof(ec_algos)/sizeof(*ec_algos); ++i, ++info)
if (n == info->name)
{
*err = nullptr;
{
*err = nullptr;
struct emptiness_check_instantiator_aux:
struct emptiness_check_instantiator_aux:
public emptiness_check_instantiator
{
emptiness_check_instantiator_aux(option_map o, void* i):
emptiness_check_instantiator(o, i)
{
}
};
return std::make_shared<emptiness_check_instantiator_aux>(o, info);
}
{
emptiness_check_instantiator_aux(option_map o, void* i):
emptiness_check_instantiator(o, i)
{
}
};
return std::make_shared<emptiness_check_instantiator_aux>(o, info);
}
*err = name;
return nullptr;
}
@ -233,13 +233,13 @@ namespace spot
aut = run.aut;
for (step s : run.prefix)
{
s.s = s.s->clone();
prefix.push_back(s);
s.s = s.s->clone();
prefix.push_back(s);
}
for (step s : run.cycle)
{
s.s = s.s->clone();
cycle.push_back(s);
s.s = s.s->clone();
cycle.push_back(s);
}
}
@ -248,8 +248,8 @@ namespace spot
{
if (&run != this)
{
this->~twa_run();
new(this) twa_run(run);
this->~twa_run();
new(this) twa_run(run);
}
return *this;
}
@ -265,7 +265,7 @@ namespace spot
os << " " << a->format_state(st.s) << "\n | ";
bdd_print_formula(os, d, st.label);
if (st.acc)
os << '\t' << st.acc;
os << '\t' << st.acc;
os << '\n';
};
@ -308,7 +308,7 @@ namespace spot
const state*
search(const state* start, twa_run::steps& l)
{
return this->bfs_steps::search(filter(start), l);
return this->bfs_steps::search(filter(start), l);
}
const state*
@ -358,7 +358,7 @@ namespace spot
do
{
assert(seg != cycle.begin());
--seg;
--seg;
seen_acc |= seg->acc;
}
while (!a->acc().accepting(seen_acc));
@ -372,10 +372,10 @@ namespace spot
assert(seg != cycle.end());
seen_acc |= seg->acc;
twa_run::step st = { seg->s->clone(), seg->label, seg->acc };
res->cycle.push_back(st);
twa_run::step st = { seg->s->clone(), seg->label, seg->acc };
res->cycle.push_back(st);
++seg;
++seg;
}
while (!a->acc().accepting(seen_acc));
segment_next = seg == cycle.end() ? cycle.front().s : seg->s;
@ -388,7 +388,7 @@ namespace spot
const state* s = shpath.search(segment_next->clone(), res->cycle);
ss.clear();
assert(s->compare(segment_start) == 0);
(void)s;
(void)s;
}
// Compute the prefix: it's the shortest path from the initial
@ -396,7 +396,7 @@ namespace spot
// Register all states from the cycle as target of the BFS.
for (twa_run::steps::const_iterator i = res->cycle.begin();
i != res->cycle.end(); ++i)
i != res->cycle.end(); ++i)
ss.insert(i->s);
const state* prefix_start = a->get_init_state();
@ -409,27 +409,27 @@ namespace spot
state_set::const_iterator ps = ss.find(prefix_start);
if (ps != ss.end())
{
// The initial state is on the cycle.
prefix_start->destroy();
cycle_entry_point = *ps;
// The initial state is on the cycle.
prefix_start->destroy();
cycle_entry_point = *ps;
}
else
{
// This initial state is outside the cycle. Compute the prefix.
// This initial state is outside the cycle. Compute the prefix.
cycle_entry_point = shpath.search(prefix_start, res->prefix);
}
// Locate cycle_entry_point on the cycle.
twa_run::steps::iterator cycle_ep_it;
for (cycle_ep_it = res->cycle.begin();
cycle_ep_it != res->cycle.end()
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
cycle_ep_it != res->cycle.end()
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
continue;
assert(cycle_ep_it != res->cycle.end());
// Now shift the cycle so it starts on cycle_entry_point.
res->cycle.splice(res->cycle.end(), res->cycle,
res->cycle.begin(), cycle_ep_it);
res->cycle.begin(), cycle_ep_it);
return res;
}
@ -446,195 +446,195 @@ namespace spot
if (prefix.empty())
{
l = &cycle;
in = "cycle";
if (!debug)
os << "No prefix.\nCycle:\n";
l = &cycle;
in = "cycle";
if (!debug)
os << "No prefix.\nCycle:\n";
}
else
{
l = &prefix;
in = "prefix";
if (!debug)
os << "Prefix:\n";
l = &prefix;
in = "prefix";
if (!debug)
os << "Prefix:\n";
}
twa_run::steps::const_iterator i = l->begin();
if (s->compare(i->s))
{
if (debug)
os << "ERROR: First state of run (in " << in << "): "
<< aut->format_state(i->s)
<< "\ndoes not match initial state of automata: "
<< aut->format_state(s) << '\n';
s->destroy();
return false;
if (debug)
os << "ERROR: First state of run (in " << in << "): "
<< aut->format_state(i->s)
<< "\ndoes not match initial state of automata: "
<< aut->format_state(s) << '\n';
s->destroy();
return false;
}
for (; i != l->end(); ++serial)
{
if (debug)
{
// Keep track of the serial associated to each state so we
// can note duplicate states and make the replay easier to read.
auto o = seen.find(s);
std::ostringstream msg;
if (o != seen.end())
{
for (auto d: o->second)
msg << " == " << d;
o->second.insert(serial);
s->destroy();
s = o->first;
}
else
{
seen[s].insert(serial);
}
os << "state " << serial << " in " << in << msg.str() << ": ";
}
else
{
os << " ";
}
os << aut->format_state(s) << '\n';
if (debug)
{
// Keep track of the serial associated to each state so we
// can note duplicate states and make the replay easier to read.
auto o = seen.find(s);
std::ostringstream msg;
if (o != seen.end())
{
for (auto d: o->second)
msg << " == " << d;
o->second.insert(serial);
s->destroy();
s = o->first;
}
else
{
seen[s].insert(serial);
}
os << "state " << serial << " in " << in << msg.str() << ": ";
}
else
{
os << " ";
}
os << aut->format_state(s) << '\n';
// expected outgoing transition
bdd label = i->label;
acc_cond::mark_t acc = i->acc;
// expected outgoing transition
bdd label = i->label;
acc_cond::mark_t acc = i->acc;
// compute the next expected state
const state* next;
++i;
if (i != l->end())
{
next = i->s;
}
else
{
if (l == &prefix)
{
l = &cycle;
in = "cycle";
i = l->begin();
if (!debug)
os << "Cycle:\n";
}
next = l->begin()->s;
}
// compute the next expected state
const state* next;
++i;
if (i != l->end())
{
next = i->s;
}
else
{
if (l == &prefix)
{
l = &cycle;
in = "cycle";
i = l->begin();
if (!debug)
os << "Cycle:\n";
}
next = l->begin()->s;
}
// browse the actual outgoing transitions
twa_succ_iterator* j = aut->succ_iter(s);
// When not debugging, S is not used as key in SEEN, so we can
// destroy it right now.
if (!debug)
s->destroy();
if (j->first())
do
{
if (j->cond() != label
|| j->acc() != acc)
continue;
// browse the actual outgoing transitions
twa_succ_iterator* j = aut->succ_iter(s);
// When not debugging, S is not used as key in SEEN, so we can
// destroy it right now.
if (!debug)
s->destroy();
if (j->first())
do
{
if (j->cond() != label
|| j->acc() != acc)
continue;
const state* s2 = j->dst();
if (s2->compare(next))
{
s2->destroy();
continue;
}
else
{
s = s2;
break;
}
}
while (j->next());
if (j->done())
{
if (debug)
{
os << "ERROR: no transition with label="
<< bdd_format_formula(aut->get_dict(), label)
<< " and acc=" << aut->acc().format(acc)
<< " leaving state " << serial
<< " for state " << aut->format_state(next) << '\n'
<< "The following transitions leave state " << serial
<< ":\n";
if (j->first())
do
{
const state* s2 = j->dst();
os << " * label="
<< bdd_format_formula(aut->get_dict(),
j->cond())
<< " and acc="
<< (aut->acc().format
(j->acc()))
<< " going to " << aut->format_state(s2) << '\n';
s2->destroy();
}
while (j->next());
}
aut->release_iter(j);
s->destroy();
return false;
}
if (debug)
{
os << "transition with label="
<< bdd_format_formula(aut->get_dict(), label)
<< " and acc=" << aut->acc().format(acc)
<< std::endl;
}
else
{
os << " | ";
bdd_print_formula(os, aut->get_dict(), label);
os << '\t';
aut->acc().format(acc);
os << std::endl;
}
aut->release_iter(j);
const state* s2 = j->dst();
if (s2->compare(next))
{
s2->destroy();
continue;
}
else
{
s = s2;
break;
}
}
while (j->next());
if (j->done())
{
if (debug)
{
os << "ERROR: no transition with label="
<< bdd_format_formula(aut->get_dict(), label)
<< " and acc=" << aut->acc().format(acc)
<< " leaving state " << serial
<< " for state " << aut->format_state(next) << '\n'
<< "The following transitions leave state " << serial
<< ":\n";
if (j->first())
do
{
const state* s2 = j->dst();
os << " * label="
<< bdd_format_formula(aut->get_dict(),
j->cond())
<< " and acc="
<< (aut->acc().format
(j->acc()))
<< " going to " << aut->format_state(s2) << '\n';
s2->destroy();
}
while (j->next());
}
aut->release_iter(j);
s->destroy();
return false;
}
if (debug)
{
os << "transition with label="
<< bdd_format_formula(aut->get_dict(), label)
<< " and acc=" << aut->acc().format(acc)
<< std::endl;
}
else
{
os << " | ";
bdd_print_formula(os, aut->get_dict(), label);
os << '\t';
aut->acc().format(acc);
os << std::endl;
}
aut->release_iter(j);
// Sum acceptance conditions.
//
// (Beware l and i designate the next step to consider.
// Therefore if i is at the beginning of the cycle, `acc'
// contains the acceptance conditions of the last transition
// in the prefix; we should not account it.)
if (l == &cycle && i != l->begin())
{
all_acc |= acc;
if (!all_acc_seen && aut->acc().accepting(all_acc))
{
all_acc_seen = true;
if (debug)
os << "all acceptance conditions ("
<< aut->acc().format(all_acc)
<< ") have been seen\n";
}
}
// Sum acceptance conditions.
//
// (Beware l and i designate the next step to consider.
// Therefore if i is at the beginning of the cycle, `acc'
// contains the acceptance conditions of the last transition
// in the prefix; we should not account it.)
if (l == &cycle && i != l->begin())
{
all_acc |= acc;
if (!all_acc_seen && aut->acc().accepting(all_acc))
{
all_acc_seen = true;
if (debug)
os << "all acceptance conditions ("
<< aut->acc().format(all_acc)
<< ") have been seen\n";
}
}
}
s->destroy();
if (!aut->acc().accepting(all_acc))
{
if (debug)
os << "ERROR: The cycle's acceptance conditions ("
<< aut->acc().format(all_acc)
<< ") do not\nmatch those of the automaton ("
<< aut->acc().format(aut->acc().all_sets())
<< ")\n";
return false;
if (debug)
os << "ERROR: The cycle's acceptance conditions ("
<< aut->acc().format(all_acc)
<< ") do not\nmatch those of the automaton ("
<< aut->acc().format(aut->acc().all_sets())
<< ")\n";
return false;
}
auto o = seen.begin();
while (o != seen.end())
{
// Advance the iterator before deleting the "key" pointer.
const state* ptr = o->first;
++o;
ptr->destroy();
// Advance the iterator before deleting the "key" pointer.
const state* ptr = o->first;
++o;
ptr->destroy();
}
return true;
@ -655,33 +655,33 @@ namespace spot
auto e = l->end();
for (auto i = l->begin(); i != e;)
{
bdd label = i->label;
acc_cond::mark_t acc = i->acc;
unsigned dst;
++i;
if (i != e)
{
dst = a->state_number(i->s);
}
else if (l == &prefix)
{
l = &cycle;
i = l->begin();
e = l->end();
dst = a->state_number(i->s);
}
else
{
dst = a->state_number(l->begin()->s);
}
bdd label = i->label;
acc_cond::mark_t acc = i->acc;
unsigned dst;
++i;
if (i != e)
{
dst = a->state_number(i->s);
}
else if (l == &prefix)
{
l = &cycle;
i = l->begin();
e = l->end();
dst = a->state_number(i->s);
}
else
{
dst = a->state_number(l->begin()->s);
}
for (auto& t: a->out(src))
if (t.dst == dst && t.cond == label && t.acc == acc)
{
(*h)[a->get_graph().index_of_edge(t)] = color;
break;
}
src = dst;
for (auto& t: a->out(src))
if (t.dst == dst && t.cond == label && t.acc == acc)
{
(*h)[a->get_graph().index_of_edge(t)] = color;
break;
}
src = dst;
}
a->set_named_prop("highlight-edges", h);
}
@ -717,7 +717,7 @@ namespace spot
{
// expected outgoing transition
bdd label = i->label;
acc_cond::mark_t acc = i->acc;
acc_cond::mark_t acc = i->acc;
// compute the next expected state
const state* next;
@ -737,9 +737,9 @@ namespace spot
}
// browse the actual outgoing transitions and
// look for next;
const state* the_next = nullptr;
for (auto j: aut->succ(s))
// look for next;
const state* the_next = nullptr;
for (auto j: aut->succ(s))
{
if (j->cond() != label
|| j->acc() != acc)
@ -748,27 +748,27 @@ namespace spot
const state* s2 = j->dst();
if (s2->compare(next) == 0)
{
the_next = s2;
break;
}
s2->destroy();
the_next = s2;
break;
}
s2->destroy();
}
assert(res);
s->destroy();
s = the_next;
s = the_next;
auto p = seen.emplace(next, 0);
if (p.second)
p.first->second = res->new_state();
dst = p.first->second;
auto p = seen.emplace(next, 0);
if (p.second)
p.first->second = res->new_state();
dst = p.first->second;
res->new_edge(src, dst, label, acc);
src = dst;
res->new_edge(src, dst, label, acc);
src = dst;
// Sum acceptance conditions.
if (l == &cycle && i != l->begin())
seen_acc |= acc;
seen_acc |= acc;
}
s->destroy();

View file

@ -78,7 +78,7 @@ namespace spot
{
public:
emptiness_check_result(const const_twa_ptr& a,
option_map o = option_map())
option_map o = option_map())
: a_(a), o_(o)
{
}
@ -126,8 +126,8 @@ namespace spot
/// Notify option updates.
virtual void options_updated(const option_map& old);
const_twa_ptr a_; ///< The automaton.
option_map o_; ///< The options.
const_twa_ptr a_; ///< The automaton.
option_map o_; ///< The options.
};
typedef std::shared_ptr<emptiness_check_result> emptiness_check_result_ptr;
@ -192,8 +192,8 @@ namespace spot
virtual void options_updated(const option_map& old);
protected:
const_twa_ptr a_; ///< The automaton.
option_map o_; ///< The options
const_twa_ptr a_; ///< The automaton.
option_map o_; ///< The options
};
typedef std::shared_ptr<emptiness_check> emptiness_check_ptr;
@ -270,7 +270,7 @@ namespace spot
acc_cond::mark_t acc;
step(const state* s, bdd label, acc_cond::mark_t acc)
: s(s), label(label), acc(acc)
: s(s), label(label), acc(acc)
{
}
step()

View file

@ -75,14 +75,14 @@ namespace spot
seteq(const unsigned_statistics& o)
{
if (!set)
{
for (auto& i: o.stats)
stats[i.first] = (o.*i.second)();
set = true;
return true;
}
{
for (auto& i: o.stats)
stats[i.first] = (o.*i.second)();
set = true;
return true;
}
if (*this == o)
return true;
return true;
return false;
}
@ -94,13 +94,13 @@ namespace spot
operator==(const unsigned_statistics_copy& o) const
{
for (auto& i: stats)
{
auto i2 = o.stats.find(i.first);
if (i2 == o.stats.end())
return false;
if (i.second != i2->second)
return false;
}
{
auto i2 = o.stats.find(i.first);
if (i2 == o.stats.end())
return false;
if (i.second != i2->second)
return false;
}
return true;
}
@ -125,13 +125,13 @@ namespace spot
: states_(0), transitions_(0), depth_(0), max_depth_(0)
{
stats["states"] =
static_cast<unsigned_statistics::unsigned_fun>(&ec_statistics::states);
static_cast<unsigned_statistics::unsigned_fun>(&ec_statistics::states);
stats["transitions"] =
static_cast<unsigned_statistics::unsigned_fun>
(&ec_statistics::transitions);
static_cast<unsigned_statistics::unsigned_fun>
(&ec_statistics::transitions);
stats["max. depth"] =
static_cast<unsigned_statistics::unsigned_fun>
(&ec_statistics::max_depth);
static_cast<unsigned_statistics::unsigned_fun>
(&ec_statistics::max_depth);
}
void
@ -157,7 +157,7 @@ namespace spot
{
depth_ += n;
if (depth_ > max_depth_)
max_depth_ = depth_;
max_depth_ = depth_;
}
void
@ -192,10 +192,10 @@ namespace spot
}
private :
unsigned states_; /// number of disctint visited states
unsigned transitions_; /// number of visited transitions
unsigned depth_; /// maximal depth of the stack(s)
unsigned max_depth_; /// maximal depth of the stack(s)
unsigned states_; /// number of disctint visited states
unsigned transitions_; /// number of visited transitions
unsigned depth_; /// maximal depth of the stack(s)
unsigned max_depth_; /// maximal depth of the stack(s)
};
/// \brief Accepting Run Search statistics.
@ -210,11 +210,11 @@ namespace spot
: prefix_states_(0), cycle_states_(0)
{
stats["(non unique) states for prefix"] =
static_cast<unsigned_statistics::unsigned_fun>
(&ars_statistics::ars_prefix_states);
static_cast<unsigned_statistics::unsigned_fun>
(&ars_statistics::ars_prefix_states);
stats["(non unique) states for cycle"] =
static_cast<unsigned_statistics::unsigned_fun>
(&ars_statistics::ars_cycle_states);
static_cast<unsigned_statistics::unsigned_fun>
(&ars_statistics::ars_cycle_states);
}
void
@ -242,8 +242,8 @@ namespace spot
}
private:
unsigned prefix_states_; /// states visited to construct the prefix
unsigned cycle_states_; /// states visited to construct the cycle
unsigned prefix_states_; /// states visited to construct the prefix
unsigned cycle_states_; /// states visited to construct the cycle
};
/// \brief Accepting Cycle Search Space statistics
@ -257,8 +257,8 @@ namespace spot
acss_statistics()
{
stats["search space states"] =
static_cast<unsigned_statistics::unsigned_fun>
(&acss_statistics::acss_states);
static_cast<unsigned_statistics::unsigned_fun>
(&acss_statistics::acss_states);
}
virtual

View file

@ -32,8 +32,8 @@ namespace spot
{
public:
shortest_path(const state_set* t,
const std::shared_ptr<const couvreur99_check_status>& ecs,
couvreur99_check_result* r)
const std::shared_ptr<const couvreur99_check_status>& ecs,
couvreur99_check_result* r)
: bfs_steps(ecs->aut), target(t), ecs(ecs), r(r)
{
}
@ -41,22 +41,22 @@ namespace spot
const state*
search(const state* start, twa_run::steps& l)
{
return this->bfs_steps::search(filter(start), l);
return this->bfs_steps::search(filter(start), l);
}
const state*
filter(const state* s)
{
r->inc_ars_prefix_states();
auto i = ecs->h.find(s);
s->destroy();
// Ignore unknown states ...
if (i == ecs->h.end())
return nullptr;
// ... as well as dead states.
if (i->second == -1)
return nullptr;
return i->first;
r->inc_ars_prefix_states();
auto i = ecs->h.find(s);
s->destroy();
// Ignore unknown states ...
if (i == ecs->h.end())
return nullptr;
// ... as well as dead states.
if (i->second == -1)
return nullptr;
return i->first;
}
bool
@ -87,7 +87,7 @@ namespace spot
unsigned count = 0;
for (auto i: ecs_->h)
if (i.second >= scc_root)
++count;
++count;
return count;
}
@ -107,7 +107,7 @@ namespace spot
// Register all states from the cycle as target of the BFS.
state_set ss;
for (twa_run::steps::const_iterator i = run_->cycle.begin();
i != run_->cycle.end(); ++i)
i != run_->cycle.end(); ++i)
ss.insert(i->s);
shortest_path shpath(&ss, ecs_, this);
@ -121,27 +121,27 @@ namespace spot
state_set::const_iterator ps = ss.find(prefix_start);
if (ps != ss.end())
{
// The initial state is on the cycle.
prefix_start->destroy();
cycle_entry_point = *ps;
// The initial state is on the cycle.
prefix_start->destroy();
cycle_entry_point = *ps;
}
else
{
// This initial state is outside the cycle. Compute the prefix.
// This initial state is outside the cycle. Compute the prefix.
cycle_entry_point = shpath.search(prefix_start, run_->prefix);
}
// Locate cycle_entry_point on the cycle.
twa_run::steps::iterator cycle_ep_it;
for (cycle_ep_it = run_->cycle.begin();
cycle_ep_it != run_->cycle.end()
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
cycle_ep_it != run_->cycle.end()
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
continue;
assert(cycle_ep_it != run_->cycle.end());
// Now shift the cycle so it starts on cycle_entry_point.
run_->cycle.splice(run_->cycle.end(), run_->cycle,
run_->cycle.begin(), cycle_ep_it);
run_->cycle.begin(), cycle_ep_it);
return run_;
}
@ -157,68 +157,68 @@ namespace spot
//
// This idea is taken from Product<T>::findWitness in LBTT 1.1.2,
// which in turn is probably inspired from
// @Article{ latvala.00.fi,
// author = {Timo Latvala and Keijo Heljanko},
// title = {Coping With Strong Fairness},
// journal = {Fundamenta Informaticae},
// year = {2000},
// volume = {43},
// number = {1--4},
// pages = {1--19},
// publisher = {IOS Press}
// @Article{ latvala.00.fi,
// author = {Timo Latvala and Keijo Heljanko},
// title = {Coping With Strong Fairness},
// journal = {Fundamenta Informaticae},
// year = {2000},
// volume = {43},
// number = {1--4},
// pages = {1--19},
// publisher = {IOS Press}
// }
const state* substart = ecs_->cycle_seed;
do
{
struct scc_bfs final: bfs_steps
{
const couvreur99_check_status* ecs;
couvreur99_check_result* r;
acc_cond::mark_t& acc_to_traverse;
int scc_root;
struct scc_bfs final: bfs_steps
{
const couvreur99_check_status* ecs;
couvreur99_check_result* r;
acc_cond::mark_t& acc_to_traverse;
int scc_root;
scc_bfs(const couvreur99_check_status* ecs,
couvreur99_check_result* r, acc_cond::mark_t& acc_to_traverse)
: bfs_steps(ecs->aut), ecs(ecs), r(r),
acc_to_traverse(acc_to_traverse),
scc_root(ecs->root.top().index)
{
}
scc_bfs(const couvreur99_check_status* ecs,
couvreur99_check_result* r, acc_cond::mark_t& acc_to_traverse)
: bfs_steps(ecs->aut), ecs(ecs), r(r),
acc_to_traverse(acc_to_traverse),
scc_root(ecs->root.top().index)
{
}
virtual const state*
filter(const state* s) override
{
auto i = ecs->h.find(s);
s->destroy();
// Ignore unknown states.
if (i == ecs->h.end())
return nullptr;
// Stay in the final SCC.
if (i->second < scc_root)
return nullptr;
r->inc_ars_cycle_states();
return i->first;
}
virtual const state*
filter(const state* s) override
{
auto i = ecs->h.find(s);
s->destroy();
// Ignore unknown states.
if (i == ecs->h.end())
return nullptr;
// Stay in the final SCC.
if (i->second < scc_root)
return nullptr;
r->inc_ars_cycle_states();
return i->first;
}
virtual bool
match(twa_run::step& st, const state* s) override
{
acc_cond::mark_t less_acc =
acc_to_traverse - st.acc;
if (less_acc != acc_to_traverse
|| (acc_to_traverse == 0U
&& s == ecs->cycle_seed))
{
acc_to_traverse = less_acc;
return true;
}
return false;
}
virtual bool
match(twa_run::step& st, const state* s) override
{
acc_cond::mark_t less_acc =
acc_to_traverse - st.acc;
if (less_acc != acc_to_traverse
|| (acc_to_traverse == 0U
&& s == ecs->cycle_seed))
{
acc_to_traverse = less_acc;
return true;
}
return false;
}
} b(ecs_.get(), this, acc_to_traverse);
} b(ecs_.get(), this, acc_to_traverse);
substart = b.search(substart, run_->cycle);
assert(substart);
substart = b.search(substart, run_->cycle);
assert(substart);
}
while (acc_to_traverse != 0U || substart != ecs_->cycle_seed);
}

View file

@ -35,8 +35,8 @@ namespace spot
{
public:
couvreur99_check_result(const
std::shared_ptr<const couvreur99_check_status>& ecs,
option_map o = option_map());
std::shared_ptr<const couvreur99_check_status>& ecs,
option_map o = option_map());
virtual twa_run_ptr accepting_run() override;

View file

@ -47,11 +47,11 @@ namespace spot
poprem_ = o.get("poprem", 1);
ecs_ = std::make_shared<couvreur99_check_status>(a);
stats["removed components"] =
static_cast<spot::unsigned_statistics::unsigned_fun>
(&couvreur99_check::get_removed_components);
static_cast<spot::unsigned_statistics::unsigned_fun>
(&couvreur99_check::get_removed_components);
stats["vmsize"] =
static_cast<spot::unsigned_statistics::unsigned_fun>
(&couvreur99_check::get_vmsize);
static_cast<spot::unsigned_statistics::unsigned_fun>
(&couvreur99_check::get_vmsize);
}
couvreur99_check::~couvreur99_check()
@ -80,12 +80,12 @@ namespace spot
// If rem has been updated, removing states is very easy.
if (poprem_)
{
assert(!ecs_->root.rem().empty());
dec_depth(ecs_->root.rem().size());
for (auto i: ecs_->root.rem())
ecs_->h[i] = -1;
// ecs_->root.rem().clear();
return;
assert(!ecs_->root.rem().empty());
dec_depth(ecs_->root.rem().size());
for (auto i: ecs_->root.rem())
ecs_->h[i] = -1;
// ecs_->root.rem().clear();
return;
}
// Remove from H all states which are reachable from state FROM.
@ -102,29 +102,29 @@ namespace spot
for (;;)
{
// Remove each destination of this iterator.
if (i->first())
do
{
inc_transitions();
// Remove each destination of this iterator.
if (i->first())
do
{
inc_transitions();
const state* s = i->dst();
auto j = ecs_->h.find(s);
assert(j != ecs_->h.end());
s->destroy();
const state* s = i->dst();
auto j = ecs_->h.find(s);
assert(j != ecs_->h.end());
s->destroy();
if (j->second != -1)
{
j->second = -1;
to_remove.push(ecs_->aut->succ_iter(j->first));
}
}
while (i->next());
ecs_->aut->release_iter(i);
if (to_remove.empty())
break;
i = to_remove.top();
to_remove.pop();
if (j->second != -1)
{
j->second = -1;
to_remove.push(ecs_->aut->succ_iter(j->first));
}
}
while (i->next());
ecs_->aut->release_iter(i);
if (to_remove.empty())
break;
i = to_remove.top();
to_remove.pop();
}
}
@ -134,10 +134,10 @@ namespace spot
{
auto acc = ecs_->aut->acc();
if (acc.get_acceptance().is_f())
return nullptr;
return nullptr;
if (acc.uses_fin_acceptance())
throw std::runtime_error
("Fin acceptance is not supported by couvreur99()");
throw std::runtime_error
("Fin acceptance is not supported by couvreur99()");
}
// We use five main data in this algorithm:
@ -170,126 +170,126 @@ namespace spot
while (!todo.empty())
{
assert(ecs_->root.size() == arc.size());
assert(ecs_->root.size() == arc.size());
// We are looking at the next successor in SUCC.
twa_succ_iterator* succ = todo.top().second;
// We are looking at the next successor in SUCC.
twa_succ_iterator* succ = todo.top().second;
// If there is no more successor, backtrack.
if (succ->done())
{
// We have explored all successors of state CURR.
const state* curr = todo.top().first;
// If there is no more successor, backtrack.
if (succ->done())
{
// We have explored all successors of state CURR.
const state* curr = todo.top().first;
// Backtrack TODO.
todo.pop();
dec_depth();
// Backtrack TODO.
todo.pop();
dec_depth();
// If poprem is used, fill rem with any component removed,
// so that remove_component() does not have to traverse
// the SCC again.
auto i = ecs_->h.find(curr);
assert(i != ecs_->h.end());
if (poprem_)
{
ecs_->root.rem().push_front(i->first);
inc_depth();
}
// When backtracking the root of an SCC, we must also
// remove that SCC from the ARC/ROOT stacks. We must
// discard from H all reachable states from this SCC.
assert(!ecs_->root.empty());
if (ecs_->root.top().index == i->second)
{
assert(!arc.empty());
arc.pop();
remove_component(curr);
ecs_->root.pop();
}
ecs_->aut->release_iter(succ);
// Do not destroy CURR: it is a key in H.
continue;
}
// If poprem is used, fill rem with any component removed,
// so that remove_component() does not have to traverse
// the SCC again.
auto i = ecs_->h.find(curr);
assert(i != ecs_->h.end());
if (poprem_)
{
ecs_->root.rem().push_front(i->first);
inc_depth();
}
// When backtracking the root of an SCC, we must also
// remove that SCC from the ARC/ROOT stacks. We must
// discard from H all reachable states from this SCC.
assert(!ecs_->root.empty());
if (ecs_->root.top().index == i->second)
{
assert(!arc.empty());
arc.pop();
remove_component(curr);
ecs_->root.pop();
}
ecs_->aut->release_iter(succ);
// Do not destroy CURR: it is a key in H.
continue;
}
// We have a successor to look at.
inc_transitions();
// Fetch the values (destination state, acceptance conditions
// of the arc) we are interested in...
const state* dest = succ->dst();
acc_cond::mark_t acc = succ->acc();
// ... and point the iterator to the next successor, for
// the next iteration.
succ->next();
// We do not need SUCC from now on.
// We have a successor to look at.
inc_transitions();
// Fetch the values (destination state, acceptance conditions
// of the arc) we are interested in...
const state* dest = succ->dst();
acc_cond::mark_t acc = succ->acc();
// ... and point the iterator to the next successor, for
// the next iteration.
succ->next();
// We do not need SUCC from now on.
// Are we going to a new state?
auto p = ecs_->h.emplace(dest, num + 1);
if (p.second)
{
// Yes. Bump number, stack the stack, and register its
// successors for later processing.
ecs_->root.push(++num);
arc.push(acc);
twa_succ_iterator* iter = ecs_->aut->succ_iter(dest);
iter->first();
todo.emplace(dest, iter);
inc_depth();
continue;
}
dest->destroy();
// Are we going to a new state?
auto p = ecs_->h.emplace(dest, num + 1);
if (p.second)
{
// Yes. Bump number, stack the stack, and register its
// successors for later processing.
ecs_->root.push(++num);
arc.push(acc);
twa_succ_iterator* iter = ecs_->aut->succ_iter(dest);
iter->first();
todo.emplace(dest, iter);
inc_depth();
continue;
}
dest->destroy();
// If we have reached a dead component, ignore it.
if (p.first->second == -1)
continue;
// If we have reached a dead component, ignore it.
if (p.first->second == -1)
continue;
// Now this is the most interesting case. We have reached a
// state S1 which is already part of a non-dead SCC. Any such
// non-dead SCC has necessarily been crossed by our path to
// this state: there is a state S2 in our path which belongs
// to this SCC too. We are going to merge all states between
// this S1 and S2 into this SCC.
//
// This merge is easy to do because the order of the SCC in
// ROOT is ascending: we just have to merge all SCCs from the
// top of ROOT that have an index greater to the one of
// the SCC of S2 (called the "threshold").
int threshold = p.first->second;
std::list<const state*> rem;
while (threshold < ecs_->root.top().index)
{
assert(!ecs_->root.empty());
assert(!arc.empty());
acc |= ecs_->root.top().condition;
acc |= arc.top();
rem.splice(rem.end(), ecs_->root.rem());
ecs_->root.pop();
arc.pop();
}
// Note that we do not always have
// threshold == ecs_->root.top().index
// after this loop, the SCC whose index is threshold might have
// been merged with a lower SCC.
// Now this is the most interesting case. We have reached a
// state S1 which is already part of a non-dead SCC. Any such
// non-dead SCC has necessarily been crossed by our path to
// this state: there is a state S2 in our path which belongs
// to this SCC too. We are going to merge all states between
// this S1 and S2 into this SCC.
//
// This merge is easy to do because the order of the SCC in
// ROOT is ascending: we just have to merge all SCCs from the
// top of ROOT that have an index greater to the one of
// the SCC of S2 (called the "threshold").
int threshold = p.first->second;
std::list<const state*> rem;
while (threshold < ecs_->root.top().index)
{
assert(!ecs_->root.empty());
assert(!arc.empty());
acc |= ecs_->root.top().condition;
acc |= arc.top();
rem.splice(rem.end(), ecs_->root.rem());
ecs_->root.pop();
arc.pop();
}
// Note that we do not always have
// threshold == ecs_->root.top().index
// after this loop, the SCC whose index is threshold might have
// been merged with a lower SCC.
// Accumulate all acceptance conditions into the merged SCC.
ecs_->root.top().condition |= acc;
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
// Accumulate all acceptance conditions into the merged SCC.
ecs_->root.top().condition |= acc;
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// We have found an accepting SCC.
// Release all iterators in TODO.
while (!todo.empty())
{
ecs_->aut->release_iter(todo.top().second);
todo.pop();
dec_depth();
}
// Use this state to start the computation of an accepting
// cycle.
ecs_->cycle_seed = p.first->first;
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// We have found an accepting SCC.
// Release all iterators in TODO.
while (!todo.empty())
{
ecs_->aut->release_iter(todo.top().second);
todo.pop();
dec_depth();
}
// Use this state to start the computation of an accepting
// cycle.
ecs_->cycle_seed = p.first->first;
set_states(ecs_->states());
return std::make_shared<couvreur99_check_result>(ecs_, options());
}
return std::make_shared<couvreur99_check_result>(ecs_, options());
}
}
// This automaton recognizes no word.
set_states(ecs_->states());
@ -314,20 +314,20 @@ namespace spot
//////////////////////////////////////////////////////////////////////
couvreur99_check_shy::todo_item::todo_item(const state* s, int n,
couvreur99_check_shy* shy)
: s(s), n(n)
couvreur99_check_shy* shy)
: s(s), n(n)
{
for (auto iter: shy->ecs_->aut->succ(s))
{
q.emplace_back(iter->acc(),
iter->dst());
shy->inc_depth();
shy->inc_transitions();
q.emplace_back(iter->acc(),
iter->dst());
shy->inc_depth();
shy->inc_transitions();
}
}
couvreur99_check_shy::couvreur99_check_shy(const const_twa_ptr& a,
option_map o)
option_map o)
: couvreur99_check(a, o), num(1)
{
group_ = o.get("group", 1);
@ -353,17 +353,17 @@ namespace spot
// unless they are used as keys in H.
while (!todo.empty())
{
succ_queue& queue = todo.back().q;
for (auto& q: queue)
{
// Destroy the state if it is a clone of a state in the
// heap or if it is an unknown state.
auto i = ecs_->h.find(q.s);
if (i == ecs_->h.end() || i->first != q.s)
q.s->destroy();
}
dec_depth(todo.back().q.size() + 1);
todo.pop_back();
succ_queue& queue = todo.back().q;
for (auto& q: queue)
{
// Destroy the state if it is a clone of a state in the
// heap or if it is an unknown state.
auto i = ecs_->h.find(q.s);
if (i == ecs_->h.end() || i->first != q.s)
q.s->destroy();
}
dec_depth(todo.back().q.size() + 1);
todo.pop_back();
}
dec_depth(ecs_->root.clear_rem());
assert(depth() == 0);
@ -376,17 +376,17 @@ namespace spot
unsigned pos = 0;
for (auto& ti: todo)
{
++pos;
os << '#' << pos << " s:" << ti.s << " n:" << ti.n
<< " q:{";
for (auto qi = ti.q.begin(); qi != ti.q.end();)
{
os << qi->s;
++qi;
if (qi != ti.q.end())
os << ", ";
}
os << "}\n";
++pos;
os << '#' << pos << " s:" << ti.s << " n:" << ti.n
<< " q:{";
for (auto qi = ti.q.begin(); qi != ti.q.end();)
{
os << qi->s;
++qi;
if (qi != ti.q.end())
os << ", ";
}
os << "}\n";
}
}
@ -396,10 +396,10 @@ namespace spot
{
auto acc = ecs_->aut->acc();
if (acc.get_acceptance().is_f())
return nullptr;
return nullptr;
if (acc.uses_fin_acceptance())
throw std::runtime_error
("Fin acceptance is not supported by couvreur99()");
throw std::runtime_error
("Fin acceptance is not supported by couvreur99()");
}
// Position in the loop seeking known successors.
pos = todo.back().q.begin();
@ -407,202 +407,202 @@ namespace spot
for (;;)
{
#ifdef TRACE
dump_queue();
dump_queue();
#endif
assert(ecs_->root.size() == 1 + arc.size());
assert(ecs_->root.size() == 1 + arc.size());
// Get the successors of the current state.
succ_queue& queue = todo.back().q;
// Get the successors of the current state.
succ_queue& queue = todo.back().q;
// If there is no more successor, backtrack.
if (queue.empty())
{
trace << "backtrack" << std::endl;
// If there is no more successor, backtrack.
if (queue.empty())
{
trace << "backtrack" << std::endl;
// We have explored all successors of state CURR.
const state* curr = todo.back().s;
int index = todo.back().n;
// We have explored all successors of state CURR.
const state* curr = todo.back().s;
int index = todo.back().n;
// Backtrack TODO.
todo.pop_back();
dec_depth();
// Backtrack TODO.
todo.pop_back();
dec_depth();
if (todo.empty())
{
// This automaton recognizes no word.
set_states(ecs_->states());
assert(poprem_ || depth() == 0);
return nullptr;
}
if (todo.empty())
{
// This automaton recognizes no word.
set_states(ecs_->states());
assert(poprem_ || depth() == 0);
return nullptr;
}
pos = todo.back().q.begin();
pos = todo.back().q.begin();
// If poprem is used, fill rem with any component removed,
// so that remove_component() does not have to traverse
// the SCC again.
if (poprem_)
{
auto i = ecs_->h.find(curr);
assert(i != ecs_->h.end());
assert(i->first == curr);
ecs_->root.rem().push_front(i->first);
inc_depth();
}
// If poprem is used, fill rem with any component removed,
// so that remove_component() does not have to traverse
// the SCC again.
if (poprem_)
{
auto i = ecs_->h.find(curr);
assert(i != ecs_->h.end());
assert(i->first == curr);
ecs_->root.rem().push_front(i->first);
inc_depth();
}
// When backtracking the root of an SCC, we must also
// remove that SCC from the ARC/ROOT stacks. We must
// discard from H all reachable states from this SCC.
assert(!ecs_->root.empty());
if (ecs_->root.top().index == index)
{
assert(!arc.empty());
arc.pop();
remove_component(curr);
ecs_->root.pop();
}
continue;
}
// When backtracking the root of an SCC, we must also
// remove that SCC from the ARC/ROOT stacks. We must
// discard from H all reachable states from this SCC.
assert(!ecs_->root.empty());
if (ecs_->root.top().index == index)
{
assert(!arc.empty());
arc.pop();
remove_component(curr);
ecs_->root.pop();
}
continue;
}
// We always make a first pass over the successors of a state
// to check whether it contains some state we have already seen.
// This way we hope to merge the most SCCs before stacking new
// states.
//
// So are we checking for known states ? If yes, POS tells us
// which state we are considering. Otherwise just pick the
// first one.
succ_queue::iterator old;
if (pos == queue.end())
old = queue.begin();
else
old = pos;
if (pos != queue.end())
++pos;
//int* i = sip.second;
// We always make a first pass over the successors of a state
// to check whether it contains some state we have already seen.
// This way we hope to merge the most SCCs before stacking new
// states.
//
// So are we checking for known states ? If yes, POS tells us
// which state we are considering. Otherwise just pick the
// first one.
succ_queue::iterator old;
if (pos == queue.end())
old = queue.begin();
else
old = pos;
if (pos != queue.end())
++pos;
//int* i = sip.second;
successor succ = *old;
trace << "picked state " << succ.s << '\n';
auto i = ecs_->h.find(succ.s);
successor succ = *old;
trace << "picked state " << succ.s << '\n';
auto i = ecs_->h.find(succ.s);
if (i == ecs_->h.end())
{
// It's a new state.
// If we are seeking known states, just skip it.
if (pos != queue.end())
continue;
if (i == ecs_->h.end())
{
// It's a new state.
// If we are seeking known states, just skip it.
if (pos != queue.end())
continue;
trace << "new state\n";
trace << "new state\n";
// Otherwise, number it and stack it so we recurse.
queue.erase(old);
dec_depth();
ecs_->h[succ.s] = ++num;
ecs_->root.push(num);
arc.push(succ.acc);
todo.emplace_back(succ.s, num, this);
pos = todo.back().q.begin();
inc_depth();
continue;
}
// Otherwise, number it and stack it so we recurse.
queue.erase(old);
dec_depth();
ecs_->h[succ.s] = ++num;
ecs_->root.push(num);
arc.push(succ.acc);
todo.emplace_back(succ.s, num, this);
pos = todo.back().q.begin();
inc_depth();
continue;
}
// It's an known state. Use i->first from now on.
succ.s->destroy();
// It's an known state. Use i->first from now on.
succ.s->destroy();
queue.erase(old);
dec_depth();
queue.erase(old);
dec_depth();
// Skip dead states.
if (i->second == -1)
{
trace << "dead state\n";
continue;
}
// Skip dead states.
if (i->second == -1)
{
trace << "dead state\n";
continue;
}
trace << "merging...\n";
trace << "merging...\n";
// Now this is the most interesting case. We have
// reached a state S1 which is already part of a
// non-dead SCC. Any such non-dead SCC has
// necessarily been crossed by our path to this
// state: there is a state S2 in our path which
// belongs to this SCC too. We are going to merge
// all states between this S1 and S2 into this
// SCC.
//
// This merge is easy to do because the order of
// the SCC in ROOT is ascending: we just have to
// merge all SCCs from the top of ROOT that have
// an index greater to the one of the SCC of S2
// (called the "threshold").
int threshold = i->second;
std::list<const state*> rem;
acc_cond::mark_t acc = succ.acc;
while (threshold < ecs_->root.top().index)
{
assert(!ecs_->root.empty());
assert(!arc.empty());
acc |= ecs_->root.top().condition;
acc |= arc.top();
rem.splice(rem.end(), ecs_->root.rem());
ecs_->root.pop();
arc.pop();
}
// Note that we do not always have
// threshold == ecs_->root.top().index
// after this loop, the SCC whose index is threshold
// might have been merged with a lower SCC.
// Now this is the most interesting case. We have
// reached a state S1 which is already part of a
// non-dead SCC. Any such non-dead SCC has
// necessarily been crossed by our path to this
// state: there is a state S2 in our path which
// belongs to this SCC too. We are going to merge
// all states between this S1 and S2 into this
// SCC.
//
// This merge is easy to do because the order of
// the SCC in ROOT is ascending: we just have to
// merge all SCCs from the top of ROOT that have
// an index greater to the one of the SCC of S2
// (called the "threshold").
int threshold = i->second;
std::list<const state*> rem;
acc_cond::mark_t acc = succ.acc;
while (threshold < ecs_->root.top().index)
{
assert(!ecs_->root.empty());
assert(!arc.empty());
acc |= ecs_->root.top().condition;
acc |= arc.top();
rem.splice(rem.end(), ecs_->root.rem());
ecs_->root.pop();
arc.pop();
}
// Note that we do not always have
// threshold == ecs_->root.top().index
// after this loop, the SCC whose index is threshold
// might have been merged with a lower SCC.
// Accumulate all acceptance conditions into the
// merged SCC.
ecs_->root.top().condition |= acc;
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
// Accumulate all acceptance conditions into the
// merged SCC.
ecs_->root.top().condition |= acc;
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
// Have we found all acceptance conditions?
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// Use this state to start the computation of an accepting
// cycle.
ecs_->cycle_seed = i->first;
// Have we found all acceptance conditions?
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// Use this state to start the computation of an accepting
// cycle.
ecs_->cycle_seed = i->first;
// We have found an accepting SCC. Clean up TODO.
clear_todo();
set_states(ecs_->states());
return std::make_shared<couvreur99_check_result>(ecs_, options());
}
// Group the pending successors of formed SCC if requested.
if (group_)
{
assert(todo.back().s);
while (ecs_->root.top().index < todo.back().n)
{
todo_list::reverse_iterator prev = todo.rbegin();
todo_list::reverse_iterator last = prev++;
// If group2 is used we insert the last->q in front
// of prev->q so that the states in prev->q are checked
// for existence again after we have processed the states
// of last->q. Otherwise we just append to the end.
prev->q.splice(group2_ ? prev->q.begin() : prev->q.end(),
last->q);
// We have found an accepting SCC. Clean up TODO.
clear_todo();
set_states(ecs_->states());
return std::make_shared<couvreur99_check_result>(ecs_, options());
}
// Group the pending successors of formed SCC if requested.
if (group_)
{
assert(todo.back().s);
while (ecs_->root.top().index < todo.back().n)
{
todo_list::reverse_iterator prev = todo.rbegin();
todo_list::reverse_iterator last = prev++;
// If group2 is used we insert the last->q in front
// of prev->q so that the states in prev->q are checked
// for existence again after we have processed the states
// of last->q. Otherwise we just append to the end.
prev->q.splice(group2_ ? prev->q.begin() : prev->q.end(),
last->q);
if (poprem_)
{
const state* s = todo.back().s;
auto i = ecs_->h.find(s);
assert(i != ecs_->h.end());
assert(i->first == s);
ecs_->root.rem().push_front(i->first);
// Don't change the stack depth, since
// we are just moving the state from TODO to REM.
}
else
{
dec_depth();
}
todo.pop_back();
}
pos = todo.back().q.begin();
}
if (poprem_)
{
const state* s = todo.back().s;
auto i = ecs_->h.find(s);
assert(i != ecs_->h.end());
assert(i->first == s);
ecs_->root.rem().push_front(i->first);
// Don't change the stack depth, since
// we are just moving the state from TODO to REM.
}
else
{
dec_depth();
}
todo.pop_back();
}
pos = todo.back().q.begin();
}
}
}

View file

@ -221,7 +221,7 @@ namespace spot
{
const state* s;
int n;
succ_queue q; // Unprocessed successors of S
succ_queue q; // Unprocessed successors of S
todo_item(const state* s, int n, couvreur99_check_shy* shy);
};

View file

@ -80,8 +80,8 @@ namespace spot
unsigned n = 0;
for (stack_type::iterator i = s.begin(); i != s.end(); ++i)
{
n += i->rem.size();
i->rem.clear();
n += i->rem.size();
i->rem.clear();
}
return n;
}

View file

@ -35,10 +35,10 @@ namespace spot
auto i = h.begin();
while (i != h.end())
{
// Advance the iterator before deleting the key.
const state* s = i->first;
++i;
s->destroy();
// Advance the iterator before deleting the key.
const state* s = i->first;
++i;
s->destroy();
}
}

View file

@ -45,11 +45,11 @@ namespace spot
{
struct stack_entry
{
const state* s; // State stored in stack entry.
const state* s; // State stored in stack entry.
twa_succ_iterator* lasttr; // Last transition explored from this state.
int lowlink; // Lowlink value if this entry.
int pre; // DFS predecessor.
int acc; // Accepting state link.
int lowlink; // Lowlink value if this entry.
int pre; // DFS predecessor.
int acc; // Accepting state link.
};
struct gv04: public emptiness_check, public ec_statistics
@ -60,342 +60,342 @@ namespace spot
// Stack of visited states on the path.
std::vector<stack_entry> stack;
int top; // Top of SCC stack.
int dftop; // Top of DFS stack.
bool violation; // Whether an accepting run was found.
int top; // Top of SCC stack.
int dftop; // Top of DFS stack.
bool violation; // Whether an accepting run was found.
gv04(const const_twa_ptr& a, option_map o)
: emptiness_check(a, o)
: emptiness_check(a, o)
{
assert(a->num_sets() <= 1);
assert(a->num_sets() <= 1);
}
~gv04()
{
for (auto i: stack)
a_->release_iter(i.lasttr);
auto s = h.begin();
while (s != h.end())
{
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
}
for (auto i: stack)
a_->release_iter(i.lasttr);
auto s = h.begin();
while (s != h.end())
{
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
}
}
virtual emptiness_check_result_ptr
check() override
{
top = dftop = -1;
violation = false;
push(a_->get_init_state(), false);
top = dftop = -1;
violation = false;
push(a_->get_init_state(), false);
while (!violation && dftop >= 0)
{
trace << "Main iteration (top = " << top
<< ", dftop = " << dftop
<< ", s = " << a_->format_state(stack[dftop].s)
<< ')' << std::endl;
while (!violation && dftop >= 0)
{
trace << "Main iteration (top = " << top
<< ", dftop = " << dftop
<< ", s = " << a_->format_state(stack[dftop].s)
<< ')' << std::endl;
twa_succ_iterator* iter = stack[dftop].lasttr;
bool cont;
if (!iter)
{
iter = stack[dftop].lasttr = a_->succ_iter(stack[dftop].s);
cont = iter->first();
}
else
{
cont = iter->next();
}
twa_succ_iterator* iter = stack[dftop].lasttr;
bool cont;
if (!iter)
{
iter = stack[dftop].lasttr = a_->succ_iter(stack[dftop].s);
cont = iter->first();
}
else
{
cont = iter->next();
}
if (!cont)
{
trace << " No more successors" << std::endl;
pop();
}
else
{
const state* s_prime = iter->dst();
bool acc =
a_->acc().accepting(iter->acc());
inc_transitions();
if (!cont)
{
trace << " No more successors" << std::endl;
pop();
}
else
{
const state* s_prime = iter->dst();
bool acc =
a_->acc().accepting(iter->acc());
inc_transitions();
trace << " Next successor: s_prime = "
<< a_->format_state(s_prime)
<< (acc ? " (with accepting link)" : "");
trace << " Next successor: s_prime = "
<< a_->format_state(s_prime)
<< (acc ? " (with accepting link)" : "");
auto i = h.find(s_prime);
auto i = h.find(s_prime);
if (i == h.end())
{
trace << " is a new state." << std::endl;
push(s_prime, acc);
}
else
{
if (i->second < stack.size()
&& stack[i->second].s->compare(s_prime) == 0)
{
// s_prime has a clone on stack
trace << " is on stack." << std::endl;
// This is an addition to GV04 to support TBA.
violation |= acc;
lowlinkupdate(dftop, i->second);
}
else
{
trace << " has been seen, but is no longer on stack."
<< std::endl;
}
if (i == h.end())
{
trace << " is a new state." << std::endl;
push(s_prime, acc);
}
else
{
if (i->second < stack.size()
&& stack[i->second].s->compare(s_prime) == 0)
{
// s_prime has a clone on stack
trace << " is on stack." << std::endl;
// This is an addition to GV04 to support TBA.
violation |= acc;
lowlinkupdate(dftop, i->second);
}
else
{
trace << " has been seen, but is no longer on stack."
<< std::endl;
}
s_prime->destroy();
}
}
set_states(h.size());
}
if (violation)
return std::make_shared<result>(*this);
return nullptr;
s_prime->destroy();
}
}
set_states(h.size());
}
if (violation)
return std::make_shared<result>(*this);
return nullptr;
}
void
push(const state* s, bool accepting)
{
trace << " push(s = " << a_->format_state(s)
<< ", accepting = " << accepting << ")\n";
trace << " push(s = " << a_->format_state(s)
<< ", accepting = " << accepting << ")\n";
h[s] = ++top;
h[s] = ++top;
stack_entry ss = { s, nullptr, top, dftop, 0 };
stack_entry ss = { s, nullptr, top, dftop, 0 };
if (accepting)
ss.acc = top - 1; // This differs from GV04 to support TBA.
else if (dftop >= 0)
ss.acc = stack[dftop].acc;
else
ss.acc = -1;
if (accepting)
ss.acc = top - 1; // This differs from GV04 to support TBA.
else if (dftop >= 0)
ss.acc = stack[dftop].acc;
else
ss.acc = -1;
trace << " s.lowlink = " << top << std::endl
<< " s.acc = " << ss.acc << std::endl;
trace << " s.lowlink = " << top << std::endl
<< " s.acc = " << ss.acc << std::endl;
stack.push_back(ss);
dftop = top;
inc_depth();
stack.push_back(ss);
dftop = top;
inc_depth();
}
void
pop()
{
trace << " pop()\n";
trace << " pop()\n";
int p = stack[dftop].pre;
if (p >= 0)
lowlinkupdate(p, dftop);
if (stack[dftop].lowlink == dftop)
{
assert(static_cast<unsigned int>(top + 1) == stack.size());
for (int i = top; i >= dftop; --i)
{
a_->release_iter(stack[i].lasttr);
stack.pop_back();
dec_depth();
}
top = dftop - 1;
}
dftop = p;
int p = stack[dftop].pre;
if (p >= 0)
lowlinkupdate(p, dftop);
if (stack[dftop].lowlink == dftop)
{
assert(static_cast<unsigned int>(top + 1) == stack.size());
for (int i = top; i >= dftop; --i)
{
a_->release_iter(stack[i].lasttr);
stack.pop_back();
dec_depth();
}
top = dftop - 1;
}
dftop = p;
}
void
lowlinkupdate(int f, int t)
{
trace << " lowlinkupdate(f = " << f << ", t = " << t
<< ")\n t.lowlink = " << stack[t].lowlink
<< "\n f.lowlink = " << stack[f].lowlink
<< "\n f.acc = " << stack[f].acc << '\n';
int stack_t_lowlink = stack[t].lowlink;
if (stack_t_lowlink <= stack[f].lowlink)
{
if (stack_t_lowlink <= stack[f].acc)
violation = true;
stack[f].lowlink = stack_t_lowlink;
trace << " f.lowlink updated to "
<< stack[f].lowlink << '\n';
}
trace << " lowlinkupdate(f = " << f << ", t = " << t
<< ")\n t.lowlink = " << stack[t].lowlink
<< "\n f.lowlink = " << stack[f].lowlink
<< "\n f.acc = " << stack[f].acc << '\n';
int stack_t_lowlink = stack[t].lowlink;
if (stack_t_lowlink <= stack[f].lowlink)
{
if (stack_t_lowlink <= stack[f].acc)
violation = true;
stack[f].lowlink = stack_t_lowlink;
trace << " f.lowlink updated to "
<< stack[f].lowlink << '\n';
}
}
virtual std::ostream&
print_stats(std::ostream& os) const override
{
os << h.size() << " unique states visited\n";
os << transitions() << " transitions explored\n";
os << max_depth() << " items max on stack\n";
return os;
os << h.size() << " unique states visited\n";
os << transitions() << " transitions explored\n";
os << max_depth() << " items max on stack\n";
return os;
}
struct result:
public emptiness_check_result,
public acss_statistics
public emptiness_check_result,
public acss_statistics
{
gv04& data;
gv04& data;
result(gv04& data)
: emptiness_check_result(data.automaton(), data.options()),
data(data)
{
}
result(gv04& data)
: emptiness_check_result(data.automaton(), data.options()),
data(data)
{
}
void
update_lowlinks()
{
// Transitively update the lowlinks, so we can use them in
// to check SCC inclusion
for (int i = 0; i <= data.top; ++i)
{
int l = data.stack[i].lowlink;
if (l < i)
{
int ll = data.stack[i].lowlink = data.stack[l].lowlink;
for (int j = i - 1; data.stack[j].lowlink != ll; --j)
data.stack[j].lowlink = ll;
}
}
}
void
update_lowlinks()
{
// Transitively update the lowlinks, so we can use them in
// to check SCC inclusion
for (int i = 0; i <= data.top; ++i)
{
int l = data.stack[i].lowlink;
if (l < i)
{
int ll = data.stack[i].lowlink = data.stack[l].lowlink;
for (int j = i - 1; data.stack[j].lowlink != ll; --j)
data.stack[j].lowlink = ll;
}
}
}
virtual unsigned
acss_states() const override
{
// Gross!
const_cast<result*>(this)->update_lowlinks();
virtual unsigned
acss_states() const override
{
// Gross!
const_cast<result*>(this)->update_lowlinks();
int scc = data.stack[data.dftop].lowlink;
int j = data.dftop;
int s = 0;
while (j >= 0 && data.stack[j].lowlink == scc)
{
--j;
++s;
}
assert(s > 0);
return s;
}
int scc = data.stack[data.dftop].lowlink;
int j = data.dftop;
int s = 0;
while (j >= 0 && data.stack[j].lowlink == scc)
{
--j;
++s;
}
assert(s > 0);
return s;
}
virtual twa_run_ptr
accepting_run() override
{
auto res = std::make_shared<twa_run>(automaton());
virtual twa_run_ptr
accepting_run() override
{
auto res = std::make_shared<twa_run>(automaton());
update_lowlinks();
update_lowlinks();
#ifdef TRACE
for (int i = 0; i <= data.top; ++i)
{
trace << "state " << i << " ("
<< data.a_->format_state(data.stack[i].s)
<< ") has lowlink = " << data.stack[i].lowlink << std::endl;
}
for (int i = 0; i <= data.top; ++i)
{
trace << "state " << i << " ("
<< data.a_->format_state(data.stack[i].s)
<< ") has lowlink = " << data.stack[i].lowlink << std::endl;
}
#endif
// We will use the root of the last SCC as the start of the
// cycle.
int scc_root = data.stack[data.dftop].lowlink;
assert(scc_root >= 0);
// We will use the root of the last SCC as the start of the
// cycle.
int scc_root = data.stack[data.dftop].lowlink;
assert(scc_root >= 0);
// Construct the prefix by unwinding the DFS stack before
// scc_root.
int father = data.stack[scc_root].pre;
while (father >= 0)
{
twa_run::step st =
{
data.stack[father].s->clone(),
data.stack[father].lasttr->cond(),
data.stack[father].lasttr->acc()
};
res->prefix.push_front(st);
father = data.stack[father].pre;
}
// Construct the prefix by unwinding the DFS stack before
// scc_root.
int father = data.stack[scc_root].pre;
while (father >= 0)
{
twa_run::step st =
{
data.stack[father].s->clone(),
data.stack[father].lasttr->cond(),
data.stack[father].lasttr->acc()
};
res->prefix.push_front(st);
father = data.stack[father].pre;
}
// Construct the cycle in two phases. A first BFS finds the
// shortest path from scc_root to an accepting transition.
// A second BFS then search a path back to scc_root. If
// there is no acceptance conditions we just use the second
// BFS to find a cycle around scc_root.
// Construct the cycle in two phases. A first BFS finds the
// shortest path from scc_root to an accepting transition.
// A second BFS then search a path back to scc_root. If
// there is no acceptance conditions we just use the second
// BFS to find a cycle around scc_root.
struct first_bfs: bfs_steps
{
const gv04& data;
int scc_root;
result* r;
struct first_bfs: bfs_steps
{
const gv04& data;
int scc_root;
result* r;
first_bfs(result* r, int scc_root)
: bfs_steps(r->data.automaton()), data(r->data),
scc_root(scc_root), r(r)
{
}
first_bfs(result* r, int scc_root)
: bfs_steps(r->data.automaton()), data(r->data),
scc_root(scc_root), r(r)
{
}
virtual const state*
filter(const state* s) override
{
// Do not escape the SCC
auto j = data.h.find(s);
if (// This state was never visited so far.
j == data.h.end()
// Or it was discarded
|| j->second >= data.stack.size()
// Or it was discarded (but its stack slot reused)
|| data.stack[j->second].s->compare(s)
// Or it is still on the stack but not in the SCC
|| data.stack[j->second].lowlink < scc_root)
{
s->destroy();
return nullptr;
}
r->inc_ars_cycle_states();
s->destroy();
return j->first;
}
virtual const state*
filter(const state* s) override
{
// Do not escape the SCC
auto j = data.h.find(s);
if (// This state was never visited so far.
j == data.h.end()
// Or it was discarded
|| j->second >= data.stack.size()
// Or it was discarded (but its stack slot reused)
|| data.stack[j->second].s->compare(s)
// Or it is still on the stack but not in the SCC
|| data.stack[j->second].lowlink < scc_root)
{
s->destroy();
return nullptr;
}
r->inc_ars_cycle_states();
s->destroy();
return j->first;
}
virtual bool
match(twa_run::step& step, const state*) override
{
return step.acc != 0U;
}
};
virtual bool
match(twa_run::step& step, const state*) override
{
return step.acc != 0U;
}
};
struct second_bfs final: first_bfs
{
const state* target;
second_bfs(result* r, int scc_root, const state* target)
: first_bfs(r, scc_root), target(target)
{
}
struct second_bfs final: first_bfs
{
const state* target;
second_bfs(result* r, int scc_root, const state* target)
: first_bfs(r, scc_root), target(target)
{
}
virtual bool
match(twa_run::step&, const state* s) override
{
return s == target;
}
};
virtual bool
match(twa_run::step&, const state* s) override
{
return s == target;
}
};
const state* bfs_start = data.stack[scc_root].s;
const state* bfs_end = bfs_start;
if (a_->num_sets() > 0)
{
first_bfs b1(this, scc_root);
bfs_start = b1.search(bfs_start, res->cycle);
assert(bfs_start);
}
if (bfs_start != bfs_end || res->cycle.empty())
{
second_bfs b2(this, scc_root, bfs_end);
bfs_start = b2.search(bfs_start, res->cycle);
assert(bfs_start == bfs_end);
}
const state* bfs_start = data.stack[scc_root].s;
const state* bfs_end = bfs_start;
if (a_->num_sets() > 0)
{
first_bfs b1(this, scc_root);
bfs_start = b1.search(bfs_start, res->cycle);
assert(bfs_start);
}
if (bfs_start != bfs_end || res->cycle.empty())
{
second_bfs b2(this, scc_root, bfs_end);
bfs_start = b2.search(bfs_start, res->cycle);
assert(bfs_start == bfs_end);
}
assert(res->cycle.begin() != res->cycle.end());
return res;
}
assert(res->cycle.begin() != res->cycle.end());
return res;
}
};

View file

@ -62,171 +62,171 @@ namespace spot
sup_map sup;
metadata(const const_twa_graph_ptr& aut, bool implicit,
bool state_labels)
bool state_labels)
{
check_det_and_comp(aut);
use_implicit_labels = implicit && is_deterministic && is_complete;
use_state_labels &= state_labels;
number_all_ap();
check_det_and_comp(aut);
use_implicit_labels = implicit && is_deterministic && is_complete;
use_state_labels &= state_labels;
number_all_ap();
}
std::ostream&
emit_acc(std::ostream& os, acc_cond::mark_t b)
{
// FIXME: We could use a cache for this.
if (b == 0U)
return os;
os << " {";
bool notfirst = false;
for (auto v: b.sets())
{
if (notfirst)
os << ' ';
else
notfirst = true;
os << v;
}
os << '}';
return os;
// FIXME: We could use a cache for this.
if (b == 0U)
return os;
os << " {";
bool notfirst = false;
for (auto v: b.sets())
{
if (notfirst)
os << ' ';
else
notfirst = true;
os << v;
}
os << '}';
return os;
}
void check_det_and_comp(const const_twa_graph_ptr& aut)
{
std::string empty;
std::string empty;
unsigned ns = aut->num_states();
bool deterministic = true;
bool complete = true;
bool state_acc = true;
bool nodeadend = true;
bool colored = aut->num_sets() >= 1;
for (unsigned src = 0; src < ns; ++src)
{
bdd sum = bddfalse;
bdd available = bddtrue;
bool st_acc = true;
bool notfirst = false;
acc_cond::mark_t prev = 0U;
bool has_succ = false;
bdd lastcond = bddfalse;
for (auto& t: aut->out(src))
{
if (has_succ)
use_state_labels &= lastcond == t.cond;
else
lastcond = t.cond;
if (complete)
sum |= t.cond;
if (deterministic)
{
if (!bdd_implies(t.cond, available))
deterministic = false;
else
available -= t.cond;
}
sup.insert(std::make_pair(t.cond, empty));
if (st_acc)
{
if (notfirst && prev != t.acc)
{
st_acc = false;
}
else
{
notfirst = true;
prev = t.acc;
}
}
if (colored)
{
auto a = t.acc;
if (!a || a.remove_some(1))
colored = false;
}
has_succ = true;
}
nodeadend &= has_succ;
if (complete)
complete &= sum == bddtrue;
common_acc.push_back(st_acc);
state_acc &= st_acc;
}
is_deterministic = deterministic;
is_complete = complete;
has_state_acc = state_acc;
// If the automaton has state-based acceptance and contain
// some states without successors do not declare it as
// colored.
is_colored = colored && (!has_state_acc || nodeadend);
// If the automaton declares that it is deterministic or
// state-based, make sure that it really is.
assert(deterministic || aut->prop_deterministic() != true);
assert(state_acc || aut->prop_state_acc() != true);
unsigned ns = aut->num_states();
bool deterministic = true;
bool complete = true;
bool state_acc = true;
bool nodeadend = true;
bool colored = aut->num_sets() >= 1;
for (unsigned src = 0; src < ns; ++src)
{
bdd sum = bddfalse;
bdd available = bddtrue;
bool st_acc = true;
bool notfirst = false;
acc_cond::mark_t prev = 0U;
bool has_succ = false;
bdd lastcond = bddfalse;
for (auto& t: aut->out(src))
{
if (has_succ)
use_state_labels &= lastcond == t.cond;
else
lastcond = t.cond;
if (complete)
sum |= t.cond;
if (deterministic)
{
if (!bdd_implies(t.cond, available))
deterministic = false;
else
available -= t.cond;
}
sup.insert(std::make_pair(t.cond, empty));
if (st_acc)
{
if (notfirst && prev != t.acc)
{
st_acc = false;
}
else
{
notfirst = true;
prev = t.acc;
}
}
if (colored)
{
auto a = t.acc;
if (!a || a.remove_some(1))
colored = false;
}
has_succ = true;
}
nodeadend &= has_succ;
if (complete)
complete &= sum == bddtrue;
common_acc.push_back(st_acc);
state_acc &= st_acc;
}
is_deterministic = deterministic;
is_complete = complete;
has_state_acc = state_acc;
// If the automaton has state-based acceptance and contain
// some states without successors do not declare it as
// colored.
is_colored = colored && (!has_state_acc || nodeadend);
// If the automaton declares that it is deterministic or
// state-based, make sure that it really is.
assert(deterministic || aut->prop_deterministic() != true);
assert(state_acc || aut->prop_state_acc() != true);
}
void number_all_ap()
{
bdd all = bddtrue;
for (auto& i: sup)
all &= bdd_support(i.first);
all_ap = all;
bdd all = bddtrue;
for (auto& i: sup)
all &= bdd_support(i.first);
all_ap = all;
while (all != bddtrue)
{
int v = bdd_var(all);
all = bdd_high(all);
ap.insert(std::make_pair(v, vap.size()));
vap.push_back(v);
}
while (all != bddtrue)
{
int v = bdd_var(all);
all = bdd_high(all);
ap.insert(std::make_pair(v, vap.size()));
vap.push_back(v);
}
if (use_implicit_labels)
return;
if (use_implicit_labels)
return;
for (auto& i: sup)
{
bdd cond = i.first;
if (cond == bddtrue)
{
i.second = "t";
continue;
}
if (cond == bddfalse)
{
i.second = "f";
continue;
}
std::ostringstream s;
bool notfirstor = false;
for (auto& i: sup)
{
bdd cond = i.first;
if (cond == bddtrue)
{
i.second = "t";
continue;
}
if (cond == bddfalse)
{
i.second = "f";
continue;
}
std::ostringstream s;
bool notfirstor = false;
minato_isop isop(cond);
bdd cube;
while ((cube = isop.next()) != bddfalse)
{
if (notfirstor)
s << " | ";
bool notfirstand = false;
while (cube != bddtrue)
{
if (notfirstand)
s << '&';
else
notfirstand = true;
bdd h = bdd_high(cube);
if (h == bddfalse)
{
s << '!' << ap[bdd_var(cube)];
cube = bdd_low(cube);
}
else
{
s << ap[bdd_var(cube)];
cube = h;
}
}
notfirstor = true;
}
i.second = s.str();
}
minato_isop isop(cond);
bdd cube;
while ((cube = isop.next()) != bddfalse)
{
if (notfirstor)
s << " | ";
bool notfirstand = false;
while (cube != bddtrue)
{
if (notfirstand)
s << '&';
else
notfirstand = true;
bdd h = bdd_high(cube);
if (h == bddfalse)
{
s << '!' << ap[bdd_var(cube)];
cube = bdd_low(cube);
}
else
{
s << ap[bdd_var(cube)];
cube = h;
}
}
notfirstor = true;
}
i.second = s.str();
}
}
};
@ -234,18 +234,18 @@ namespace spot
enum hoa_acceptance
{
Hoa_Acceptance_States, /// state-based acceptance if
/// (globally) possible
/// transition-based acceptance
/// otherwise.
Hoa_Acceptance_States, /// state-based acceptance if
/// (globally) possible
/// transition-based acceptance
/// otherwise.
Hoa_Acceptance_Transitions, /// transition-based acceptance globally
Hoa_Acceptance_Mixed /// mix state-based and transition-based
};
static std::ostream&
print_hoa(std::ostream& os,
const const_twa_graph_ptr& aut,
const char* opt)
const const_twa_graph_ptr& aut,
const char* opt)
{
bool newline = true;
hoa_acceptance acceptance = Hoa_Acceptance_States;
@ -255,35 +255,35 @@ namespace spot
if (opt)
while (*opt)
{
switch (char c = *opt++)
{
case 'i':
implicit_labels = true;
break;
case 'k':
state_labels = true;
break;
case 'l':
newline = false;
break;
case 'm':
acceptance = Hoa_Acceptance_Mixed;
break;
case 's':
acceptance = Hoa_Acceptance_States;
break;
case 't':
acceptance = Hoa_Acceptance_Transitions;
break;
case 'v':
verbose = true;
break;
default:
throw std::runtime_error
(std::string("unknown option for print_hoa(): ") + c);
}
}
{
switch (char c = *opt++)
{
case 'i':
implicit_labels = true;
break;
case 'k':
state_labels = true;
break;
case 'l':
newline = false;
break;
case 'm':
acceptance = Hoa_Acceptance_Mixed;
break;
case 's':
acceptance = Hoa_Acceptance_States;
break;
case 't':
acceptance = Hoa_Acceptance_Transitions;
break;
case 'v':
verbose = true;
break;
default:
throw std::runtime_error
(std::string("unknown option for print_hoa(): ") + c);
}
}
// Calling get_init_state_number() may add a state to empty
// automata, so it has to be done first.
@ -314,72 +314,72 @@ namespace spot
acc_cond::acc_code acc_c = aut->acc().get_acceptance();
if (aut->acc().is_generalized_buchi())
{
if (aut->acc().is_all())
os << "acc-name: all";
else if (aut->acc().is_buchi())
os << "acc-name: Buchi";
else
os << "acc-name: generalized-Buchi " << num_acc;
os << nl;
if (aut->acc().is_all())
os << "acc-name: all";
else if (aut->acc().is_buchi())
os << "acc-name: Buchi";
else
os << "acc-name: generalized-Buchi " << num_acc;
os << nl;
}
else if (aut->acc().is_generalized_co_buchi())
{
if (aut->acc().is_none())
os << "acc-name: none";
else if (aut->acc().is_co_buchi())
os << "acc-name: co-Buchi";
else
os << "acc-name: generalized-co-Buchi " << num_acc;
os << nl;
if (aut->acc().is_none())
os << "acc-name: none";
else if (aut->acc().is_co_buchi())
os << "acc-name: co-Buchi";
else
os << "acc-name: generalized-co-Buchi " << num_acc;
os << nl;
}
else
{
int r = aut->acc().is_rabin();
assert(r != 0);
if (r > 0)
{
os << "acc-name: Rabin " << r << nl;
// Force the acceptance to remove any duplicate sets, and
// make sure it is correctly ordered.
acc_c = acc_cond::acc_code::rabin(r);
}
else
{
r = aut->acc().is_streett();
assert(r != 0);
if (r > 0)
{
os << "acc-name: Streett " << r << nl;
// Force the acceptance to remove any duplicate sets, and
// make sure it is correctly ordered.
acc_c = acc_cond::acc_code::streett(r);
}
else
{
std::vector<unsigned> pairs;
if (aut->acc().is_generalized_rabin(pairs))
{
os << "acc-name: generalized-Rabin " << pairs.size();
for (auto p: pairs)
os << ' ' << p;
os << nl;
// Force the acceptance to remove any duplicate
// sets, and make sure it is correctly ordered.
acc_c = acc_cond::acc_code::generalized_rabin(pairs.begin(),
pairs.end());
}
else
{
bool max = false;
bool odd = false;
if (aut->acc().is_parity(max, odd))
os << "acc-name: parity "
<< (max ? "max " : "min ")
<< (odd ? "odd " : "even ")
<< num_acc << nl;
}
}
}
int r = aut->acc().is_rabin();
assert(r != 0);
if (r > 0)
{
os << "acc-name: Rabin " << r << nl;
// Force the acceptance to remove any duplicate sets, and
// make sure it is correctly ordered.
acc_c = acc_cond::acc_code::rabin(r);
}
else
{
r = aut->acc().is_streett();
assert(r != 0);
if (r > 0)
{
os << "acc-name: Streett " << r << nl;
// Force the acceptance to remove any duplicate sets, and
// make sure it is correctly ordered.
acc_c = acc_cond::acc_code::streett(r);
}
else
{
std::vector<unsigned> pairs;
if (aut->acc().is_generalized_rabin(pairs))
{
os << "acc-name: generalized-Rabin " << pairs.size();
for (auto p: pairs)
os << ' ' << p;
os << nl;
// Force the acceptance to remove any duplicate
// sets, and make sure it is correctly ordered.
acc_c = acc_cond::acc_code::generalized_rabin(pairs.begin(),
pairs.end());
}
else
{
bool max = false;
bool odd = false;
if (aut->acc().is_parity(max, odd))
os << "acc-name: parity "
<< (max ? "max " : "min ")
<< (odd ? "odd " : "even ")
<< num_acc << nl;
}
}
}
}
os << "Acceptance: " << num_acc << ' ';
os << acc_c;
@ -390,17 +390,17 @@ namespace spot
unsigned prop_len = 60;
auto prop = [&](const char* str)
{
if (newline)
{
auto l = strlen(str);
if (prop_len < l)
{
prop_len = 60;
os << "\nproperties:";
}
prop_len -= l;
}
os << str;
if (newline)
{
auto l = strlen(str);
if (prop_len < l)
{
prop_len = 60;
os << "\nproperties:";
}
prop_len -= l;
}
os << str;
};
// We do not support alternating automata so far, and it's
// probable that nobody cares about the "no-univ-branch"
@ -452,132 +452,132 @@ namespace spot
std::vector<acc_cond::mark_t> outm;
if (implicit_labels)
{
out.resize(1UL << nap);
if (acceptance != Hoa_Acceptance_States)
outm.resize(1UL << nap);
out.resize(1UL << nap);
if (acceptance != Hoa_Acceptance_States)
outm.resize(1UL << nap);
}
os << "--BODY--" << nl;
auto sn = aut->get_named_prop<std::vector<std::string>>("state-names");
for (unsigned i = 0; i < num_states; ++i)
{
hoa_acceptance this_acc = acceptance;
if (this_acc == Hoa_Acceptance_Mixed)
this_acc = (md.common_acc[i] ?
Hoa_Acceptance_States : Hoa_Acceptance_Transitions);
hoa_acceptance this_acc = acceptance;
if (this_acc == Hoa_Acceptance_Mixed)
this_acc = (md.common_acc[i] ?
Hoa_Acceptance_States : Hoa_Acceptance_Transitions);
os << "State: ";
if (state_labels)
{
bool output = false;
for (auto& t: aut->out(i))
{
os << '[' << md.sup[t.cond] << "] ";
output = true;
break;
}
if (!output)
os << "[f] ";
}
os << i;
if (sn && i < sn->size() && !(*sn)[i].empty())
os << " \"" << (*sn)[i] << '"';
if (this_acc == Hoa_Acceptance_States)
{
acc_cond::mark_t acc = 0U;
for (auto& t: aut->out(i))
{
acc = t.acc;
break;
}
md.emit_acc(os, acc);
}
os << nl;
os << "State: ";
if (state_labels)
{
bool output = false;
for (auto& t: aut->out(i))
{
os << '[' << md.sup[t.cond] << "] ";
output = true;
break;
}
if (!output)
os << "[f] ";
}
os << i;
if (sn && i < sn->size() && !(*sn)[i].empty())
os << " \"" << (*sn)[i] << '"';
if (this_acc == Hoa_Acceptance_States)
{
acc_cond::mark_t acc = 0U;
for (auto& t: aut->out(i))
{
acc = t.acc;
break;
}
md.emit_acc(os, acc);
}
os << nl;
if (!implicit_labels && !state_labels)
{
if (!implicit_labels && !state_labels)
{
for (auto& t: aut->out(i))
{
os << '[' << md.sup[t.cond] << "] " << t.dst;
if (this_acc == Hoa_Acceptance_Transitions)
md.emit_acc(os, t.acc);
os << nl;
}
}
else if (state_labels)
{
unsigned n = 0;
for (auto& t: aut->out(i))
{
os << t.dst;
if (this_acc == Hoa_Acceptance_Transitions)
{
md.emit_acc(os, t.acc);
os << nl;
}
else
{
++n;
os << (((n & 15) && t.next_succ) ? ' ' : nl);
}
}
}
else
{
for (auto& t: aut->out(i))
{
bdd cond = t.cond;
while (cond != bddfalse)
{
bdd one = bdd_satoneset(cond, md.all_ap, bddfalse);
cond -= one;
unsigned level = 1;
unsigned pos = 0U;
while (one != bddtrue)
{
bdd h = bdd_high(one);
if (h == bddfalse)
{
one = bdd_low(one);
}
else
{
pos |= level;
one = h;
}
level <<= 1;
}
out[pos] = t.dst;
if (this_acc != Hoa_Acceptance_States)
outm[pos] = t.acc;
}
}
unsigned n = out.size();
for (unsigned i = 0; i < n;)
{
os << out[i];
if (this_acc != Hoa_Acceptance_States)
{
md.emit_acc(os, outm[i]) << nl;
++i;
}
else
{
++i;
os << (((i & 15) && i < n) ? ' ' : nl);
}
}
}
for (auto& t: aut->out(i))
{
os << '[' << md.sup[t.cond] << "] " << t.dst;
if (this_acc == Hoa_Acceptance_Transitions)
md.emit_acc(os, t.acc);
os << nl;
}
}
else if (state_labels)
{
unsigned n = 0;
for (auto& t: aut->out(i))
{
os << t.dst;
if (this_acc == Hoa_Acceptance_Transitions)
{
md.emit_acc(os, t.acc);
os << nl;
}
else
{
++n;
os << (((n & 15) && t.next_succ) ? ' ' : nl);
}
}
}
else
{
for (auto& t: aut->out(i))
{
bdd cond = t.cond;
while (cond != bddfalse)
{
bdd one = bdd_satoneset(cond, md.all_ap, bddfalse);
cond -= one;
unsigned level = 1;
unsigned pos = 0U;
while (one != bddtrue)
{
bdd h = bdd_high(one);
if (h == bddfalse)
{
one = bdd_low(one);
}
else
{
pos |= level;
one = h;
}
level <<= 1;
}
out[pos] = t.dst;
if (this_acc != Hoa_Acceptance_States)
outm[pos] = t.acc;
}
}
unsigned n = out.size();
for (unsigned i = 0; i < n;)
{
os << out[i];
if (this_acc != Hoa_Acceptance_States)
{
md.emit_acc(os, outm[i]) << nl;
++i;
}
else
{
++i;
os << (((i & 15) && i < n) ? ' ' : nl);
}
}
}
}
os << "--END--"; // No newline. Let the caller decide.
os << "--END--"; // No newline. Let the caller decide.
return os;
}
std::ostream&
print_hoa(std::ostream& os,
const const_twa_ptr& aut,
const char* opt)
const const_twa_ptr& aut,
const char* opt)
{
auto a = std::dynamic_pointer_cast<const twa_graph>(aut);
@ -588,12 +588,12 @@ namespace spot
char* tmpopt = nullptr;
if (std::dynamic_pointer_cast<const fair_kripke>(aut))
{
unsigned n = opt ? strlen(opt) : 0;
tmpopt = new char[n + 2];
if (opt)
strcpy(tmpopt, opt);
tmpopt[n] = 'k';
tmpopt[n + 1] = 0;
unsigned n = opt ? strlen(opt) : 0;
tmpopt = new char[n + 2];
if (opt)
strcpy(tmpopt, opt);
tmpopt[n] = 'k';
tmpopt[n + 1] = 0;
}
print_hoa(os, a, tmpopt ? tmpopt : opt);
delete[] tmpopt;

View file

@ -38,6 +38,6 @@ namespace spot
/// single-line output, (v) verbose properties.
SPOT_API std::ostream&
print_hoa(std::ostream& os,
const const_twa_ptr& g,
const char* opt = nullptr);
const const_twa_ptr& g,
const char* opt = nullptr);
}

View file

@ -33,23 +33,23 @@ namespace spot
unsigned nondet_states = 0;
unsigned ns = aut->num_states();
for (unsigned src = 0; src < ns; ++src)
{
bdd available = bddtrue;
for (auto& t: aut->out(src))
if (!bdd_implies(t.cond, available))
{
++nondet_states;
break;
}
else
{
available -= t.cond;
}
// If we are not counting non-deterministic states, abort as
// soon as possible.
if (!count && nondet_states)
break;
}
{
bdd available = bddtrue;
for (auto& t: aut->out(src))
if (!bdd_implies(t.cond, available))
{
++nondet_states;
break;
}
else
{
available -= t.cond;
}
// If we are not counting non-deterministic states, abort as
// soon as possible.
if (!count && nondet_states)
break;
}
return nondet_states;
}
}
@ -75,11 +75,11 @@ namespace spot
unsigned ns = aut->num_states();
for (unsigned src = 0; src < ns; ++src)
{
bdd available = bddtrue;
for (auto& t: aut->out(src))
available -= t.cond;
if (available != bddfalse)
return false;
bdd available = bddtrue;
for (auto& t: aut->out(src))
available -= t.cond;
if (available != bddfalse)
return false;
}
// The empty automaton is not complete since it does not have an
// initial state.

View file

@ -37,7 +37,7 @@ namespace spot
auto prod = product(clean_a, clean_a);
auto clean_p = scc_filter_states(prod);
return (clean_a->num_states() == clean_p->num_states()
&& clean_a->num_edges() == clean_p->num_edges());
&& clean_a->num_edges() == clean_p->num_edges());
}
bool check_unambiguous(const twa_graph_ptr& aut)

View file

@ -35,7 +35,7 @@ namespace spot
keep[s] = true;
auto sccaut = mask_keep_states(aut, keep, states.front());
sccaut->set_acceptance(sccaut->acc().num_sets(),
sccaut->get_acceptance().complement());
sccaut->get_acceptance().complement());
return !sccaut->is_empty();
}
@ -67,18 +67,18 @@ namespace spot
auto a = map.get_aut();
for (auto s: map.states_of(scc))
{
bool has_succ = false;
bdd sumall = bddfalse;
for (auto& t: a->out(s))
{
has_succ = true;
if (map.scc_of(t.dst) == scc)
sumall |= t.cond;
if (sumall == bddtrue)
break;
}
if (!has_succ || sumall != bddtrue)
return false;
bool has_succ = false;
bdd sumall = bddfalse;
for (auto& t: a->out(s))
{
has_succ = true;
if (map.scc_of(t.dst) == scc)
sumall |= t.cond;
if (sumall == bddtrue)
break;
}
if (!has_succ || sumall != bddtrue)
return false;
}
return true;
}
@ -88,7 +88,7 @@ namespace spot
{
// If all transitions use all acceptance conditions, the SCC is weak.
return (map.is_accepting_scc(scc)
&& map.used_acc_of(scc).size() == 1
&& is_complete_scc(map, scc));
&& map.used_acc_of(scc).size() == 1
&& is_complete_scc(map, scc));
}
}

View file

@ -38,83 +38,83 @@ namespace spot
{
public:
lbtt_bfs(const const_twa_ptr& a, std::ostream& os, bool sba_format)
: twa_reachable_iterator_breadth_first(a),
os_(os),
sba_format_(sba_format),
sba_(nullptr)
: twa_reachable_iterator_breadth_first(a),
os_(os),
sba_format_(sba_format),
sba_(nullptr)
{
// Check if the automaton can be converted into a
// twa_graph. This makes the state_is_accepting() function
// more efficient.
if (a->is_sba())
sba_ = std::dynamic_pointer_cast<const twa_graph>(a);
// Check if the automaton can be converted into a
// twa_graph. This makes the state_is_accepting() function
// more efficient.
if (a->is_sba())
sba_ = std::dynamic_pointer_cast<const twa_graph>(a);
}
acc_cond::mark_t
state_acc_sets(const state *s) const
{
// If the automaton has a SBA type, it's easier to just query the
// state_is_accepting() method.
if (sba_)
return sba_->state_acc_sets(sba_->state_number(s));
// If the automaton has a SBA type, it's easier to just query the
// state_is_accepting() method.
if (sba_)
return sba_->state_acc_sets(sba_->state_number(s));
// Otherwise, since we are dealing with a degeneralized
// automaton nonetheless, the transitions leaving an accepting
// state are either all accepting, or all non-accepting. So
// we just check the acceptance of the first transition. This
// is not terribly efficient since we have to create the
// iterator.
twa_succ_iterator* it = aut_->succ_iter(s);
if (!it->first())
return {};
auto res = it->acc();
aut_->release_iter(it);
return res;
// Otherwise, since we are dealing with a degeneralized
// automaton nonetheless, the transitions leaving an accepting
// state are either all accepting, or all non-accepting. So
// we just check the acceptance of the first transition. This
// is not terribly efficient since we have to create the
// iterator.
twa_succ_iterator* it = aut_->succ_iter(s);
if (!it->first())
return {};
auto res = it->acc();
aut_->release_iter(it);
return res;
}
void
process_state(const state* s, int n, twa_succ_iterator*)
{
--n;
if (n == 0)
body_ << "0 1";
else
body_ << "-1\n" << n << " 0";
// Do we have state-based acceptance?
if (sba_format_)
{
for (auto i: state_acc_sets(s).sets())
body_ << ' ' << i;
body_ << " -1";
}
body_ << '\n';
--n;
if (n == 0)
body_ << "0 1";
else
body_ << "-1\n" << n << " 0";
// Do we have state-based acceptance?
if (sba_format_)
{
for (auto i: state_acc_sets(s).sets())
body_ << ' ' << i;
body_ << " -1";
}
body_ << '\n';
}
void
process_link(const state*, int,
const state*, int out, const twa_succ_iterator* si)
const state*, int out, const twa_succ_iterator* si)
{
body_ << out - 1 << ' ';
if (!sba_format_)
{
for (auto s: si->acc().sets())
body_ << s << ' ';
body_ << "-1 ";
}
print_lbt_ltl(body_, bdd_to_formula(si->cond(),
aut_->get_dict())) << '\n';
body_ << out - 1 << ' ';
if (!sba_format_)
{
for (auto s: si->acc().sets())
body_ << s << ' ';
body_ << "-1 ";
}
print_lbt_ltl(body_, bdd_to_formula(si->cond(),
aut_->get_dict())) << '\n';
}
void
end()
{
os_ << seen.size() << ' ';
if (sba_format_)
os_ << aut_->num_sets();
else
os_ << aut_->num_sets() << 't';
os_ << '\n' << body_.str() << "-1" << std::endl;
os_ << seen.size() << ' ';
if (sba_format_)
os_ << aut_->num_sets();
else
os_ << aut_->num_sets() << 't';
os_ << '\n' << body_.str() << "-1" << std::endl;
}
private:
@ -131,19 +131,19 @@ namespace spot
{
if (!g->acc().is_generalized_buchi())
throw std::runtime_error
("LBTT only supports generalized Büchi acceptance");
("LBTT only supports generalized Büchi acceptance");
bool sba = g->prop_state_acc().is_true();
if (opt)
switch (char c = *opt++)
{
case 't':
sba = false;
break;
default:
throw std::runtime_error
(std::string("unknown option for print_lbtt(): ") + c);
}
{
case 't':
sba = false;
break;
default:
throw std::runtime_error
(std::string("unknown option for print_lbtt(): ") + c);
}
lbtt_bfs b(g, os, sba);
b.run();

View file

@ -36,5 +36,5 @@ namespace spot
// default to state-based acceptance when the automaton is marked so.
SPOT_API std::ostream&
print_lbtt(std::ostream& os, const const_twa_ptr& g,
const char* opt = nullptr);
const char* opt = nullptr);
}

View file

@ -33,10 +33,10 @@ namespace spot
{
public:
ltl2taa_visitor(const taa_tgba_formula_ptr& res,
language_containment_checker* lcc,
bool refined = false, bool negated = false)
: res_(res), refined_(refined), negated_(negated),
lcc_(lcc), init_(), succ_()
language_containment_checker* lcc,
bool refined = false, bool negated = false)
: res_(res), refined_(refined), negated_(negated),
lcc_(lcc), init_(), succ_()
{
}
@ -47,272 +47,272 @@ namespace spot
taa_tgba_formula_ptr&
result()
{
res_->set_init_state(init_);
return res_;
res_->set_init_state(init_);
return res_;
}
void
visit(formula f)
{
init_ = f;
switch (f.kind())
{
case op::ff:
return;
case op::tt:
{
std::vector<formula> empty;
res_->create_transition(init_, empty);
succ_state ss = { empty, f, empty };
succ_.push_back(ss);
return;
}
case op::eword:
SPOT_UNIMPLEMENTED();
case op::ap:
{
res_->register_ap(f);
if (negated_)
f = formula::Not(f);
init_ = f;
std::vector<formula> empty;
taa_tgba::transition* t = res_->create_transition(init_, empty);
res_->add_condition(t, f);
succ_state ss = { empty, f, empty };
succ_.push_back(ss);
return;
}
case op::X:
{
ltl2taa_visitor v = recurse(f[0]);
std::vector<formula> dst;
std::vector<formula> a;
if (v.succ_.empty()) // Handle X(0)
return;
dst.push_back(v.init_);
res_->create_transition(init_, dst);
succ_state ss = { dst, formula::tt(), a };
succ_.push_back(ss);
return;
}
case op::F:
case op::G:
SPOT_UNIMPLEMENTED(); // TBD
return;
case op::Not:
{
negated_ = true;
ltl2taa_visitor v = recurse(f[0]);
// Done in recurse
succ_ = v.succ_;
return;
}
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::Star:
case op::FStar:
case op::Xor:
case op::Implies:
case op::Equiv:
case op::UConcat:
case op::EConcat:
case op::EConcatMarked:
case op::Concat:
case op::Fusion:
case op::AndNLM:
case op::AndRat:
case op::OrRat:
SPOT_UNIMPLEMENTED();
init_ = f;
switch (f.kind())
{
case op::ff:
return;
case op::tt:
{
std::vector<formula> empty;
res_->create_transition(init_, empty);
succ_state ss = { empty, f, empty };
succ_.push_back(ss);
return;
}
case op::eword:
SPOT_UNIMPLEMENTED();
case op::ap:
{
res_->register_ap(f);
if (negated_)
f = formula::Not(f);
init_ = f;
std::vector<formula> empty;
taa_tgba::transition* t = res_->create_transition(init_, empty);
res_->add_condition(t, f);
succ_state ss = { empty, f, empty };
succ_.push_back(ss);
return;
}
case op::X:
{
ltl2taa_visitor v = recurse(f[0]);
std::vector<formula> dst;
std::vector<formula> a;
if (v.succ_.empty()) // Handle X(0)
return;
dst.push_back(v.init_);
res_->create_transition(init_, dst);
succ_state ss = { dst, formula::tt(), a };
succ_.push_back(ss);
return;
}
case op::F:
case op::G:
SPOT_UNIMPLEMENTED(); // TBD
return;
case op::Not:
{
negated_ = true;
ltl2taa_visitor v = recurse(f[0]);
// Done in recurse
succ_ = v.succ_;
return;
}
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::Star:
case op::FStar:
case op::Xor:
case op::Implies:
case op::Equiv:
case op::UConcat:
case op::EConcat:
case op::EConcatMarked:
case op::Concat:
case op::Fusion:
case op::AndNLM:
case op::AndRat:
case op::OrRat:
SPOT_UNIMPLEMENTED();
case op::U:
case op::W:
case op::R:
case op::M:
visit_binop(f);
return;
case op::And:
case op::Or:
visit_multop(f);
return;
}
case op::U:
case op::W:
case op::R:
case op::M:
visit_binop(f);
return;
case op::And:
case op::Or:
visit_multop(f);
return;
}
}
void
visit_binop(formula f)
{
ltl2taa_visitor v1 = recurse(f[0]);
ltl2taa_visitor v2 = recurse(f[1]);
ltl2taa_visitor v1 = recurse(f[0]);
ltl2taa_visitor v2 = recurse(f[1]);
std::vector<succ_state>::iterator i1;
std::vector<succ_state>::iterator i2;
taa_tgba::transition* t = nullptr;
bool contained = false;
bool strong = false;
std::vector<succ_state>::iterator i1;
std::vector<succ_state>::iterator i2;
taa_tgba::transition* t = nullptr;
bool contained = false;
bool strong = false;
switch (f.kind())
{
case op::U:
strong = true;
// fall thru
case op::W:
if (refined_)
contained = lcc_->contained(f[0], f[1]);
for (i1 = v1.succ_.begin(); i1 != v1.succ_.end(); ++i1)
{
// Refined rule
if (refined_ && contained)
i1->Q.erase
(remove(i1->Q.begin(), i1->Q.end(), v1.init_), i1->Q.end());
switch (f.kind())
{
case op::U:
strong = true;
// fall thru
case op::W:
if (refined_)
contained = lcc_->contained(f[0], f[1]);
for (i1 = v1.succ_.begin(); i1 != v1.succ_.end(); ++i1)
{
// Refined rule
if (refined_ && contained)
i1->Q.erase
(remove(i1->Q.begin(), i1->Q.end(), v1.init_), i1->Q.end());
i1->Q.push_back(init_); // Add the initial state
if (strong)
i1->acc.push_back(f[1]);
t = res_->create_transition(init_, i1->Q);
res_->add_condition(t, i1->condition);
if (strong)
res_->add_acceptance_condition(t, f[1]);
else
for (unsigned i = 0; i < i1->acc.size(); ++i)
res_->add_acceptance_condition(t, i1->acc[i]);
succ_.push_back(*i1);
}
for (i2 = v2.succ_.begin(); i2 != v2.succ_.end(); ++i2)
{
t = res_->create_transition(init_, i2->Q);
res_->add_condition(t, i2->condition);
succ_.push_back(*i2);
}
return;
case op::M: // Strong Release
strong = true;
case op::R: // Weak Release
if (refined_)
contained = lcc_->contained(f[0], f[1]);
i1->Q.push_back(init_); // Add the initial state
if (strong)
i1->acc.push_back(f[1]);
t = res_->create_transition(init_, i1->Q);
res_->add_condition(t, i1->condition);
if (strong)
res_->add_acceptance_condition(t, f[1]);
else
for (unsigned i = 0; i < i1->acc.size(); ++i)
res_->add_acceptance_condition(t, i1->acc[i]);
succ_.push_back(*i1);
}
for (i2 = v2.succ_.begin(); i2 != v2.succ_.end(); ++i2)
{
t = res_->create_transition(init_, i2->Q);
res_->add_condition(t, i2->condition);
succ_.push_back(*i2);
}
return;
case op::M: // Strong Release
strong = true;
case op::R: // Weak Release
if (refined_)
contained = lcc_->contained(f[0], f[1]);
for (i2 = v2.succ_.begin(); i2 != v2.succ_.end(); ++i2)
{
for (i1 = v1.succ_.begin(); i1 != v1.succ_.end(); ++i1)
{
std::vector<formula> u; // Union
std::vector<formula> a; // Acceptance conditions
std::copy(i1->Q.begin(), i1->Q.end(), ii(u, u.end()));
formula f = i1->condition; // Refined rule
if (!refined_ || !contained)
{
std::copy(i2->Q.begin(), i2->Q.end(), ii(u, u.end()));
f = formula::And({f, i2->condition});
}
t = res_->create_transition(init_, u);
res_->add_condition(t, f);
succ_state ss = { u, f, a };
succ_.push_back(ss);
}
for (i2 = v2.succ_.begin(); i2 != v2.succ_.end(); ++i2)
{
for (i1 = v1.succ_.begin(); i1 != v1.succ_.end(); ++i1)
{
std::vector<formula> u; // Union
std::vector<formula> a; // Acceptance conditions
std::copy(i1->Q.begin(), i1->Q.end(), ii(u, u.end()));
formula f = i1->condition; // Refined rule
if (!refined_ || !contained)
{
std::copy(i2->Q.begin(), i2->Q.end(), ii(u, u.end()));
f = formula::And({f, i2->condition});
}
t = res_->create_transition(init_, u);
res_->add_condition(t, f);
succ_state ss = { u, f, a };
succ_.push_back(ss);
}
if (refined_) // Refined rule
i2->Q.erase
(remove(i2->Q.begin(), i2->Q.end(), v2.init_), i2->Q.end());
if (refined_) // Refined rule
i2->Q.erase
(remove(i2->Q.begin(), i2->Q.end(), v2.init_), i2->Q.end());
i2->Q.push_back(init_); // Add the initial state
t = res_->create_transition(init_, i2->Q);
res_->add_condition(t, i2->condition);
i2->Q.push_back(init_); // Add the initial state
t = res_->create_transition(init_, i2->Q);
res_->add_condition(t, i2->condition);
if (strong)
{
i2->acc.push_back(f[0]);
res_->add_acceptance_condition(t, f[0]);
}
else if (refined_)
for (unsigned i = 0; i < i2->acc.size(); ++i)
res_->add_acceptance_condition(t, i2->acc[i]);
succ_.push_back(*i2);
}
return;
default:
SPOT_UNIMPLEMENTED();
}
SPOT_UNREACHABLE();
if (strong)
{
i2->acc.push_back(f[0]);
res_->add_acceptance_condition(t, f[0]);
}
else if (refined_)
for (unsigned i = 0; i < i2->acc.size(); ++i)
res_->add_acceptance_condition(t, i2->acc[i]);
succ_.push_back(*i2);
}
return;
default:
SPOT_UNIMPLEMENTED();
}
SPOT_UNREACHABLE();
}
void
visit_multop(formula f)
{
bool ok = true;
std::vector<ltl2taa_visitor> vs;
for (unsigned n = 0, s = f.size(); n < s; ++n)
{
vs.push_back(recurse(f[n]));
if (vs[n].succ_.empty()) // Handle 0
ok = false;
}
bool ok = true;
std::vector<ltl2taa_visitor> vs;
for (unsigned n = 0, s = f.size(); n < s; ++n)
{
vs.push_back(recurse(f[n]));
if (vs[n].succ_.empty()) // Handle 0
ok = false;
}
std::vector<succ_state>::iterator i;
taa_tgba::transition* t = nullptr;
switch (f.kind())
{
case op::And:
{
if (!ok)
return;
std::vector<succ_state> p = all_n_tuples(vs);
for (unsigned n = 0; n < p.size(); ++n)
{
if (refined_)
{
std::vector<formula> v; // All sub initial states.
sort(p[n].Q.begin(), p[n].Q.end());
for (unsigned m = 0; m < f.size(); ++m)
{
if (!binary_search(p[n].Q.begin(), p[n].Q.end(),
vs[m].init_))
break;
v.push_back(vs[m].init_);
}
std::vector<succ_state>::iterator i;
taa_tgba::transition* t = nullptr;
switch (f.kind())
{
case op::And:
{
if (!ok)
return;
std::vector<succ_state> p = all_n_tuples(vs);
for (unsigned n = 0; n < p.size(); ++n)
{
if (refined_)
{
std::vector<formula> v; // All sub initial states.
sort(p[n].Q.begin(), p[n].Q.end());
for (unsigned m = 0; m < f.size(); ++m)
{
if (!binary_search(p[n].Q.begin(), p[n].Q.end(),
vs[m].init_))
break;
v.push_back(vs[m].init_);
}
if (v.size() == f.size())
{
std::vector<formula> Q;
sort(v.begin(), v.end());
for (unsigned m = 0; m < p[n].Q.size(); ++m)
if (!binary_search(v.begin(), v.end(), p[n].Q[m]))
Q.push_back(p[n].Q[m]);
Q.push_back(init_);
t = res_->create_transition(init_, Q);
res_->add_condition(t, p[n].condition);
for (unsigned i = 0; i < p[n].acc.size(); ++i)
res_->add_acceptance_condition(t, p[n].acc[i]);
succ_.push_back(p[n]);
continue;
}
}
t = res_->create_transition(init_, p[n].Q);
res_->add_condition(t, p[n].condition);
succ_.push_back(p[n]);
}
return;
}
case op::Or:
for (unsigned n = 0, s = f.size(); n < s; ++n)
for (auto i: vs[n].succ_)
{
t = res_->create_transition(init_, i.Q);
res_->add_condition(t, i.condition);
succ_.push_back(i);
}
return;
default:
SPOT_UNIMPLEMENTED();
}
SPOT_UNREACHABLE();
if (v.size() == f.size())
{
std::vector<formula> Q;
sort(v.begin(), v.end());
for (unsigned m = 0; m < p[n].Q.size(); ++m)
if (!binary_search(v.begin(), v.end(), p[n].Q[m]))
Q.push_back(p[n].Q[m]);
Q.push_back(init_);
t = res_->create_transition(init_, Q);
res_->add_condition(t, p[n].condition);
for (unsigned i = 0; i < p[n].acc.size(); ++i)
res_->add_acceptance_condition(t, p[n].acc[i]);
succ_.push_back(p[n]);
continue;
}
}
t = res_->create_transition(init_, p[n].Q);
res_->add_condition(t, p[n].condition);
succ_.push_back(p[n]);
}
return;
}
case op::Or:
for (unsigned n = 0, s = f.size(); n < s; ++n)
for (auto i: vs[n].succ_)
{
t = res_->create_transition(init_, i.Q);
res_->add_condition(t, i.condition);
succ_.push_back(i);
}
return;
default:
SPOT_UNIMPLEMENTED();
}
SPOT_UNREACHABLE();
}
ltl2taa_visitor
recurse(formula f)
{
ltl2taa_visitor v(res_, lcc_, refined_, negated_);
v.visit(f);
return v;
ltl2taa_visitor v(res_, lcc_, refined_, negated_);
v.visit(f);
return v;
}
private:
@ -325,9 +325,9 @@ namespace spot
struct succ_state
{
std::vector<formula> Q; // States
formula condition;
std::vector<formula> acc;
std::vector<formula> Q; // States
formula condition;
std::vector<formula> acc;
};
formula init_;
@ -337,61 +337,61 @@ namespace spot
std::vector<succ_state>
all_n_tuples(const std::vector<ltl2taa_visitor>& vs)
{
std::vector<succ_state> product;
std::vector<succ_state> product;
std::vector<int> pos(vs.size());
for (unsigned i = 0; i < vs.size(); ++i)
pos[i] = vs[i].succ_.size();
std::vector<int> pos(vs.size());
for (unsigned i = 0; i < vs.size(); ++i)
pos[i] = vs[i].succ_.size();
while (pos[0] != 0)
{
std::vector<formula> u; // Union
std::vector<formula> a; // Acceptance conditions
formula f = formula::tt();
for (unsigned i = 0; i < vs.size(); ++i)
{
if (vs[i].succ_.empty())
continue;
const succ_state& ss(vs[i].succ_[pos[i] - 1]);
std::copy(ss.Q.begin(), ss.Q.end(), ii(u, u.end()));
f = formula::And({ss.condition, f});
for (unsigned i = 0; i < ss.acc.size(); ++i)
{
formula g = ss.acc[i];
a.push_back(g);
}
}
succ_state ss = { u, f, a };
product.push_back(ss);
while (pos[0] != 0)
{
std::vector<formula> u; // Union
std::vector<formula> a; // Acceptance conditions
formula f = formula::tt();
for (unsigned i = 0; i < vs.size(); ++i)
{
if (vs[i].succ_.empty())
continue;
const succ_state& ss(vs[i].succ_[pos[i] - 1]);
std::copy(ss.Q.begin(), ss.Q.end(), ii(u, u.end()));
f = formula::And({ss.condition, f});
for (unsigned i = 0; i < ss.acc.size(); ++i)
{
formula g = ss.acc[i];
a.push_back(g);
}
}
succ_state ss = { u, f, a };
product.push_back(ss);
for (int i = vs.size() - 1; i >= 0; --i)
{
if (vs[i].succ_.empty())
continue;
if (pos[i] > 1 || (i == 0 && pos[0] == 1))
{
--pos[i];
break;
}
else
pos[i] = vs[i].succ_.size();
}
}
return product;
for (int i = vs.size() - 1; i >= 0; --i)
{
if (vs[i].succ_.empty())
continue;
if (pos[i] > 1 || (i == 0 && pos[0] == 1))
{
--pos[i];
break;
}
else
pos[i] = vs[i].succ_.size();
}
}
return product;
}
};
} // anonymous
taa_tgba_formula_ptr
ltl_to_taa(formula f,
const bdd_dict_ptr& dict, bool refined_rules)
const bdd_dict_ptr& dict, bool refined_rules)
{
// TODO: implement translation of F and G
auto f2 = negative_normal_form(unabbreviate(f, "^ieFG"));
auto res = make_taa_tgba_formula(dict);
language_containment_checker* lcc =
new language_containment_checker(make_bdd_dict(),
false, false, false, false);
false, false, false, false);
ltl2taa_visitor v(res, lcc, refined_rules);
v.visit(f2);
auto taa = v.result();

View file

@ -49,5 +49,5 @@ namespace spot
/// \return A spot::taa that recognizes the language of \a f.
SPOT_API taa_tgba_formula_ptr
ltl_to_taa(formula f, const bdd_dict_ptr& dict,
bool refined_rules = false);
bool refined_rules = false);
}

File diff suppressed because it is too large Load diff

View file

@ -35,18 +35,18 @@ namespace spot
/// This is based on the following paper.
/** \verbatim
@InProceedings{couvreur.99.fm,
author = {Jean-Michel Couvreur},
author = {Jean-Michel Couvreur},
title = {On-the-fly Verification of Temporal Logic},
pages = {253--271},
editor = {Jeannette M. Wing and Jim Woodcock and Jim Davies},
editor = {Jeannette M. Wing and Jim Woodcock and Jim Davies},
booktitle = {Proceedings of the World Congress on Formal Methods in the
Development of Computing Systems (FM'99)},
Development of Computing Systems (FM'99)},
publisher = {Springer-Verlag},
series = {Lecture Notes in Computer Science},
volume = {1708},
series = {Lecture Notes in Computer Science},
volume = {1708},
year = {1999},
address = {Toulouse, France},
month = {September},
address = {Toulouse, France},
month = {September},
isbn = {3-540-66587-0}
}
\endverbatim */
@ -71,18 +71,18 @@ namespace spot
/// conditions) will be merged. This correspond to an optimization
/// described in the following paper.
/** \verbatim
@InProceedings{ sebastiani.03.charme,
author = {Roberto Sebastiani and Stefano Tonetta},
title = {"More Deterministic" vs. "Smaller" B{\"u}chi Automata for
Efficient LTL Model Checking},
@InProceedings{ sebastiani.03.charme,
author = {Roberto Sebastiani and Stefano Tonetta},
title = {"More Deterministic" vs. "Smaller" B{\"u}chi Automata for
Efficient LTL Model Checking},
booktitle = {Proceedings for the 12th Advanced Research Working
Conference on Correct Hardware Design and Verification
Methods (CHARME'03)},
Conference on Correct Hardware Design and Verification
Methods (CHARME'03)},
pages = {126--140},
year = {2003},
editor = {G. Goos and J. Hartmanis and J. van Leeuwen},
volume = {2860},
series = {Lectures Notes in Computer Science},
editor = {G. Goos and J. Hartmanis and J. van Leeuwen},
volume = {2860},
series = {Lectures Notes in Computer Science},
month = {October},
publisher = {Springer-Verlag}
}
@ -104,36 +104,36 @@ namespace spot
/// spot::tl_simplifier. This idea is taken from the
/// following paper.
/** \verbatim
@InProceedings{ thirioux.02.fmics,
author = {Xavier Thirioux},
@InProceedings{ thirioux.02.fmics,
author = {Xavier Thirioux},
title = {Simple and Efficient Translation from {LTL} Formulas to
{B\"u}chi Automata},
{B\"u}chi Automata},
booktitle = {Proceedings of the 7th International ERCIM Workshop in
Formal Methods for Industrial Critical Systems (FMICS'02)},
series = {Electronic Notes in Theoretical Computer Science},
volume = {66(2)},
Formal Methods for Industrial Critical Systems (FMICS'02)},
series = {Electronic Notes in Theoretical Computer Science},
volume = {66(2)},
publisher = {Elsevier},
editor = {Rance Cleaveland and Hubert Garavel},
editor = {Rance Cleaveland and Hubert Garavel},
year = {2002},
month = jul,
address = {M{\'a}laga, Spain}
address = {M{\'a}laga, Spain}
}
\endverbatim */
///
/// \param unambiguous When true, unambigous TGBA will be produced using
/// the trick described in the following paper.
/** \verbatim
@InProceedings{ benedikt.13.tacas,
author = {Michael Benedikt and Rastislav Lenhardt and James
Worrell},
@InProceedings{ benedikt.13.tacas,
author = {Michael Benedikt and Rastislav Lenhardt and James
Worrell},
title = {{LTL} Model Checking of Interval Markov Chains},
booktitle = {19th International Conference on Tools and Algorithms for
the Construction and Analysis of Systems (TACAS'13)},
the Construction and Analysis of Systems (TACAS'13)},
year = {2013},
pages = {32--46},
series = {Lecture Notes in Computer Science},
volume = {7795},
editor = {Nir Piterman and Scott A. Smolka},
series = {Lecture Notes in Computer Science},
volume = {7795},
editor = {Nir Piterman and Scott A. Smolka},
publisher = {Springer}
}
\endverbatim */
@ -141,10 +141,10 @@ namespace spot
/// \return A spot::twa_graph that recognizes the language of \a f.
SPOT_API twa_graph_ptr
ltl_to_tgba_fm(formula f, const bdd_dict_ptr& dict,
bool exprop = false, bool symb_merge = true,
bool branching_postponement = false,
bool fair_loop_approx = false,
const atomic_prop_set* unobs = nullptr,
tl_simplifier* simplifier = nullptr,
bool unambiguous = false);
bool exprop = false, bool symb_merge = true,
bool branching_postponement = false,
bool fair_loop_approx = false,
const atomic_prop_set* unobs = nullptr,
tl_simplifier* simplifier = nullptr,
bool unambiguous = false);
}

View file

@ -55,7 +55,7 @@ namespace spot
/// \pre The automaton \a a must have at most one acceptance
/// condition (i.e. it is a TBA).
magic_search_(const const_twa_ptr& a, size_t size,
option_map o = option_map())
option_map o = option_map())
: emptiness_check(a, o),
h(size)
{
@ -89,8 +89,8 @@ namespace spot
/// visits only a finite set of accepting paths.
virtual emptiness_check_result_ptr check() override
{
auto t = std::static_pointer_cast<magic_search_>
(this->emptiness_check::shared_from_this());
auto t = std::static_pointer_cast<magic_search_>
(this->emptiness_check::shared_from_this());
if (st_red.empty())
{
assert(st_blue.empty());
@ -99,7 +99,7 @@ namespace spot
h.add_new_state(s0, BLUE);
push(st_blue, s0, bddfalse, 0U);
if (dfs_blue())
return std::make_shared<magic_search_result>(t, options());
return std::make_shared<magic_search_result>(t, options());
}
else
{
@ -130,27 +130,27 @@ namespace spot
virtual bool safe() const override
{
return heap::Safe;
return heap::Safe;
}
const heap& get_heap() const
{
return h;
return h;
}
const stack_type& get_st_blue() const
{
return st_blue;
return st_blue;
}
const stack_type& get_st_red() const
{
return st_red;
return st_red;
}
private:
void push(stack_type& st, const state* s,
const bdd& label, acc_cond::mark_t acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
twa_succ_iterator* i = a_->succ_iter(s);
@ -161,7 +161,7 @@ namespace spot
void pop(stack_type& st)
{
dec_depth();
a_->release_iter(st.front().it);
a_->release_iter(st.front().it);
st.pop_front();
}
@ -235,7 +235,7 @@ namespace spot
typename heap::color_ref c = h.get_color_ref(f_dest.s);
assert(!c.is_white());
if (!st_blue.empty() &&
a_->acc().accepting(f_dest.acc) && c.get_color() != RED)
a_->acc().accepting(f_dest.acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -380,7 +380,7 @@ namespace spot
{
public:
magic_search_result(const std::shared_ptr<magic_search_>& m,
option_map o = option_map())
option_map o = option_map())
: emptiness_check_result(m->automaton(), o), ms(m)
{
if (options()[FROM_STACK])
@ -420,7 +420,7 @@ namespace spot
private:
emptiness_check_result* computer;
std::shared_ptr<magic_search_> ms;
std::shared_ptr<magic_search_> ms;
};
};
@ -433,21 +433,21 @@ namespace spot
{
public:
color_ref(color* c) :p(c)
{
}
{
}
color get_color() const
{
return *p;
}
{
return *p;
}
void set_color(color c)
{
assert(!is_white());
*p=c;
}
{
assert(!is_white());
*p=c;
}
bool is_white() const
{
return !p;
}
{
return !p;
}
private:
color *p;
};
@ -588,7 +588,7 @@ namespace spot
emptiness_check_ptr
bit_state_hashing_magic_search(const const_twa_ptr& a,
size_t size, option_map o)
size_t size, option_map o)
{
return std::make_shared<magic_search_<bsh_magic_search_heap>>(a, size, o);
}

View file

@ -97,7 +97,7 @@ namespace spot
/// from \c godefroid.93.pstv, not \c courcoubetis.92.fmsd.
SPOT_API emptiness_check_ptr
explicit_magic_search(const const_twa_ptr& a,
option_map o = option_map());
option_map o = option_map());
/// \brief Returns an emptiness checker on the spot::tgba automaton \a a.
///
@ -128,7 +128,7 @@ namespace spot
///
SPOT_API emptiness_check_ptr
bit_state_hashing_magic_search(const const_twa_ptr& a, size_t size,
option_map o = option_map());
option_map o = option_map());
/// \brief Wrapper for the two magic_search implementations.
///

View file

@ -22,7 +22,7 @@
namespace spot
{
twa_graph_ptr mask_acc_sets(const const_twa_graph_ptr& in,
acc_cond::mark_t to_remove)
acc_cond::mark_t to_remove)
{
auto res = make_twa_graph(in->get_dict());
res->copy_ap_of(in);
@ -31,7 +31,7 @@ namespace spot
unsigned tr = to_remove.count();
assert(tr <= na);
res->set_acceptance(na - tr,
in->get_acceptance().strip(to_remove, true));
in->get_acceptance().strip(to_remove, true));
transform_accessible(in, res, [&](unsigned,
bdd& cond,
acc_cond::mark_t& acc,
@ -60,10 +60,10 @@ namespace spot
bdd& cond,
acc_cond::mark_t&,
unsigned dst)
{
if (!to_keep[src] || !to_keep[dst])
cond = bddfalse;
}, init);
{
if (!to_keep[src] || !to_keep[dst])
cond = bddfalse;
}, init);
return res;
}

View file

@ -49,36 +49,36 @@ namespace spot
auto new_state =
[&](unsigned old_state) -> unsigned
{
unsigned tmp = seen[old_state];
if (tmp == -1U)
{
tmp = cpy->new_state();
seen[old_state] = tmp;
todo.push_back(old_state);
}
return tmp;
unsigned tmp = seen[old_state];
if (tmp == -1U)
{
tmp = cpy->new_state();
seen[old_state] = tmp;
todo.push_back(old_state);
}
return tmp;
};
cpy->set_init_state(new_state(init));
while (!todo.empty())
{
unsigned old_src = todo.back();
todo.pop_back();
unsigned old_src = todo.back();
todo.pop_back();
unsigned new_src = seen[old_src];
assert(new_src != -1U);
unsigned new_src = seen[old_src];
assert(new_src != -1U);
for (auto& t: old->out(old_src))
{
bdd cond = t.cond;
acc_cond::mark_t acc = t.acc;
trans(t.src, cond, acc, t.dst);
for (auto& t: old->out(old_src))
{
bdd cond = t.cond;
acc_cond::mark_t acc = t.acc;
trans(t.src, cond, acc, t.dst);
if (cond != bddfalse)
cpy->new_edge(new_src,
new_state(t.dst),
cond, acc);
}
if (cond != bddfalse)
cpy->new_edge(new_src,
new_state(t.dst),
cond, acc);
}
}
}
@ -136,7 +136,7 @@ namespace spot
/// \brief Remove all edges that belong to some given acceptance sets.
SPOT_API
twa_graph_ptr mask_acc_sets(const const_twa_graph_ptr& in,
acc_cond::mark_t to_remove);
acc_cond::mark_t to_remove);
/// \brief Keep only the states as specified by \a to_keep.
///
@ -144,6 +144,6 @@ namespace spot
/// state. The initial state will be set to \a init.
SPOT_API
twa_graph_ptr mask_keep_states(const const_twa_graph_ptr& in,
std::vector<bool>& to_keep,
unsigned int init);
std::vector<bool>& to_keep,
unsigned int init);
}

View file

@ -58,16 +58,16 @@ namespace spot
{
static std::ostream&
dump_hash_set(const hash_set* hs,
const const_twa_ptr& aut,
std::ostream& out)
const const_twa_ptr& aut,
std::ostream& out)
{
out << '{';
const char* sep = "";
for (hash_set::const_iterator i = hs->begin(); i != hs->end(); ++i)
{
out << sep << aut->format_state(*i);
sep = ", ";
}
{
out << sep << aut->format_state(*i);
sep = ", ";
}
out << '}';
return out;
}
@ -90,32 +90,32 @@ namespace spot
tovisit.push(init);
seen->insert(init);
while (!tovisit.empty())
{
const state* src = tovisit.front();
tovisit.pop();
{
const state* src = tovisit.front();
tovisit.pop();
for (auto sit: a->succ(src))
{
const state* dst = sit->dst();
// Is it a new state ?
if (seen->find(dst) == seen->end())
{
// Register the successor for later processing.
tovisit.push(dst);
seen->insert(dst);
}
else
dst->destroy();
}
}
for (auto sit: a->succ(src))
{
const state* dst = sit->dst();
// Is it a new state ?
if (seen->find(dst) == seen->end())
{
// Register the successor for later processing.
tovisit.push(dst);
seen->insert(dst);
}
else
dst->destroy();
}
}
}
// From the base automaton and the list of sets, build the minimal
// resulting automaton
static twa_graph_ptr
build_result(const const_twa_ptr& a,
std::list<hash_set*>& sets,
hash_set* final)
std::list<hash_set*>& sets,
hash_set* final)
{
auto dict = a->get_dict();
auto res = make_twa_graph(dict);
@ -128,76 +128,76 @@ namespace spot
hash_map state_num;
std::list<hash_set*>::iterator sit;
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set::iterator hit;
hash_set* h = *sit;
unsigned num = res->new_state();
for (hit = h->begin(); hit != h->end(); ++hit)
state_num[*hit] = num;
}
{
hash_set::iterator hit;
hash_set* h = *sit;
unsigned num = res->new_state();
for (hit = h->begin(); hit != h->end(); ++hit)
state_num[*hit] = num;
}
// For each transition in the initial automaton, add the corresponding
// transition in res.
if (!final->empty())
res->set_buchi();
res->set_buchi();
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set* h = *sit;
{
hash_set* h = *sit;
// Pick one state.
const state* src = *h->begin();
unsigned src_num = state_num[src];
bool accepting = (final->find(src) != final->end());
// Pick one state.
const state* src = *h->begin();
unsigned src_num = state_num[src];
bool accepting = (final->find(src) != final->end());
// Connect it to all destinations.
for (auto succit: a->succ(src))
{
const state* dst = succit->dst();
hash_map::const_iterator i = state_num.find(dst);
dst->destroy();
if (i == state_num.end()) // Ignore useless destinations.
continue;
res->new_acc_edge(src_num, i->second,
succit->cond(), accepting);
}
}
// Connect it to all destinations.
for (auto succit: a->succ(src))
{
const state* dst = succit->dst();
hash_map::const_iterator i = state_num.find(dst);
dst->destroy();
if (i == state_num.end()) // Ignore useless destinations.
continue;
res->new_acc_edge(src_num, i->second,
succit->cond(), accepting);
}
}
res->merge_edges();
if (res->num_states() > 0)
{
const state* init_state = a->get_init_state();
unsigned init_num = state_num[init_state];
init_state->destroy();
res->set_init_state(init_num);
}
{
const state* init_state = a->get_init_state();
unsigned init_num = state_num[init_state];
init_state->destroy();
res->set_init_state(init_num);
}
return res;
}
struct wdba_search_acc_loop final : public bfs_steps
{
wdba_search_acc_loop(const const_twa_ptr& det_a,
unsigned scc_n, scc_info& sm,
power_map& pm, const state* dest)
: bfs_steps(det_a), scc_n(scc_n), sm(sm), pm(pm), dest(dest)
unsigned scc_n, scc_info& sm,
power_map& pm, const state* dest)
: bfs_steps(det_a), scc_n(scc_n), sm(sm), pm(pm), dest(dest)
{
seen(dest);
seen(dest);
}
virtual const state*
filter(const state* s) override
{
s = seen(s);
if (sm.scc_of(std::static_pointer_cast<const twa_graph>(a_)
->state_number(s)) != scc_n)
return nullptr;
return s;
s = seen(s);
if (sm.scc_of(std::static_pointer_cast<const twa_graph>(a_)
->state_number(s)) != scc_n)
return nullptr;
return s;
}
virtual bool
match(twa_run::step&, const state* to) override
{
return to == dest;
return to == dest;
}
unsigned scc_n;
@ -210,8 +210,8 @@ namespace spot
bool
wdba_scc_is_accepting(const const_twa_graph_ptr& det_a, unsigned scc_n,
const const_twa_graph_ptr& orig_a, scc_info& sm,
power_map& pm)
const const_twa_graph_ptr& orig_a, scc_info& sm,
power_map& pm)
{
// Get some state from the SCC #n.
const state* start = det_a->state_from_number(sm.one_state_of(scc_n));
@ -230,10 +230,10 @@ namespace spot
loop_a->new_states(loop_size);
int n;
for (n = 1, i = loop.begin(); n < loop_size; ++n, ++i)
{
loop_a->new_edge(n - 1, n, i->label);
i->s->destroy();
}
{
loop_a->new_edge(n - 1, n, i->label);
i->s->destroy();
}
assert(i != loop.end());
loop_a->new_edge(n - 1, 0, i->label);
i->s->destroy();
@ -246,23 +246,23 @@ namespace spot
// Iterate on each original state corresponding to start.
const power_map::power_state& ps =
pm.states_of(det_a->state_number(start));
pm.states_of(det_a->state_number(start));
for (auto& s: ps)
{
// Construct a product between LOOP_A and ORIG_A starting in
// S. FIXME: This could be sped up a lot!
if (!product(loop_a, orig_a, 0U, s)->is_empty())
{
accepting = true;
break;
}
}
{
// Construct a product between LOOP_A and ORIG_A starting in
// S. FIXME: This could be sped up a lot!
if (!product(loop_a, orig_a, 0U, s)->is_empty())
{
accepting = true;
break;
}
}
return accepting;
}
static twa_graph_ptr minimize_dfa(const const_twa_graph_ptr& det_a,
hash_set* final, hash_set* non_final)
hash_set* final, hash_set* non_final)
{
typedef std::list<hash_set*> partition_t;
partition_t cur_run;
@ -278,53 +278,53 @@ namespace spot
// Use bdd variables to number sets. set_num is the first variable
// available.
unsigned set_num =
det_a->get_dict()->register_anonymous_variables(size, det_a);
det_a->get_dict()->register_anonymous_variables(size, det_a);
std::set<int> free_var;
for (unsigned i = set_num; i < set_num + size; ++i)
free_var.insert(i);
free_var.insert(i);
std::map<int, int> used_var;
hash_set* final_copy;
if (!final->empty())
{
unsigned s = final->size();
used_var[set_num] = s;
free_var.erase(set_num);
if (s > 1)
cur_run.push_back(final);
else
done.push_back(final);
for (hash_set::const_iterator i = final->begin();
i != final->end(); ++i)
state_set_map[*i] = set_num;
{
unsigned s = final->size();
used_var[set_num] = s;
free_var.erase(set_num);
if (s > 1)
cur_run.push_back(final);
else
done.push_back(final);
for (hash_set::const_iterator i = final->begin();
i != final->end(); ++i)
state_set_map[*i] = set_num;
final_copy = new hash_set(*final);
}
final_copy = new hash_set(*final);
}
else
{
final_copy = final;
}
{
final_copy = final;
}
if (!non_final->empty())
{
unsigned s = non_final->size();
unsigned num = set_num + 1;
used_var[num] = s;
free_var.erase(num);
if (s > 1)
cur_run.push_back(non_final);
else
done.push_back(non_final);
for (hash_set::const_iterator i = non_final->begin();
i != non_final->end(); ++i)
state_set_map[*i] = num;
}
{
unsigned s = non_final->size();
unsigned num = set_num + 1;
used_var[num] = s;
free_var.erase(num);
if (s > 1)
cur_run.push_back(non_final);
else
done.push_back(non_final);
for (hash_set::const_iterator i = non_final->begin();
i != non_final->end(); ++i)
state_set_map[*i] = num;
}
else
{
delete non_final;
}
{
delete non_final;
}
// A bdd_states_map is a list of formulae (in a BDD form)
// associated with a destination set of states.
@ -333,119 +333,119 @@ namespace spot
bool did_split = true;
while (did_split)
{
did_split = false;
while (!cur_run.empty())
{
// Get a set to process.
hash_set* cur = cur_run.front();
cur_run.pop_front();
{
did_split = false;
while (!cur_run.empty())
{
// Get a set to process.
hash_set* cur = cur_run.front();
cur_run.pop_front();
trace << "processing " << format_hash_set(cur, det_a)
<< std::endl;
trace << "processing " << format_hash_set(cur, det_a)
<< std::endl;
hash_set::iterator hi;
bdd_states_map bdd_map;
for (hi = cur->begin(); hi != cur->end(); ++hi)
{
const state* src = *hi;
bdd f = bddfalse;
for (auto si: det_a->succ(src))
{
const state* dst = si->dst();
hash_map::const_iterator i = state_set_map.find(dst);
dst->destroy();
if (i == state_set_map.end())
// The destination state is not in our
// partition. This can happen if the initial
// FINAL and NON_FINAL supplied to the algorithm
// do not cover the whole automaton (because we
// want to ignore some useless states). Simply
// ignore these states here.
continue;
f |= (bdd_ithvar(i->second) & si->cond());
}
hash_set::iterator hi;
bdd_states_map bdd_map;
for (hi = cur->begin(); hi != cur->end(); ++hi)
{
const state* src = *hi;
bdd f = bddfalse;
for (auto si: det_a->succ(src))
{
const state* dst = si->dst();
hash_map::const_iterator i = state_set_map.find(dst);
dst->destroy();
if (i == state_set_map.end())
// The destination state is not in our
// partition. This can happen if the initial
// FINAL and NON_FINAL supplied to the algorithm
// do not cover the whole automaton (because we
// want to ignore some useless states). Simply
// ignore these states here.
continue;
f |= (bdd_ithvar(i->second) & si->cond());
}
// Have we already seen this formula ?
bdd_states_map::iterator bsi = bdd_map.find(f);
if (bsi == bdd_map.end())
{
// No, create a new set.
hash_set* new_set = new hash_set;
new_set->insert(src);
bdd_map[f] = new_set;
}
else
{
// Yes, add the current state to the set.
bsi->second->insert(src);
}
}
// Have we already seen this formula ?
bdd_states_map::iterator bsi = bdd_map.find(f);
if (bsi == bdd_map.end())
{
// No, create a new set.
hash_set* new_set = new hash_set;
new_set->insert(src);
bdd_map[f] = new_set;
}
else
{
// Yes, add the current state to the set.
bsi->second->insert(src);
}
}
bdd_states_map::iterator bsi = bdd_map.begin();
if (bdd_map.size() == 1)
{
// The set was not split.
trace << "set " << format_hash_set(bsi->second, det_a)
<< " was not split" << std::endl;
next_run.push_back(bsi->second);
}
else
{
did_split = true;
for (; bsi != bdd_map.end(); ++bsi)
{
hash_set* set = bsi->second;
// Free the number associated to these states.
unsigned num = state_set_map[*set->begin()];
assert(used_var.find(num) != used_var.end());
unsigned left = (used_var[num] -= set->size());
// Make sure LEFT does not become negative (hence bigger
// than SIZE when read as unsigned)
assert(left < size);
if (left == 0)
{
used_var.erase(num);
free_var.insert(num);
}
// Pick a free number
assert(!free_var.empty());
num = *free_var.begin();
free_var.erase(free_var.begin());
used_var[num] = set->size();
for (hash_set::iterator hit = set->begin();
hit != set->end(); ++hit)
state_set_map[*hit] = num;
// Trivial sets can't be splitted any further.
if (set->size() == 1)
{
trace << "set " << format_hash_set(set, det_a)
<< " is minimal" << std::endl;
done.push_back(set);
}
else
{
trace << "set " << format_hash_set(set, det_a)
<< " should be processed further" << std::endl;
next_run.push_back(set);
}
}
}
delete cur;
}
if (did_split)
trace << "splitting did occur during this pass." << std::endl;
else
trace << "splitting did not occur during this pass." << std::endl;
std::swap(cur_run, next_run);
}
bdd_states_map::iterator bsi = bdd_map.begin();
if (bdd_map.size() == 1)
{
// The set was not split.
trace << "set " << format_hash_set(bsi->second, det_a)
<< " was not split" << std::endl;
next_run.push_back(bsi->second);
}
else
{
did_split = true;
for (; bsi != bdd_map.end(); ++bsi)
{
hash_set* set = bsi->second;
// Free the number associated to these states.
unsigned num = state_set_map[*set->begin()];
assert(used_var.find(num) != used_var.end());
unsigned left = (used_var[num] -= set->size());
// Make sure LEFT does not become negative (hence bigger
// than SIZE when read as unsigned)
assert(left < size);
if (left == 0)
{
used_var.erase(num);
free_var.insert(num);
}
// Pick a free number
assert(!free_var.empty());
num = *free_var.begin();
free_var.erase(free_var.begin());
used_var[num] = set->size();
for (hash_set::iterator hit = set->begin();
hit != set->end(); ++hit)
state_set_map[*hit] = num;
// Trivial sets can't be splitted any further.
if (set->size() == 1)
{
trace << "set " << format_hash_set(set, det_a)
<< " is minimal" << std::endl;
done.push_back(set);
}
else
{
trace << "set " << format_hash_set(set, det_a)
<< " should be processed further" << std::endl;
next_run.push_back(set);
}
}
}
delete cur;
}
if (did_split)
trace << "splitting did occur during this pass." << std::endl;
else
trace << "splitting did not occur during this pass." << std::endl;
std::swap(cur_run, next_run);
}
done.splice(done.end(), cur_run);
#ifdef TRACE
trace << "Final partition: ";
for (partition_t::const_iterator i = done.begin(); i != done.end(); ++i)
trace << format_hash_set(*i, det_a) << ' ';
trace << format_hash_set(*i, det_a) << ' ';
trace << std::endl;
#endif
@ -456,13 +456,13 @@ namespace spot
delete final_copy;
hash_map::iterator hit;
for (hit = state_set_map.begin(); hit != state_set_map.end();)
{
hash_map::iterator old = hit++;
old->first->destroy();
}
{
hash_map::iterator old = hit++;
old->first->destroy();
}
std::list<hash_set*>::iterator it;
for (it = done.begin(); it != done.end(); ++it)
delete *it;
delete *it;
return res;
}
@ -522,60 +522,60 @@ namespace spot
// SCC are numbered in topological order
// (but in the reverse order as Löding's)
for (unsigned m = 0; m < scc_count; ++m)
{
bool is_useless = true;
bool transient = sm.is_trivial(m);
auto& succ = sm.succ(m);
{
bool is_useless = true;
bool transient = sm.is_trivial(m);
auto& succ = sm.succ(m);
if (transient && succ.empty())
{
// A trivial SCC without successor is useless.
useless[m] = true;
d[m] = k - 1;
continue;
}
if (transient && succ.empty())
{
// A trivial SCC without successor is useless.
useless[m] = true;
d[m] = k - 1;
continue;
}
// Compute the minimum color l of the successors.
// Also SCCs are useless if all their successor are
// useless.
unsigned l = k;
for (unsigned j: succ)
{
is_useless &= useless[j];
unsigned dj = d[j];
if (dj < l)
l = dj;
}
// Compute the minimum color l of the successors.
// Also SCCs are useless if all their successor are
// useless.
unsigned l = k;
for (unsigned j: succ)
{
is_useless &= useless[j];
unsigned dj = d[j];
if (dj < l)
l = dj;
}
if (transient)
{
d[m] = l;
}
else
{
// Regular SCCs are accepting if any of their loop
// corresponds to an accepted word in the original
// automaton.
if (wdba_scc_is_accepting(det_a, m, a, sm, pm))
{
is_useless = false;
d[m] = l & ~1; // largest even number inferior or equal
}
else
{
d[m] = (l - 1) | 1; // largest odd number inferior or equal
}
}
if (transient)
{
d[m] = l;
}
else
{
// Regular SCCs are accepting if any of their loop
// corresponds to an accepted word in the original
// automaton.
if (wdba_scc_is_accepting(det_a, m, a, sm, pm))
{
is_useless = false;
d[m] = l & ~1; // largest even number inferior or equal
}
else
{
d[m] = (l - 1) | 1; // largest odd number inferior or equal
}
}
useless[m] = is_useless;
useless[m] = is_useless;
if (!is_useless)
{
hash_set* dest_set = (d[m] & 1) ? non_final : final;
for (auto s: sm.states_of(m))
dest_set->insert(det_a->state_from_number(s));
}
}
if (!is_useless)
{
hash_set* dest_set = (d[m] & 1) ? non_final : final;
for (auto s: sm.states_of(m))
dest_set->insert(det_a->state_from_number(s));
}
}
}
auto res = minimize_dfa(det_a, final, non_final);
@ -597,18 +597,18 @@ namespace spot
twa_graph_ptr
minimize_obligation(const const_twa_graph_ptr& aut_f,
formula f,
const_twa_graph_ptr aut_neg_f,
bool reject_bigger)
formula f,
const_twa_graph_ptr aut_neg_f,
bool reject_bigger)
{
auto min_aut_f = minimize_wdba(aut_f);
if (reject_bigger)
{
// Abort if min_aut_f has more states than aut_f.
unsigned orig_states = aut_f->num_states();
if (orig_states < min_aut_f->num_states())
return std::const_pointer_cast<twa_graph>(aut_f);
// Abort if min_aut_f has more states than aut_f.
unsigned orig_states = aut_f->num_states();
if (orig_states < min_aut_f->num_states())
return std::const_pointer_cast<twa_graph>(aut_f);
}
// If the input automaton was already weak and deterministic, the
@ -629,25 +629,25 @@ namespace spot
// Build negation automaton if not supplied.
if (!aut_neg_f)
{
if (f)
{
// If we know the formula, simply build the automaton for
// its negation.
aut_neg_f = ltl_to_tgba_fm(formula::Not(f), aut_f->get_dict());
// Remove useless SCCs.
aut_neg_f = scc_filter(aut_neg_f, true);
}
else if (is_deterministic(aut_f))
{
// If the automaton is deterministic, complementing is
// easy.
aut_neg_f = remove_fin(dtwa_complement(aut_f));
}
else
{
// Otherwise, we cannot check if the minimization is safe.
return nullptr;
}
if (f)
{
// If we know the formula, simply build the automaton for
// its negation.
aut_neg_f = ltl_to_tgba_fm(formula::Not(f), aut_f->get_dict());
// Remove useless SCCs.
aut_neg_f = scc_filter(aut_neg_f, true);
}
else if (is_deterministic(aut_f))
{
// If the automaton is deterministic, complementing is
// easy.
aut_neg_f = remove_fin(dtwa_complement(aut_f));
}
else
{
// Otherwise, we cannot check if the minimization is safe.
return nullptr;
}
}
// If the negation is a guarantee automaton, then the
@ -659,13 +659,13 @@ namespace spot
if (product(min_aut_f, aut_neg_f)->is_empty())
{
// Complement the minimized WDBA.
assert((bool)min_aut_f->prop_weak());
auto neg_min_aut_f = remove_fin(dtwa_complement(min_aut_f));
if (product(aut_f, neg_min_aut_f)->is_empty())
// Finally, we are now sure that it was safe
// to minimize the automaton.
ok = true;
// Complement the minimized WDBA.
assert((bool)min_aut_f->prop_weak());
auto neg_min_aut_f = remove_fin(dtwa_complement(min_aut_f));
if (product(aut_f, neg_min_aut_f)->is_empty())
// Finally, we are now sure that it was safe
// to minimize the automaton.
ok = true;
}
if (ok)

View file

@ -37,16 +37,16 @@ namespace spot
///
/// For more detail about monitors, see the following paper:
/** \verbatim
@InProceedings{ tabakov.10.rv,
author = {Deian Tabakov and Moshe Y. Vardi},
title = {Optimized Temporal Monitors for SystemC{$^*$}},
@InProceedings{ tabakov.10.rv,
author = {Deian Tabakov and Moshe Y. Vardi},
title = {Optimized Temporal Monitors for SystemC{$^*$}},
booktitle = {Proceedings of the 10th International Conferance
on Runtime Verification},
pages = {436--451},
year = 2010,
volume = {6418},
series = {Lecture Notes in Computer Science},
month = nov,
pages = {436--451},
year = 2010,
volume = {6418},
series = {Lecture Notes in Computer Science},
month = nov,
publisher = {Spring-Verlag}
}
\endverbatim */
@ -76,19 +76,19 @@ namespace spot
/// technique.
///
/** \verbatim
@InProceedings{ dax.07.atva,
author = {Christian Dax and Jochen Eisinger and Felix Klaedtke},
@InProceedings{ dax.07.atva,
author = {Christian Dax and Jochen Eisinger and Felix Klaedtke},
title = {Mechanizing the Powerset Construction for Restricted
Classes of {$\omega$}-Automata},
Classes of {$\omega$}-Automata},
year = 2007,
series = {Lecture Notes in Computer Science},
series = {Lecture Notes in Computer Science},
publisher = {Springer-Verlag},
volume = 4762,
volume = 4762,
booktitle = {Proceedings of the 5th International Symposium on
Automated Technology for Verification and Analysis
(ATVA'07)},
editor = {Kedar S. Namjoshi and Tomohiro Yoneda and Teruo Higashino
and Yoshio Okamura},
Automated Technology for Verification and Analysis
(ATVA'07)},
editor = {Kedar S. Namjoshi and Tomohiro Yoneda and Teruo Higashino
and Yoshio Okamura},
month = oct
}
\endverbatim */
@ -101,19 +101,19 @@ namespace spot
/// by the following paper:
///
/** \verbatim
@InProceedings{ dax.07.atva,
author = {Christian Dax and Jochen Eisinger and Felix Klaedtke},
@InProceedings{ dax.07.atva,
author = {Christian Dax and Jochen Eisinger and Felix Klaedtke},
title = {Mechanizing the Powerset Construction for Restricted
Classes of {$\omega$}-Automata},
Classes of {$\omega$}-Automata},
year = 2007,
series = {Lecture Notes in Computer Science},
series = {Lecture Notes in Computer Science},
publisher = {Springer-Verlag},
volume = 4762,
volume = 4762,
booktitle = {Proceedings of the 5th International Symposium on
Automated Technology for Verification and Analysis
(ATVA'07)},
editor = {Kedar S. Namjoshi and Tomohiro Yoneda and Teruo Higashino
and Yoshio Okamura},
Automated Technology for Verification and Analysis
(ATVA'07)},
editor = {Kedar S. Namjoshi and Tomohiro Yoneda and Teruo Higashino
and Yoshio Okamura},
month = oct
}
\endverbatim */
@ -151,8 +151,8 @@ namespace spot
/// that the minimized WDBA is correct.
SPOT_API twa_graph_ptr
minimize_obligation(const const_twa_graph_ptr& aut_f,
formula f = nullptr,
const_twa_graph_ptr aut_neg_f = nullptr,
bool reject_bigger = false);
formula f = nullptr,
const_twa_graph_ptr aut_neg_f = nullptr,
bool reject_bigger = false);
/// @}
}

View file

@ -79,8 +79,8 @@ namespace spot
virtual unsigned
acss_states() const override
{
// all visited states are in the state space search
return static_cast<const T*>(this)->h_.size();
// all visited states are in the state space search
return static_cast<const T*>(this)->h_.size();
}
};
@ -127,7 +127,7 @@ namespace spot
if (i == str.end())
i = stb.begin();
transition t = { i->s->clone(), j->label, j->acc,
j->s->clone() };
j->s->clone() };
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
@ -139,7 +139,7 @@ namespace spot
i = j = stb.rbegin(); ++j;
while (i->s->compare(start) != 0)
++i, ++j;
++i, ++j;
stack_type::const_reverse_iterator end = stb.rend();
for (; j != end; ++i, ++j)
@ -147,7 +147,7 @@ namespace spot
if ((covered_acc & j->acc) != j->acc)
{
transition t = { i->s->clone(), j->label, j->acc,
j->s->clone() };
j->s->clone() };
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
@ -159,11 +159,11 @@ namespace spot
if ((covered_acc & j->acc) != j->acc)
{
transition t = { i->s->clone(), j->label, j->acc,
j->s->clone() };
j->s->clone() };
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
covered_acc |= j->acc;
covered_acc |= j->acc;
}
i = j; ++j;
@ -173,7 +173,7 @@ namespace spot
if ((covered_acc & j->acc) != j->acc)
{
transition t = { i->s->clone(), j->label, j->acc,
j->s->clone() };
j->s->clone() };
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
@ -203,7 +203,7 @@ namespace spot
construct_prefix(run);
for (typename accepting_transitions_list::const_iterator i =
acc_trans.begin(); i != acc_trans.end(); ++i)
acc_trans.begin(); i != acc_trans.end(); ++i)
{
i->source->destroy();
i->dest->destroy();
@ -227,32 +227,32 @@ namespace spot
typedef std::list<transition> accepting_transitions_list;
typedef std::unordered_set<const state*,
state_ptr_hash, state_ptr_equal> state_set;
state_ptr_hash, state_ptr_equal> state_set;
void clean(const const_twa_ptr& a, stack_type& st1,
state_set& seen, state_set& dead)
state_set& seen, state_set& dead)
{
while (!st1.empty())
{
a->release_iter(st1.front().it);
st1.pop_front();
}
{
a->release_iter(st1.front().it);
st1.pop_front();
}
for (state_set::iterator i = seen.begin(); i != seen.end();)
{
const state* s = *i;
++i;
s->destroy();
}
{
const state* s = *i;
++i;
s->destroy();
}
for (state_set::iterator i = dead.begin(); i != dead.end();)
{
const state* s = *i;
++i;
s->destroy();
}
{
const state* s = *i;
++i;
s->destroy();
}
}
bool dfs(const state* target, accepting_transitions_list& acc_trans,
acc_cond::mark_t& covered_acc)
acc_cond::mark_t& covered_acc)
{
assert(h_.has_been_visited(target));
stack_type st1;
@ -276,7 +276,7 @@ namespace spot
ndfsr_trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->cond();
auto acc = f.it->acc();
auto acc = f.it->acc();
f.it->next();
if (h_.has_been_visited(s_prime))
{
@ -287,7 +287,7 @@ namespace spot
}
else if (seen.find(s_prime) == seen.end())
{
this->inc_ars_cycle_states();
this->inc_ars_cycle_states();
ndfsr_trace << " it is not seen, go down" << std::endl;
seen.insert(s_prime);
twa_succ_iterator* i = a_->succ_iter(s_prime);
@ -296,13 +296,13 @@ namespace spot
}
else if ((acc & covered_acc) != acc)
{
this->inc_ars_cycle_states();
this->inc_ars_cycle_states();
ndfsr_trace << " a propagation is needed, "
<< "start a search" << std::endl;
if (search(s_prime, target, dead))
{
transition t = { f.s->clone(), label, acc,
s_prime->clone() };
s_prime->clone() };
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
@ -342,13 +342,13 @@ namespace spot
<< std::endl;
if (search(f_dest.s, target, dead))
{
transition t = { st1.front().s->clone(),
f_dest.label, f_dest.acc,
f_dest.s->clone() };
transition t = { st1.front().s->clone(),
f_dest.label, f_dest.acc,
f_dest.s->clone() };
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
covered_acc |= f_dest.acc;
covered_acc |= f_dest.acc;
if (a_->acc().accepting(covered_acc))
{
clean(a_, st1, seen, dead);
@ -372,8 +372,8 @@ namespace spot
{
public:
test_path(ars_statistics* ars,
const const_twa_ptr& a, const state* t,
const state_set& d, const heap& h)
const const_twa_ptr& a, const state* t,
const state_set& d, const heap& h)
: bfs_steps(a), ars(ars), target(t), dead(d), h(h)
{
}
@ -401,20 +401,20 @@ namespace spot
const state* filter(const state* s)
{
if (!h.has_been_visited(s)
|| seen.find(s) != seen.end()
|| dead.find(s) != dead.end())
|| seen.find(s) != seen.end()
|| dead.find(s) != dead.end())
{
s->destroy();
return nullptr;
}
ars->inc_ars_cycle_states();
ars->inc_ars_cycle_states();
seen.insert(s);
return s;
}
void finalize(const std::map<const state*, twa_run::step,
state_ptr_less_than>&,
const twa_run::step&, const state*, twa_run::steps&)
state_ptr_less_than>&,
const twa_run::step&, const state*, twa_run::steps&)
{
}
@ -440,35 +440,35 @@ namespace spot
{
twa_run::steps path;
if (start->compare(target) == 0)
return true;
return true;
test_path s(this, a_, target, dead, h_);
const state* res = s.search(start->clone(), path);
if (res)
{
assert(res->compare(target) == 0);
return true;
}
{
assert(res->compare(target) == 0);
return true;
}
else
{
state_set::const_iterator it;
for (it = s.get_seen().begin(); it != s.get_seen().end(); ++it)
dead.insert((*it)->clone());
return false;
}
{
state_set::const_iterator it;
for (it = s.get_seen().begin(); it != s.get_seen().end(); ++it)
dead.insert((*it)->clone());
return false;
}
}
typedef std::unordered_multimap<const state*, transition,
state_ptr_hash,
state_ptr_equal> m_source_trans;
state_ptr_hash,
state_ptr_equal> m_source_trans;
template<bool cycle>
class min_path: public bfs_steps
{
public:
min_path(ars_statistics* ars,
const const_twa_ptr& a,
const m_source_trans& target, const heap& h)
const const_twa_ptr& a,
const m_source_trans& target, const heap& h)
: bfs_steps(a), ars(ars), target(target), h(h)
{
}
@ -506,10 +506,10 @@ namespace spot
return nullptr;
}
ndfsr_trace << " OK" << std::endl;
if (cycle)
ars->inc_ars_cycle_states();
else
ars->inc_ars_prefix_states();
if (cycle)
ars->inc_ars_cycle_states();
else
ars->inc_ars_prefix_states();
seen.insert(s);
return s;
}
@ -529,92 +529,92 @@ namespace spot
};
void construct_cycle(twa_run_ptr run,
const accepting_transitions_list& acc_trans)
const accepting_transitions_list& acc_trans)
{
assert(!acc_trans.empty());
transition current = acc_trans.front();
// insert the first accepting transition in the cycle
ndfsr_trace << "the initial accepting transition is from "
<< a_->format_state(current.source) << " to "
<< a_->format_state(current.dest) << std::endl;
<< a_->format_state(current.source) << " to "
<< a_->format_state(current.dest) << std::endl;
const state* begin = current.source;
m_source_trans target;
typename accepting_transitions_list::const_iterator i =
acc_trans.begin();
acc_trans.begin();
ndfsr_trace << "targets are the source states: ";
for (++i; i != acc_trans.end(); ++i)
{
if (i->source->compare(begin) == 0 &&
i->source->compare(i->dest) == 0)
{
ndfsr_trace << "(self loop " << a_->format_state(i->source)
<< " -> " << a_->format_state(i->dest)
<< " ignored) ";
twa_run::step st = { i->source->clone(), i->label, i->acc };
run->cycle.push_back(st);
}
else
{
ndfsr_trace << a_->format_state(i->source) << " (-> "
<< a_->format_state(i->dest) << ") ";
target.emplace(i->source, *i);
}
}
{
if (i->source->compare(begin) == 0 &&
i->source->compare(i->dest) == 0)
{
ndfsr_trace << "(self loop " << a_->format_state(i->source)
<< " -> " << a_->format_state(i->dest)
<< " ignored) ";
twa_run::step st = { i->source->clone(), i->label, i->acc };
run->cycle.push_back(st);
}
else
{
ndfsr_trace << a_->format_state(i->source) << " (-> "
<< a_->format_state(i->dest) << ") ";
target.emplace(i->source, *i);
}
}
ndfsr_trace << std::endl;
twa_run::step st = { current.source->clone(), current.label,
current.acc };
current.acc };
run->cycle.push_back(st);
while (!target.empty())
{
// find a minimal path from current.dest to any source state in
// target.
ndfsr_trace << "looking for a path from "
<< a_->format_state(current.dest) << std::endl;
typename m_source_trans::iterator i = target.find(current.dest);
if (i == target.end())
{
min_path<true> s(this, a_, target, h_);
const state* res = s.search(current.dest->clone(), run->cycle);
// init current to the corresponding transition.
assert(res);
ndfsr_trace << a_->format_state(res) << " reached" << std::endl;
i = target.find(res);
assert(i != target.end());
}
else
{
ndfsr_trace << "this is a target" << std::endl;
}
current = i->second;
// complete the path with the corresponding transition
twa_run::step st = { current.source->clone(), current.label,
current.acc };
run->cycle.push_back(st);
// remove this source state of target
target.erase(i);
}
{
// find a minimal path from current.dest to any source state in
// target.
ndfsr_trace << "looking for a path from "
<< a_->format_state(current.dest) << std::endl;
typename m_source_trans::iterator i = target.find(current.dest);
if (i == target.end())
{
min_path<true> s(this, a_, target, h_);
const state* res = s.search(current.dest->clone(), run->cycle);
// init current to the corresponding transition.
assert(res);
ndfsr_trace << a_->format_state(res) << " reached" << std::endl;
i = target.find(res);
assert(i != target.end());
}
else
{
ndfsr_trace << "this is a target" << std::endl;
}
current = i->second;
// complete the path with the corresponding transition
twa_run::step st = { current.source->clone(), current.label,
current.acc };
run->cycle.push_back(st);
// remove this source state of target
target.erase(i);
}
if (current.dest->compare(begin) != 0)
{
// close the cycle by adding a path from the destination of the
// last inserted transition to the source of the first one
ndfsr_trace << std::endl << "looking for a path from "
<< a_->format_state(current.dest) << " to "
<< a_->format_state(begin) << std::endl;
transition tmp;
// Initialize to please GCC 4.0.1 (Darwin).
tmp.source = tmp.dest = nullptr;
tmp.acc = 0U;
target.emplace(begin, tmp);
min_path<true> s(this, a_, target, h_);
const state* res = s.search(current.dest->clone(), run->cycle);
assert(res);
assert(res->compare(begin) == 0);
(void)res;
}
{
// close the cycle by adding a path from the destination of the
// last inserted transition to the source of the first one
ndfsr_trace << std::endl << "looking for a path from "
<< a_->format_state(current.dest) << " to "
<< a_->format_state(begin) << std::endl;
transition tmp;
// Initialize to please GCC 4.0.1 (Darwin).
tmp.source = tmp.dest = nullptr;
tmp.acc = 0U;
target.emplace(begin, tmp);
min_path<true> s(this, a_, target, h_);
const state* res = s.search(current.dest->clone(), run->cycle);
assert(res);
assert(res->compare(begin) == 0);
(void)res;
}
}
void construct_prefix(twa_run_ptr run)
@ -626,7 +626,7 @@ namespace spot
// Register all states from the cycle as target of the BFS.
for (twa_run::steps::const_iterator i = run->cycle.begin();
i != run->cycle.end(); ++i)
i != run->cycle.end(); ++i)
target.emplace(i->s, tmp);
const state* prefix_start = a_->get_init_state();
@ -655,8 +655,8 @@ namespace spot
// Locate cycle_entry_point on the cycle.
twa_run::steps::iterator cycle_ep_it;
for (cycle_ep_it = run->cycle.begin();
cycle_ep_it != run->cycle.end()
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
cycle_ep_it != run->cycle.end()
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
continue;
assert(cycle_ep_it != run->cycle.end());
cycle_entry_point->destroy();

View file

@ -47,167 +47,167 @@ namespace spot
public:
never_claim_output(std::ostream& os, const char* options)
: os_(os)
: os_(os)
{
if (options)
while (char c = *options++)
switch (c)
{
case '6':
opt_624_ = true;
break;
case 'c':
opt_comments_ = true;
break;
default:
throw std::runtime_error
(std::string("unknown option for print_never_claim(): ")
+ c);
}
if (options)
while (char c = *options++)
switch (c)
{
case '6':
opt_624_ = true;
break;
case 'c':
opt_comments_ = true;
break;
default:
throw std::runtime_error
(std::string("unknown option for print_never_claim(): ")
+ c);
}
}
void
start() const
{
os_ << "never {";
auto n = aut_->get_named_prop<std::string>("automaton-name");
if (n)
os_ << " /* " << *n << " */";
os_ << '\n';
os_ << "never {";
auto n = aut_->get_named_prop<std::string>("automaton-name");
if (n)
os_ << " /* " << *n << " */";
os_ << '\n';
}
void
end() const
{
if (need_accept_all_)
{
os_ << "accept_all:";
print_comment(accept_all_);
os_ << "\n skip\n";
}
os_ << '}' << std::endl;
if (need_accept_all_)
{
os_ << "accept_all:";
print_comment(accept_all_);
os_ << "\n skip\n";
}
os_ << '}' << std::endl;
}
bool is_sink(unsigned n) const
{
auto ts = aut_->out(n);
assert(ts.begin() != ts.end());
auto it = ts.begin();
return (it->cond == bddtrue) && (it->dst == n) && (++it == ts.end());
auto ts = aut_->out(n);
assert(ts.begin() != ts.end());
auto it = ts.begin();
return (it->cond == bddtrue) && (it->dst == n) && (++it == ts.end());
}
void
print_comment(unsigned n) const
{
if (sn_)
if (n < sn_->size() && !(*sn_)[n].empty())
os_ << " /* " << (*sn_)[n] << " */";
if (sn_)
if (n < sn_->size() && !(*sn_)[n].empty())
os_ << " /* " << (*sn_)[n] << " */";
}
void
print_state(unsigned n) const
{
bool acc = aut_->state_is_accepting(n);
if (n == aut_->get_init_state_number())
{
if (acc)
os_ << "accept_init";
else
os_ << "T0_init";
}
else
{
if (!acc)
os_ << "T0_S" << n;
else if (is_sink(n))
os_ << "accept_all";
else
os_ << "accept_S" << n;
}
bool acc = aut_->state_is_accepting(n);
if (n == aut_->get_init_state_number())
{
if (acc)
os_ << "accept_init";
else
os_ << "T0_init";
}
else
{
if (!acc)
os_ << "T0_S" << n;
else if (is_sink(n))
os_ << "accept_all";
else
os_ << "accept_S" << n;
}
}
void process_state(unsigned n)
{
if (aut_->state_is_accepting(n) && is_sink(n)
&& n != aut_->get_init_state_number())
{
// We want the accept_all state at the end of the never claim.
need_accept_all_ = true;
accept_all_ = n;
return;
}
if (aut_->state_is_accepting(n) && is_sink(n)
&& n != aut_->get_init_state_number())
{
// We want the accept_all state at the end of the never claim.
need_accept_all_ = true;
accept_all_ = n;
return;
}
print_state(n);
os_ << ':';
print_comment(n);
os_ << (opt_624_ ? "\n do\n" : "\n if\n");
bool did_output = false;
for (auto& t: aut_->out(n))
{
did_output = true;
bool atom =
opt_624_ && aut_->state_is_accepting(t.dst) && is_sink(t.dst);
if (atom)
os_ << " :: atomic { (";
else
os_ << " :: (";
formula f = bdd_to_formula(t.cond, aut_->get_dict());
// This is actually a Boolean formula, but the LTL printer
// is all we have.
print_spin_ltl(os_, f, true);
if (atom)
{
os_ << ") -> assert(!(";
print_spin_ltl(os_, f, true);
os_ << ")) }";
}
else
{
os_ << ") -> goto ";
print_state(t.dst);
}
os_ << '\n';
}
if (!did_output)
{
if (opt_624_)
{
os_ << " :: atomic { (false) -> assert(!(false)) }";
}
else
{
os_ << " :: (false) -> goto ";
print_state(n);
}
os_ << '\n';
}
os_ << (opt_624_ ? " od;\n" : " fi;\n");
print_state(n);
os_ << ':';
print_comment(n);
os_ << (opt_624_ ? "\n do\n" : "\n if\n");
bool did_output = false;
for (auto& t: aut_->out(n))
{
did_output = true;
bool atom =
opt_624_ && aut_->state_is_accepting(t.dst) && is_sink(t.dst);
if (atom)
os_ << " :: atomic { (";
else
os_ << " :: (";
formula f = bdd_to_formula(t.cond, aut_->get_dict());
// This is actually a Boolean formula, but the LTL printer
// is all we have.
print_spin_ltl(os_, f, true);
if (atom)
{
os_ << ") -> assert(!(";
print_spin_ltl(os_, f, true);
os_ << ")) }";
}
else
{
os_ << ") -> goto ";
print_state(t.dst);
}
os_ << '\n';
}
if (!did_output)
{
if (opt_624_)
{
os_ << " :: atomic { (false) -> assert(!(false)) }";
}
else
{
os_ << " :: (false) -> goto ";
print_state(n);
}
os_ << '\n';
}
os_ << (opt_624_ ? " od;\n" : " fi;\n");
}
void print(const const_twa_graph_ptr& aut)
{
aut_ = aut;
if (opt_comments_)
sn_ = aut->get_named_prop<std::vector<std::string>>("state-names");
start();
unsigned init = aut_->get_init_state_number();
unsigned ns = aut_->num_states();
process_state(init);
for (unsigned n = 0; n < ns; ++n)
if (n != init)
process_state(n);
end();
aut_ = aut;
if (opt_comments_)
sn_ = aut->get_named_prop<std::vector<std::string>>("state-names");
start();
unsigned init = aut_->get_init_state_number();
unsigned ns = aut_->num_states();
process_state(init);
for (unsigned n = 0; n < ns; ++n)
if (n != init)
process_state(n);
end();
}
};
} // anonymous namespace
std::ostream&
print_never_claim(std::ostream& os, const const_twa_ptr& g,
const char* options)
const char* options)
{
if (!(g->acc().is_buchi() || g->acc().is_all()))
throw std::runtime_error
("Never claim output only supports Büchi acceptance");
("Never claim output only supports Büchi acceptance");
never_claim_output d(os, options);
auto aut = std::dynamic_pointer_cast<const twa_graph>(g);
if (!aut)

View file

@ -40,6 +40,6 @@ namespace spot
/// \param opt a string of option: 'c' to comment each state
SPOT_API std::ostream&
print_never_claim(std::ostream& os,
const const_twa_ptr& g,
const char* opt = nullptr);
const const_twa_ptr& g,
const char* opt = nullptr);
}

View file

@ -43,11 +43,11 @@ namespace spot
ensure_ba(twa_graph_ptr& a)
{
if (a->num_sets() == 0)
{
auto m = a->set_buchi();
for (auto& t: a->edges())
t.acc = m;
}
{
auto m = a->set_buchi();
for (auto& t: a->edges())
t.acc = m;
}
return a;
}
}
@ -56,36 +56,36 @@ namespace spot
{
if (opt)
{
degen_order_ = opt->get("degen-order", 0);
degen_reset_ = opt->get("degen-reset", 1);
degen_cache_ = opt->get("degen-lcache", 1);
degen_lskip_ = opt->get("degen-lskip", 1);
degen_lowinit_ = opt->get("degen-lowinit", 0);
det_scc_ = opt->get("det-scc", 1);
det_simul_ = opt->get("det-simul", 1);
det_stutter_ = opt->get("det-stutter", 1);
simul_ = opt->get("simul", -1);
scc_filter_ = opt->get("scc-filter", -1);
ba_simul_ = opt->get("ba-simul", -1);
tba_determinisation_ = opt->get("tba-det", 0);
sat_minimize_ = opt->get("sat-minimize", 0);
sat_acc_ = opt->get("sat-acc", 0);
sat_states_ = opt->get("sat-states", 0);
state_based_ = opt->get("state-based", 0);
wdba_minimize_ = opt->get("wdba-minimize", 1);
degen_order_ = opt->get("degen-order", 0);
degen_reset_ = opt->get("degen-reset", 1);
degen_cache_ = opt->get("degen-lcache", 1);
degen_lskip_ = opt->get("degen-lskip", 1);
degen_lowinit_ = opt->get("degen-lowinit", 0);
det_scc_ = opt->get("det-scc", 1);
det_simul_ = opt->get("det-simul", 1);
det_stutter_ = opt->get("det-stutter", 1);
simul_ = opt->get("simul", -1);
scc_filter_ = opt->get("scc-filter", -1);
ba_simul_ = opt->get("ba-simul", -1);
tba_determinisation_ = opt->get("tba-det", 0);
sat_minimize_ = opt->get("sat-minimize", 0);
sat_acc_ = opt->get("sat-acc", 0);
sat_states_ = opt->get("sat-states", 0);
state_based_ = opt->get("state-based", 0);
wdba_minimize_ = opt->get("wdba-minimize", 1);
if (sat_acc_ && sat_minimize_ == 0)
sat_minimize_ = 1; // 2?
if (sat_states_ && sat_minimize_ == 0)
sat_minimize_ = 1;
if (sat_minimize_)
{
tba_determinisation_ = 1;
if (sat_acc_ <= 0)
sat_acc_ = -1;
if (sat_states_ <= 0)
sat_states_ = -1;
}
if (sat_acc_ && sat_minimize_ == 0)
sat_minimize_ = 1; // 2?
if (sat_states_ && sat_minimize_ == 0)
sat_minimize_ = 1;
if (sat_minimize_)
{
tba_determinisation_ = 1;
if (sat_acc_ <= 0)
sat_acc_ = -1;
if (sat_states_ <= 0)
sat_states_ = -1;
}
}
}
@ -97,14 +97,14 @@ namespace spot
switch (opt)
{
case 0:
return a;
return a;
case 1:
return simulation(a);
return simulation(a);
case 2:
return cosimulation(a);
return cosimulation(a);
case 3:
default:
return iterated_simulations(a);
return iterated_simulations(a);
}
}
@ -116,14 +116,14 @@ namespace spot
switch (opt)
{
case 0:
return a;
return a;
case 1:
return simulation_sba(a);
return simulation_sba(a);
case 2:
return cosimulation_sba(a);
return cosimulation_sba(a);
case 3:
default:
return iterated_simulations_sba(a);
return iterated_simulations_sba(a);
}
}
@ -131,9 +131,9 @@ namespace spot
postprocessor::do_degen(const twa_graph_ptr& a)
{
auto d = degeneralize(a,
degen_reset_, degen_order_,
degen_cache_, degen_lskip_,
degen_lowinit_);
degen_reset_, degen_order_,
degen_cache_, degen_lskip_,
degen_lowinit_);
return do_sba_simul(d, ba_simul_);
}
@ -145,7 +145,7 @@ namespace spot
// If the automaton is weak, using transition-based acceptance
// won't help, so let's preserve it.
if ((state_based_ || a->prop_inherently_weak().is_true())
&& a->prop_state_acc().is_true())
&& a->prop_state_acc().is_true())
return scc_filter_states(a, arg);
else
return scc_filter(a, arg);
@ -175,22 +175,22 @@ namespace spot
if (type_ != Generic && !a->acc().is_generalized_buchi())
{
a = to_generalized_buchi(a);
if (PREF_ == Any && level_ == Low)
a = do_scc_filter(a, true);
a = to_generalized_buchi(a);
if (PREF_ == Any && level_ == Low)
a = do_scc_filter(a, true);
}
if (PREF_ == Any && level_ == Low
&& (type_ == Generic
|| type_ == TGBA
|| (type_ == BA && a->is_sba())
|| (type_ == Monitor && a->num_sets() == 0)))
&& (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 (COMP_)
a = complete(a);
if (SBACC_)
a = sbacc(a);
return a;
}
int original_acc = a->num_sets();
@ -205,38 +205,38 @@ namespace spot
if (type_ == Monitor)
{
if (PREF_ == Deterministic)
a = minimize_monitor(a);
else
strip_acceptance_here(a);
if (PREF_ == Deterministic)
a = minimize_monitor(a);
else
strip_acceptance_here(a);
if (PREF_ == Any)
return a;
if (PREF_ == Any)
return a;
a = do_simul(a, simul_);
a = do_simul(a, simul_);
// For Small,High we return the smallest between the output of
// the simulation, and that of the deterministic minimization.
if (PREF_ == Small && level_ == High && simul_)
{
auto m = minimize_monitor(a);
if (m->num_states() < a->num_states())
a = m;
}
if (COMP_)
a = complete(a);
return a;
// For Small,High we return the smallest between the output of
// the simulation, and that of the deterministic minimization.
if (PREF_ == Small && level_ == High && simul_)
{
auto m = minimize_monitor(a);
if (m->num_states() < a->num_states())
a = m;
}
if (COMP_)
a = complete(a);
return a;
}
if (PREF_ == Any)
{
if (type_ == BA)
a = do_degen(a);
if (COMP_)
a = complete(a);
if (SBACC_)
a = sbacc(a);
return a;
if (type_ == BA)
a = do_degen(a);
if (COMP_)
a = complete(a);
if (SBACC_)
a = sbacc(a);
return a;
}
bool dba_is_wdba = false;
@ -248,45 +248,45 @@ namespace spot
// WDBA-minimization.
if ((PREF_ != Small || level_ != Low) && wdba_minimize_)
{
bool reject_bigger = (PREF_ == Small) && (level_ == Medium);
dba = minimize_obligation(a, f, nullptr, reject_bigger);
if (dba
&& dba->prop_inherently_weak().is_true()
&& dba->prop_deterministic().is_true())
{
// The WDBA is a BA, so no degeneralization is required.
// We just need to add an acceptance set if there is none.
dba_is_minimal = dba_is_wdba = true;
if (type_ == BA)
ensure_ba(dba);
}
else
{
// Minimization failed.
dba = nullptr;
}
bool reject_bigger = (PREF_ == Small) && (level_ == Medium);
dba = minimize_obligation(a, f, nullptr, reject_bigger);
if (dba
&& dba->prop_inherently_weak().is_true()
&& dba->prop_deterministic().is_true())
{
// The WDBA is a BA, so no degeneralization is required.
// We just need to add an acceptance set if there is none.
dba_is_minimal = dba_is_wdba = true;
if (type_ == BA)
ensure_ba(dba);
}
else
{
// Minimization failed.
dba = nullptr;
}
}
// Run a simulation when wdba failed (or was not run), or
// at hard levels if we want a small output.
if (!dba || (level_ == High && PREF_ == Small))
{
if (((SBACC_ && a->prop_state_acc().is_true())
|| (type_ == BA && a->is_sba()))
&& !tba_determinisation_)
{
sim = do_sba_simul(a, ba_simul_);
}
else
{
sim = do_simul(a, simul_);
// Degeneralize the result of the simulation if needed.
// No need to do that if tba_determinisation_ will be used.
if (type_ == BA && !tba_determinisation_)
sim = do_degen(sim);
else if (SBACC_ && !tba_determinisation_)
sim = sbacc(sim);
}
if (((SBACC_ && a->prop_state_acc().is_true())
|| (type_ == BA && a->is_sba()))
&& !tba_determinisation_)
{
sim = do_sba_simul(a, ba_simul_);
}
else
{
sim = do_simul(a, simul_);
// Degeneralize the result of the simulation if needed.
// No need to do that if tba_determinisation_ will be used.
if (type_ == BA && !tba_determinisation_)
sim = do_degen(sim);
else if (SBACC_ && !tba_determinisation_)
sim = sbacc(sim);
}
}
// If WDBA failed, but the simulation returned a deterministic
@ -294,80 +294,80 @@ namespace spot
assert(dba || sim);
if (!dba && is_deterministic(sim))
{
std::swap(sim, dba);
// We postponed degeneralization above i case we would need
// to perform TBA-determinisation, but now it is clear
// that we won't perform it. So do degeneralize.
if (tba_determinisation_)
{
if (type_ == BA)
{
dba = do_degen(dba);
assert(is_deterministic(dba));
}
else if (SBACC_)
{
dba = sbacc(dba);
assert(is_deterministic(dba));
}
}
std::swap(sim, dba);
// We postponed degeneralization above i case we would need
// to perform TBA-determinisation, but now it is clear
// that we won't perform it. So do degeneralize.
if (tba_determinisation_)
{
if (type_ == BA)
{
dba = do_degen(dba);
assert(is_deterministic(dba));
}
else if (SBACC_)
{
dba = sbacc(dba);
assert(is_deterministic(dba));
}
}
}
// If we don't have a DBA, attempt tba-determinization if requested.
if (tba_determinisation_ && !dba)
{
twa_graph_ptr tmpd = nullptr;
if (PREF_ == Deterministic
&& f
&& f.is_syntactic_recurrence()
&& sim->num_sets() > 1)
tmpd = degeneralize_tba(sim);
twa_graph_ptr tmpd = nullptr;
if (PREF_ == Deterministic
&& f
&& f.is_syntactic_recurrence()
&& sim->num_sets() > 1)
tmpd = degeneralize_tba(sim);
auto in = tmpd ? tmpd : sim;
auto in = tmpd ? tmpd : sim;
// These thresholds are arbitrary.
//
// For producing Small automata, we assume that a
// deterministic automaton that is twice the size of the
// original will never get reduced to a smaller one. We also
// do not want more than 2^13 cycles in an SCC.
//
// For Deterministic automata, we accept automata that
// are 8 times bigger, with no more that 2^15 cycle per SCC.
// The cycle threshold is the most important limit here. You
// may up it if you want to try producing larger automata.
auto tmp =
tba_determinize_check(in,
(PREF_ == Small) ? 2 : 8,
1 << ((PREF_ == Small) ? 13 : 15),
f);
if (tmp && tmp != in)
{
// There is no point in running the reverse simulation on
// a deterministic automaton, since all prefixes are
// unique.
dba = simulation(tmp);
}
if (dba && PREF_ == Deterministic)
{
// disregard the result of the simulation.
sim = nullptr;
}
else
{
// degeneralize sim, because we did not do it earlier
if (type_ == BA)
sim = do_degen(sim);
}
// These thresholds are arbitrary.
//
// For producing Small automata, we assume that a
// deterministic automaton that is twice the size of the
// original will never get reduced to a smaller one. We also
// do not want more than 2^13 cycles in an SCC.
//
// For Deterministic automata, we accept automata that
// are 8 times bigger, with no more that 2^15 cycle per SCC.
// The cycle threshold is the most important limit here. You
// may up it if you want to try producing larger automata.
auto tmp =
tba_determinize_check(in,
(PREF_ == Small) ? 2 : 8,
1 << ((PREF_ == Small) ? 13 : 15),
f);
if (tmp && tmp != in)
{
// There is no point in running the reverse simulation on
// a deterministic automaton, since all prefixes are
// unique.
dba = simulation(tmp);
}
if (dba && PREF_ == Deterministic)
{
// disregard the result of the simulation.
sim = nullptr;
}
else
{
// degeneralize sim, because we did not do it earlier
if (type_ == BA)
sim = do_degen(sim);
}
}
if (PREF_ == Deterministic && type_ == Generic && !dba)
{
dba = tgba_determinize(to_generalized_buchi(sim),
false, det_scc_, det_simul_, det_stutter_);
if (level_ != Low)
dba = simulation(dba);
sim = nullptr;
dba = tgba_determinize(to_generalized_buchi(sim),
false, det_scc_, det_simul_, det_stutter_);
if (level_ != Low)
dba = simulation(dba);
sim = nullptr;
}
// Now dba contains either the result of WDBA-minimization (in
@ -379,101 +379,101 @@ namespace spot
// value in sat_minimize_ can force its use for debugging.
if (sat_minimize_ && dba && (!dba_is_wdba || sat_minimize_ < 0))
{
if (type_ == Generic)
throw std::runtime_error
("postproc() no yet updated to mix sat-minimize and Generic");
unsigned target_acc;
if (type_ == BA)
target_acc = 1;
else if (sat_acc_ != -1)
target_acc = sat_acc_;
else
// Take the number of acceptance conditions from the input
// automaton, not from dba, because dba often has been
// degeneralized by tba_determinize_check(). Make sure it
// is at least 1.
target_acc = original_acc > 0 ? original_acc : 1;
if (type_ == Generic)
throw std::runtime_error
("postproc() no yet updated to mix sat-minimize and Generic");
unsigned target_acc;
if (type_ == BA)
target_acc = 1;
else if (sat_acc_ != -1)
target_acc = sat_acc_;
else
// Take the number of acceptance conditions from the input
// automaton, not from dba, because dba often has been
// degeneralized by tba_determinize_check(). Make sure it
// is at least 1.
target_acc = original_acc > 0 ? original_acc : 1;
const_twa_graph_ptr in = nullptr;
if (target_acc == 1)
{
// If we are seeking a minimal DBA with unknown number of
// states, then we should start from the degeneralized,
// because the input TBA might be smaller.
if (state_based_)
in = degeneralize(dba);
else
in = degeneralize_tba(dba);
}
else
{
in = dba;
}
const_twa_graph_ptr in = nullptr;
if (target_acc == 1)
{
// If we are seeking a minimal DBA with unknown number of
// states, then we should start from the degeneralized,
// because the input TBA might be smaller.
if (state_based_)
in = degeneralize(dba);
else
in = degeneralize_tba(dba);
}
else
{
in = dba;
}
twa_graph_ptr res = complete(in);
if (target_acc == 1)
{
if (sat_states_ != -1)
res = dtba_sat_synthetize(res, sat_states_, state_based_);
else if (sat_minimize_ == 1 || sat_minimize_ == -1)
res = dtba_sat_minimize(res, state_based_);
else // sat_minimize_ == 2
res = dtba_sat_minimize_dichotomy(res, state_based_);
}
else
{
if (sat_states_ != -1)
res = dtwa_sat_synthetize
(res, target_acc,
acc_cond::acc_code::generalized_buchi(target_acc),
sat_states_, state_based_);
else if (sat_minimize_ == 1 || sat_minimize_ == -1)
res = dtwa_sat_minimize
(res, target_acc,
acc_cond::acc_code::generalized_buchi(target_acc),
state_based_);
else // sat_minimize_ == 2
res = dtwa_sat_minimize_dichotomy
(res, target_acc,
acc_cond::acc_code::generalized_buchi(target_acc),
state_based_);
}
twa_graph_ptr res = complete(in);
if (target_acc == 1)
{
if (sat_states_ != -1)
res = dtba_sat_synthetize(res, sat_states_, state_based_);
else if (sat_minimize_ == 1 || sat_minimize_ == -1)
res = dtba_sat_minimize(res, state_based_);
else // sat_minimize_ == 2
res = dtba_sat_minimize_dichotomy(res, state_based_);
}
else
{
if (sat_states_ != -1)
res = dtwa_sat_synthetize
(res, target_acc,
acc_cond::acc_code::generalized_buchi(target_acc),
sat_states_, state_based_);
else if (sat_minimize_ == 1 || sat_minimize_ == -1)
res = dtwa_sat_minimize
(res, target_acc,
acc_cond::acc_code::generalized_buchi(target_acc),
state_based_);
else // sat_minimize_ == 2
res = dtwa_sat_minimize_dichotomy
(res, target_acc,
acc_cond::acc_code::generalized_buchi(target_acc),
state_based_);
}
if (res)
{
dba = do_scc_filter(res, true);
dba_is_minimal = true;
}
if (res)
{
dba = do_scc_filter(res, true);
dba_is_minimal = true;
}
}
// Degeneralize the dba resulting from tba-determinization or
// sat-minimization (which is a TBA) if requested and needed.
if (dba && !dba_is_wdba && type_ == BA
&& !(dba_is_minimal && state_based_ && dba->num_sets() == 1))
&& !(dba_is_minimal && state_based_ && dba->num_sets() == 1))
dba = degeneralize(dba);
if (dba && sim)
{
if (dba->num_states() > sim->num_states())
dba = nullptr;
else
sim = nullptr;
if (dba->num_states() > sim->num_states())
dba = nullptr;
else
sim = nullptr;
}
if (level_ == High && scc_filter_ != 0)
{
if (dba)
{
// Do that even for WDBA, to remove marks from transitions
// leaving trivial SCCs.
dba = do_scc_filter(dba, true);
assert(!sim);
}
else if (sim)
{
sim = do_scc_filter(sim, true);
assert(!dba);
}
if (dba)
{
// Do that even for WDBA, to remove marks from transitions
// leaving trivial SCCs.
dba = do_scc_filter(dba, true);
assert(!sim);
}
else if (sim)
{
sim = do_scc_filter(sim, true);
assert(!dba);
}
}
sim = dba ? dba : sim;

View file

@ -95,10 +95,10 @@ namespace spot
enum
{
Any = 0,
Small = 1, // Small and Deterministic
Deterministic = 2, // are exclusive choices.
Small = 1, // Small and Deterministic
Deterministic = 2, // are exclusive choices.
Complete = 4,
SBAcc = 8, // State-based acceptance.
SBAcc = 8, // State-based acceptance.
Unambiguous = 16,
};
typedef int output_pref;

View file

@ -50,10 +50,10 @@ namespace spot
unsigned nap = 0;
int v = vin.id();
while (v != 1)
{
v = bdd_high(v);
++nap;
}
{
v = bdd_high(v);
++nap;
}
return nap;
}
@ -63,8 +63,8 @@ namespace spot
power_map::power_state ps;
unsigned ns = in->size();
for (unsigned pos = 0; pos < ns; ++pos)
if (in->get(pos))
ps.insert(pos);
if (in->get(pos))
ps.insert(pos);
return ps;
}
@ -72,7 +72,7 @@ namespace spot
{
size_t operator()(const bitvect* bv) const
{
return bv->hash();
return bv->hash();
}
};
@ -80,7 +80,7 @@ namespace spot
{
bool operator()(const bitvect* bvl, const bitvect* bvr) const
{
return *bvl == *bvr;
return *bvl == *bvr;
}
};
}
@ -94,9 +94,9 @@ namespace spot
sup_map sup;
// Record occurrences of all guards
for (auto& t: aut->edges())
sup.emplace(t.cond);
sup.emplace(t.cond);
for (auto& i: sup)
allap &= bdd_support(i);
allap &= bdd_support(i);
}
unsigned nap = number_of_variables(allap);
@ -118,13 +118,13 @@ namespace spot
bdd all = bddtrue;
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, allap, bddfalse);
all -= one;
bdd2num.emplace(one, num2bdd.size());
num2bdd.push_back(one);
bdd one = bdd_satoneset(all, allap, bddfalse);
all -= one;
bdd2num.emplace(one, num2bdd.size());
num2bdd.push_back(one);
}
size_t nc = num2bdd.size(); // number of conditions
size_t nc = num2bdd.size(); // number of conditions
assert(nc == (1UL << nap));
// An array of bit vectors of size 'ns'. Each original state is
@ -134,18 +134,18 @@ namespace spot
for (unsigned src = 0; src < ns; ++src)
{
size_t base = src * nc;
for (auto& t: aut->out(src))
{
bdd all = t.cond;
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, allap, bddfalse);
all -= one;
unsigned num = bdd2num[one];
bv->at(base + num).set(t.dst);
}
}
size_t base = src * nc;
for (auto& t: aut->out(src))
{
bdd all = t.cond;
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, allap, bddfalse);
all -= one;
unsigned num = bdd2num[one];
bv->at(base + num).set(t.dst);
}
}
}
typedef power_map::power_state power_state;
@ -175,39 +175,39 @@ namespace spot
for (unsigned src_num = 0; src_num < res->num_states(); ++src_num)
{
om->clear_all();
om->clear_all();
const power_state& src = pm.states_of(src_num);
const power_state& src = pm.states_of(src_num);
for (auto s: src)
{
size_t base = s * nc;
for (unsigned c = 0; c < nc; ++c)
om->at(c) |= bv->at(base + c);
}
for (unsigned c = 0; c < nc; ++c)
{
auto dst = &om->at(c);
if (dst->is_fully_clear())
continue;
auto i = seen.find(dst);
unsigned dst_num;
if (i != seen.end())
{
dst_num = i->second;
}
else
{
dst_num = res->new_state();
auto dst2 = dst->clone();
seen[dst2] = dst_num;
toclean.push_back(dst2);
auto ps = bv_to_ps(dst);
assert(pm.map_.size() == dst_num);
pm.map_.emplace_back(std::move(ps));
}
res->new_edge(src_num, dst_num, num2bdd[c]);
}
for (auto s: src)
{
size_t base = s * nc;
for (unsigned c = 0; c < nc; ++c)
om->at(c) |= bv->at(base + c);
}
for (unsigned c = 0; c < nc; ++c)
{
auto dst = &om->at(c);
if (dst->is_fully_clear())
continue;
auto i = seen.find(dst);
unsigned dst_num;
if (i != seen.end())
{
dst_num = i->second;
}
else
{
dst_num = res->new_state();
auto dst2 = dst->clone();
seen[dst2] = dst_num;
toclean.push_back(dst2);
auto ps = bv_to_ps(dst);
assert(pm.map_.size() == dst_num);
pm.map_.emplace_back(std::move(ps));
}
res->new_edge(src_num, dst_num, num2bdd[c]);
}
}
for (auto v: toclean)
@ -238,133 +238,133 @@ namespace spot
protected:
const_twa_graph_ptr ref_;
power_map& refmap_;
edge_set reject_; // set of rejecting edges
set_set accept_; // set of cycles that are accepting
edge_set all_; // all non rejecting edges
unsigned threshold_; // maximum count of enumerated cycles
unsigned cycles_left_; // count of cycles left to explore
edge_set reject_; // set of rejecting edges
set_set accept_; // set of cycles that are accepting
edge_set all_; // all non rejecting edges
unsigned threshold_; // maximum count of enumerated cycles
unsigned cycles_left_; // count of cycles left to explore
public:
fix_scc_acceptance(const scc_info& sm, const_twa_graph_ptr ref,
power_map& refmap, unsigned threshold)
: enumerate_cycles(sm), ref_(ref), refmap_(refmap),
threshold_(threshold)
power_map& refmap, unsigned threshold)
: enumerate_cycles(sm), ref_(ref), refmap_(refmap),
threshold_(threshold)
{
}
bool fix_scc(const int m)
{
reject_.clear();
accept_.clear();
cycles_left_ = threshold_;
run(m);
reject_.clear();
accept_.clear();
cycles_left_ = threshold_;
run(m);
// std::cerr << "SCC #" << m << '\n';
// std::cerr << "REJECT: ";
// print_set(std::cerr, reject_) << '\n';
// std::cerr << "ALL: ";
// print_set(std::cerr, all_) << '\n';
// for (set_set::const_iterator j = accept_.begin();
// j != accept_.end(); ++j)
// {
// std::cerr << "ACCEPT: ";
// print_set(std::cerr, *j) << '\n';
// }
// std::cerr << "SCC #" << m << '\n';
// std::cerr << "REJECT: ";
// print_set(std::cerr, reject_) << '\n';
// std::cerr << "ALL: ";
// print_set(std::cerr, all_) << '\n';
// for (set_set::const_iterator j = accept_.begin();
// j != accept_.end(); ++j)
// {
// std::cerr << "ACCEPT: ";
// print_set(std::cerr, *j) << '\n';
// }
auto acc = aut_->acc().all_sets();
for (auto i: all_)
i->acc = acc;
return threshold_ != 0 && cycles_left_ == 0;
auto acc = aut_->acc().all_sets();
for (auto i: all_)
i->acc = acc;
return threshold_ != 0 && cycles_left_ == 0;
}
bool is_cycle_accepting(cycle_iter begin, edge_set& ts) const
{
auto a = std::const_pointer_cast<twa_graph>(aut_);
auto a = std::const_pointer_cast<twa_graph>(aut_);
// Build an automaton representing this loop.
auto loop_a = make_twa_graph(aut_->get_dict());
int loop_size = std::distance(begin, dfs_.end());
loop_a->new_states(loop_size);
int n;
cycle_iter i;
for (n = 1, i = begin; n <= loop_size; ++n, ++i)
{
trans* t = &a->edge_data(i->succ);
loop_a->new_edge(n - 1, n % loop_size, t->cond);
if (reject_.find(t) == reject_.end())
ts.insert(t);
}
assert(i == dfs_.end());
// Build an automaton representing this loop.
auto loop_a = make_twa_graph(aut_->get_dict());
int loop_size = std::distance(begin, dfs_.end());
loop_a->new_states(loop_size);
int n;
cycle_iter i;
for (n = 1, i = begin; n <= loop_size; ++n, ++i)
{
trans* t = &a->edge_data(i->succ);
loop_a->new_edge(n - 1, n % loop_size, t->cond);
if (reject_.find(t) == reject_.end())
ts.insert(t);
}
assert(i == dfs_.end());
unsigned loop_a_init = loop_a->get_init_state_number();
assert(loop_a_init == 0);
unsigned loop_a_init = loop_a->get_init_state_number();
assert(loop_a_init == 0);
// Check if the loop is accepting in the original automaton.
bool accepting = false;
// Check if the loop is accepting in the original automaton.
bool accepting = false;
// Iterate on each original state corresponding to the
// start of the loop in the determinized automaton.
for (auto s: refmap_.states_of(begin->s))
{
// Check the product between LOOP_A, and ORIG_A starting
// in S.
if (!product(loop_a, ref_, loop_a_init, s)->is_empty())
{
accepting = true;
break;
}
}
return accepting;
// Iterate on each original state corresponding to the
// start of the loop in the determinized automaton.
for (auto s: refmap_.states_of(begin->s))
{
// Check the product between LOOP_A, and ORIG_A starting
// in S.
if (!product(loop_a, ref_, loop_a_init, s)->is_empty())
{
accepting = true;
break;
}
}
return accepting;
}
std::ostream&
print_set(std::ostream& o, const edge_set& s) const
{
o << "{ ";
for (auto i: s)
o << i << ' ';
o << '}';
return o;
o << "{ ";
for (auto i: s)
o << i << ' ';
o << '}';
return o;
}
virtual bool
cycle_found(unsigned start) override
{
cycle_iter i = dfs_.begin();
while (i->s != start)
++i;
edge_set ts;
bool is_acc = is_cycle_accepting(i, ts);
do
++i;
while (i != dfs_.end());
if (is_acc)
{
accept_.push_back(ts);
all_.insert(ts.begin(), ts.end());
}
else
{
for (auto t: ts)
{
reject_.insert(t);
for (auto& j: accept_)
j.erase(t);
all_.erase(t);
}
}
cycle_iter i = dfs_.begin();
while (i->s != start)
++i;
edge_set ts;
bool is_acc = is_cycle_accepting(i, ts);
do
++i;
while (i != dfs_.end());
if (is_acc)
{
accept_.push_back(ts);
all_.insert(ts.begin(), ts.end());
}
else
{
for (auto t: ts)
{
reject_.insert(t);
for (auto& j: accept_)
j.erase(t);
all_.erase(t);
}
}
// Abort this algorithm if we have seen too much cycles, i.e.,
// when cycle_left_ *reaches* 0. (If cycle_left_ == 0, that
// means we had no limit.)
return (cycles_left_ == 0) || --cycles_left_;
// Abort this algorithm if we have seen too much cycles, i.e.,
// when cycle_left_ *reaches* 0. (If cycle_left_ == 0, that
// means we had no limit.)
return (cycles_left_ == 0) || --cycles_left_;
}
};
static bool
fix_dba_acceptance(twa_graph_ptr det,
const_twa_graph_ptr ref, power_map& refmap,
unsigned threshold)
const_twa_graph_ptr ref, power_map& refmap,
unsigned threshold)
{
det->copy_acceptance_of(ref);
@ -375,16 +375,16 @@ namespace spot
fix_scc_acceptance fsa(sm, ref, refmap, threshold);
for (unsigned m = 0; m < scc_count; ++m)
if (!sm.is_trivial(m))
if (fsa.fix_scc(m))
return true;
if (!sm.is_trivial(m))
if (fsa.fix_scc(m))
return true;
return false;
}
}
twa_graph_ptr
tba_determinize(const const_twa_graph_ptr& aut,
unsigned threshold_states, unsigned threshold_cycles)
unsigned threshold_states, unsigned threshold_cycles)
{
power_map pm;
// Do not merge edges in the deterministic automaton. If we
@ -393,7 +393,7 @@ namespace spot
auto det = tgba_powerset(aut, pm, false);
if ((threshold_states > 0)
&& (pm.map_.size() > aut->num_states() * threshold_states))
&& (pm.map_.size() > aut->num_states() * threshold_states))
return nullptr;
if (fix_dba_acceptance(det, aut, pm, threshold_cycles))
return nullptr;
@ -403,10 +403,10 @@ namespace spot
twa_graph_ptr
tba_determinize_check(const twa_graph_ptr& aut,
unsigned threshold_states,
unsigned threshold_cycles,
formula f,
const_twa_graph_ptr neg_aut)
unsigned threshold_states,
unsigned threshold_cycles,
formula f,
const_twa_graph_ptr neg_aut)
{
if (f == nullptr && neg_aut == nullptr)
return nullptr;
@ -420,17 +420,17 @@ namespace spot
if (neg_aut == nullptr)
{
neg_aut = ltl_to_tgba_fm(formula::Not(f), aut->get_dict());
// Remove useless SCCs.
neg_aut = scc_filter(neg_aut, true);
neg_aut = ltl_to_tgba_fm(formula::Not(f), aut->get_dict());
// Remove useless SCCs.
neg_aut = scc_filter(neg_aut, true);
}
if (product(det, neg_aut)->is_empty())
// Complement the DBA.
if (product(aut, remove_fin(dtwa_complement(det)))->is_empty())
// Finally, we are now sure that it was safe
// to determinize the automaton.
return det;
// Finally, we are now sure that it was safe
// to determinize the automaton.
return det;
return aut;
}

View file

@ -56,7 +56,7 @@ namespace spot
//@{
SPOT_API twa_graph_ptr
tgba_powerset(const const_twa_graph_ptr& aut,
power_map& pm, bool merge = true);
power_map& pm, bool merge = true);
SPOT_API twa_graph_ptr
tgba_powerset(const const_twa_graph_ptr& aut);
//@}
@ -71,19 +71,19 @@ namespace spot
///
/// The construction is adapted from Section 3.2 of:
/// \verbatim
/// @InProceedings{ dax.07.atva,
/// author = {Christian Dax and Jochen Eisinger and Felix Klaedtke},
/// @InProceedings{ dax.07.atva,
/// author = {Christian Dax and Jochen Eisinger and Felix Klaedtke},
/// title = {Mechanizing the Powerset Construction for Restricted
/// Classes of {$\omega$}-Automata},
/// Classes of {$\omega$}-Automata},
/// year = 2007,
/// series = {Lecture Notes in Computer Science},
/// series = {Lecture Notes in Computer Science},
/// publisher = {Springer-Verlag},
/// volume = 4762,
/// volume = 4762,
/// booktitle = {Proceedings of the 5th International Symposium on
/// Automated Technology for Verification and Analysis
/// (ATVA'07)},
/// editor = {Kedar S. Namjoshi and Tomohiro Yoneda and Teruo Higashino
/// and Yoshio Okamura},
/// Automated Technology for Verification and Analysis
/// (ATVA'07)},
/// editor = {Kedar S. Namjoshi and Tomohiro Yoneda and Teruo Higashino
/// and Yoshio Okamura},
/// month = oct
/// }
/// \endverbatim
@ -99,8 +99,8 @@ namespace spot
/// threshold_cycles cycles.
SPOT_API twa_graph_ptr
tba_determinize(const const_twa_graph_ptr& aut,
unsigned threshold_states = 0,
unsigned threshold_cycles = 0);
unsigned threshold_states = 0,
unsigned threshold_cycles = 0);
/// \brief Determinize a TBA and make sure it is correct.
///
@ -131,9 +131,9 @@ namespace spot
/// were supplied.
SPOT_API twa_graph_ptr
tba_determinize_check(const twa_graph_ptr& aut,
unsigned threshold_states = 0,
unsigned threshold_cycles = 0,
formula f = nullptr,
const_twa_graph_ptr neg_aut = nullptr);
unsigned threshold_states = 0,
unsigned threshold_cycles = 0,
formula f = nullptr,
const_twa_graph_ptr neg_aut = nullptr);
}

View file

@ -41,120 +41,120 @@ namespace spot
static
twa_graph_ptr product_aux(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state,
bool and_acc)
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state,
bool and_acc)
{
std::unordered_map<product_state, unsigned, product_state_hash> s2n;
std::deque<std::pair<product_state, unsigned>> todo;
if (left->get_dict() != right->get_dict())
throw std::runtime_error("product: left and right automata should "
"share their bdd_dict");
throw std::runtime_error("product: left and right automata should "
"share their bdd_dict");
auto res = make_twa_graph(left->get_dict());
res->copy_ap_of(left);
res->copy_ap_of(right);
auto left_num = left->num_sets();
auto right_acc = right->get_acceptance() << left_num;
if (and_acc)
right_acc &= left->get_acceptance();
right_acc &= left->get_acceptance();
else
right_acc |= left->get_acceptance();
right_acc |= left->get_acceptance();
res->set_acceptance(left_num + right->num_sets(), right_acc);
auto v = new product_states;
res->set_named_prop("product-states", v);
auto new_state =
[&](unsigned left_state, unsigned right_state) -> unsigned
{
product_state x(left_state, right_state);
auto p = s2n.emplace(x, 0);
if (p.second) // This is a new state
{
p.first->second = res->new_state();
todo.emplace_back(x, p.first->second);
assert(p.first->second == v->size());
v->push_back(x);
}
return p.first->second;
};
[&](unsigned left_state, unsigned right_state) -> unsigned
{
product_state x(left_state, right_state);
auto p = s2n.emplace(x, 0);
if (p.second) // This is a new state
{
p.first->second = res->new_state();
todo.emplace_back(x, p.first->second);
assert(p.first->second == v->size());
v->push_back(x);
}
return p.first->second;
};
res->set_init_state(new_state(left_state, right_state));
if (right_acc.is_f())
// Do not bother doing any work if the resulting acceptance is
// false.
return res;
// Do not bother doing any work if the resulting acceptance is
// false.
return res;
while (!todo.empty())
{
auto top = todo.front();
todo.pop_front();
for (auto& l: left->out(top.first.first))
for (auto& r: right->out(top.first.second))
{
auto cond = l.cond & r.cond;
if (cond == bddfalse)
continue;
auto dst = new_state(l.dst, r.dst);
res->new_edge(top.second, dst, cond,
l.acc | (r.acc << left_num));
// If right is deterministic, we can abort immediately!
}
}
{
auto top = todo.front();
todo.pop_front();
for (auto& l: left->out(top.first.first))
for (auto& r: right->out(top.first.second))
{
auto cond = l.cond & r.cond;
if (cond == bddfalse)
continue;
auto dst = new_state(l.dst, r.dst);
res->new_edge(top.second, dst, cond,
l.acc | (r.acc << left_num));
// If right is deterministic, we can abort immediately!
}
}
res->prop_deterministic(left->prop_deterministic()
&& right->prop_deterministic());
&& right->prop_deterministic());
res->prop_stutter_invariant(left->prop_stutter_invariant()
&& right->prop_stutter_invariant());
&& right->prop_stutter_invariant());
// The product of X!a and Xa, two stutter-sentive formulas,
// is stutter-invariant.
//res->prop_stutter_sensitive(left->prop_stutter_sensitive()
// && right->prop_stutter_sensitive());
// && right->prop_stutter_sensitive());
res->prop_inherently_weak(left->prop_inherently_weak()
&& right->prop_inherently_weak());
&& right->prop_inherently_weak());
res->prop_weak(left->prop_weak()
&& right->prop_weak());
&& right->prop_weak());
res->prop_terminal(left->prop_terminal()
&& right->prop_terminal());
&& right->prop_terminal());
res->prop_state_acc(left->prop_state_acc()
&& right->prop_state_acc());
&& right->prop_state_acc());
return res;
}
}
twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state)
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state)
{
return product_aux(left, right, left_state, right_state, true);
}
twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right)
const const_twa_graph_ptr& right)
{
return product(left, right,
left->get_init_state_number(),
right->get_init_state_number());
left->get_init_state_number(),
right->get_init_state_number());
}
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state)
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state)
{
return product_aux(complete(left),
complete(right),
left_state, right_state, false);
complete(right),
left_state, right_state, false);
}
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right)
const const_twa_graph_ptr& right)
{
return product_or(left, right,
left->get_init_state_number(),
right->get_init_state_number());
left->get_init_state_number(),
right->get_init_state_number());
}
}

View file

@ -32,22 +32,22 @@ namespace spot
SPOT_API
twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right);
const const_twa_graph_ptr& right);
SPOT_API
twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state);
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state);
SPOT_API
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right);
const const_twa_graph_ptr& right);
SPOT_API
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state);
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state);
}

View file

@ -29,16 +29,16 @@ namespace spot
twa_run_ptr
project_twa_run(const const_twa_ptr& a_run,
const const_twa_ptr& a_proj,
const const_twa_run_ptr& run)
const const_twa_ptr& a_proj,
const const_twa_run_ptr& run)
{
auto res = std::make_shared<twa_run>(a_proj);
for (auto& i: run->prefix)
res->prefix.emplace_back(a_run->project_state(i.s, a_proj),
i.label, i.acc);
i.label, i.acc);
for (auto& i: run->cycle)
res->prefix.emplace_back(a_run->project_state(i.s, a_proj),
i.label, i.acc);
i.label, i.acc);
return res;
}
}

View file

@ -43,6 +43,6 @@ namespace spot
/// \return true iff the run could be completed
SPOT_API twa_run_ptr
project_twa_run(const const_twa_ptr& a_run,
const const_twa_ptr& a_proj,
const const_twa_run_ptr& run);
const const_twa_ptr& a_proj,
const const_twa_run_ptr& run);
}

View file

@ -37,33 +37,33 @@ namespace spot
{
static unsigned
random_deterministic_labels_rec(std::vector<bdd>& labels, int *props,
int props_n, bdd current, unsigned n)
int props_n, bdd current, unsigned n)
{
if (n > 1 && props_n >= 1)
{
bdd ap = bdd_ithvar(*props);
bdd ap = bdd_ithvar(*props);
++props;
--props_n;
--props_n;
// There are m labels generated from "current & ap"
// and n - m labels generated from "current & !ap"
// There are m labels generated from "current & ap"
// and n - m labels generated from "current & !ap"
unsigned m = rrand(1, n - 1);
if (2 * m < n)
{
m = n - m;
ap = !ap;
}
if (2 * m < n)
{
m = n - m;
ap = !ap;
}
unsigned res = random_deterministic_labels_rec(labels, props,
props_n,
current & ap, m);
res += random_deterministic_labels_rec(labels, props, props_n,
current & !ap, n - res);
unsigned res = random_deterministic_labels_rec(labels, props,
props_n,
current & ap, m);
res += random_deterministic_labels_rec(labels, props, props_n,
current & !ap, n - res);
return res;
}
else
{
labels.push_back(current);
labels.push_back(current);
return 1;
}
}
@ -81,8 +81,8 @@ namespace spot
{
acc_cond::mark_t m = 0U;
for (unsigned i = 0U; i < n_accs; ++i)
if (drand() < a)
m.set(i);
if (drand() < a)
m.set(i);
return m;
}
@ -100,21 +100,21 @@ namespace spot
int size = 0;
bdd p = bddtrue;
while (props_n)
{
if (size == 8 * sizeof(int))
{
p &= bdd_ibuildcube(val, size, props);
props += size;
val = 0;
size = 0;
}
val <<= 1;
val |= (drand() < t);
++size;
--props_n;
}
{
if (size == 8 * sizeof(int))
{
p &= bdd_ibuildcube(val, size, props);
props += size;
val = 0;
size = 0;
}
val <<= 1;
val |= (drand() < t);
++size;
--props_n;
}
if (size > 0)
p &= bdd_ibuildcube(val, size, props);
p &= bdd_ibuildcube(val, size, props);
return p;
}
@ -122,9 +122,9 @@ namespace spot
twa_graph_ptr
random_graph(int n, float d,
const atomic_prop_set* ap, const bdd_dict_ptr& dict,
unsigned n_accs, float a, float t,
bool deterministic, bool state_acc, bool colored)
const atomic_prop_set* ap, const bdd_dict_ptr& dict,
unsigned n_accs, float a, float t,
bool deterministic, bool state_acc, bool colored)
{
if (n <= 0)
throw std::invalid_argument("random_graph() requires n>0 states");
@ -157,8 +157,8 @@ namespace spot
for (int i = 1; i < n; ++i)
{
state_randomizer[i] = i;
unreachable_nodes.insert(i);
state_randomizer[i] = i;
unreachable_nodes.insert(i);
}
// We want to connect each node to a number of successors between
@ -168,57 +168,57 @@ namespace spot
while (!nodes_to_process.empty())
{
auto src = *nodes_to_process.begin();
nodes_to_process.erase(nodes_to_process.begin());
auto src = *nodes_to_process.begin();
nodes_to_process.erase(nodes_to_process.begin());
// Choose a random number of successors (at least one), using
// a binomial distribution.
unsigned nsucc = 1 + bin.rand();
// Choose a random number of successors (at least one), using
// a binomial distribution.
unsigned nsucc = 1 + bin.rand();
bool saw_unreachable = false;
bool saw_unreachable = false;
// Create NSUCC random labels.
std::vector<bdd> labels;
if (deterministic)
{
labels = random_deterministic_labels(props, props_n, nsucc);
// Create NSUCC random labels.
std::vector<bdd> labels;
if (deterministic)
{
labels = random_deterministic_labels(props, props_n, nsucc);
// if nsucc > 2^props_n, we cannot produce nsucc deterministic
// edges so we set it to labels.size()
nsucc = labels.size();
}
else
for (unsigned i = 0; i < nsucc; ++i)
labels.push_back(random_labels(props, props_n, t));
// if nsucc > 2^props_n, we cannot produce nsucc deterministic
// edges so we set it to labels.size()
nsucc = labels.size();
}
else
for (unsigned i = 0; i < nsucc; ++i)
labels.push_back(random_labels(props, props_n, t));
int possibilities = n;
unsigned dst;
acc_cond::mark_t m = 0U;
if (state_acc)
m = colored ? random_acc1(n_accs) : random_acc(n_accs, a);
unsigned dst;
acc_cond::mark_t m = 0U;
if (state_acc)
m = colored ? random_acc1(n_accs) : random_acc(n_accs, a);
for (auto& l: labels)
{
if (!state_acc)
m = colored ? random_acc1(n_accs) : random_acc(n_accs, a);
for (auto& l: labels)
{
if (!state_acc)
m = colored ? random_acc1(n_accs) : random_acc(n_accs, a);
// No connection to unreachable successors so far. This
// is our last chance, so force it now.
if (--nsucc == 0
&& !unreachable_nodes.empty()
&& !saw_unreachable)
{
// Pick a random unreachable node.
int index = mrand(unreachable_nodes.size());
node_set::const_iterator i = unreachable_nodes.begin();
std::advance(i, index);
// No connection to unreachable successors so far. This
// is our last chance, so force it now.
if (--nsucc == 0
&& !unreachable_nodes.empty()
&& !saw_unreachable)
{
// Pick a random unreachable node.
int index = mrand(unreachable_nodes.size());
node_set::const_iterator i = unreachable_nodes.begin();
std::advance(i, index);
// Link it from src.
res->new_edge(src, *i, l, m);
nodes_to_process.insert(*i);
unreachable_nodes.erase(*i);
break;
}
// Link it from src.
res->new_edge(src, *i, l, m);
nodes_to_process.insert(*i);
unreachable_nodes.erase(*i);
break;
}
// Pick the index of a random node.
int index = mrand(possibilities--);
@ -237,10 +237,10 @@ namespace spot
unreachable_nodes.erase(j);
saw_unreachable = true;
}
}
}
// The node must have at least one successor.
assert(res->get_graph().state_storage(src).succ);
// The node must have at least one successor.
assert(res->get_graph().state_storage(src).succ);
}
// All nodes must be reachable.
assert(unreachable_nodes.empty());

View file

@ -56,18 +56,18 @@ namespace spot
///
/// This algorithms is adapted from the one in Fig 6.2 page 48 of
/** \verbatim
@TechReport{ tauriainen.00.a66,
author = {Heikki Tauriainen},
@TechReport{ tauriainen.00.a66,
author = {Heikki Tauriainen},
title = {Automated Testing of {B\"u}chi Automata Translators for
{L}inear {T}emporal {L}ogic},
address = {Espoo, Finland},
{L}inear {T}emporal {L}ogic},
address = {Espoo, Finland},
institution = {Helsinki University of Technology, Laboratory for
Theoretical Computer Science},
number = {A66},
year = {2000},
url = {http://citeseer.nj.nec.com/tauriainen00automated.html},
type = {Research Report},
note = {Reprint of Master's thesis}
Theoretical Computer Science},
number = {A66},
year = {2000},
url = {http://citeseer.nj.nec.com/tauriainen00automated.html},
type = {Research Report},
note = {Reprint of Master's thesis}
}
\endverbatim */
///
@ -84,10 +84,10 @@ namespace spot
/// acceptance sets, this does not set the acceptance condition.
SPOT_API twa_graph_ptr
random_graph(int n, float d,
const atomic_prop_set* ap, const bdd_dict_ptr& dict,
unsigned n_accs = 0, float a = 0.1, float t = 0.5,
bool deterministic = false, bool state_acc = false,
bool colored = false);
const atomic_prop_set* ap, const bdd_dict_ptr& dict,
unsigned n_accs = 0, float a = 0.1, float t = 0.5,
bool deterministic = false, bool state_acc = false,
bool colored = false);
/// Build a random acceptance where each acceptance sets is used once.
SPOT_API acc_cond::acc_code random_acceptance(unsigned n_accs);

View file

@ -27,40 +27,40 @@ namespace spot
{
void
randomize(twa_graph_ptr& aut, bool randomize_states,
bool randomize_edges)
bool randomize_edges)
{
if (!randomize_states && !randomize_edges)
return;
auto& g = aut->get_graph();
if (randomize_states)
{
unsigned n = g.num_states();
std::vector<unsigned> nums(n);
std::iota(nums.begin(), nums.end(), 0);
mrandom_shuffle(nums.begin(), nums.end());
g.rename_states_(nums);
aut->set_init_state(nums[aut->get_init_state_number()]);
unsigned n = g.num_states();
std::vector<unsigned> nums(n);
std::iota(nums.begin(), nums.end(), 0);
mrandom_shuffle(nums.begin(), nums.end());
g.rename_states_(nums);
aut->set_init_state(nums[aut->get_init_state_number()]);
if (auto sn =
aut->get_named_prop<std::vector<std::string>>("state-names"))
{
unsigned sns = sn->size(); // Might be != n.
auto nn = new std::vector<std::string>(n);
for (unsigned i = 0; i < sns && i < n; ++i)
(*nn)[nums[i]] = (*sn)[i];
aut->set_named_prop("state-names", nn);
}
if (auto sn =
aut->get_named_prop<std::vector<std::string>>("state-names"))
{
unsigned sns = sn->size(); // Might be != n.
auto nn = new std::vector<std::string>(n);
for (unsigned i = 0; i < sns && i < n; ++i)
(*nn)[nums[i]] = (*sn)[i];
aut->set_named_prop("state-names", nn);
}
}
if (randomize_edges)
{
g.remove_dead_edges_();
auto& v = g.edge_vector();
mrandom_shuffle(v.begin() + 1, v.end());
g.remove_dead_edges_();
auto& v = g.edge_vector();
mrandom_shuffle(v.begin() + 1, v.end());
}
typedef twa_graph::graph_t::edge_storage_t tr_t;
g.sort_edges_([](const tr_t& lhs, const tr_t& rhs)
{ return lhs.src < rhs.src; });
{ return lhs.src < rhs.src; });
g.chain_edges_();
}
}

View file

@ -29,6 +29,6 @@ namespace spot
/// leaving this state.
SPOT_API void
randomize(twa_graph_ptr& aut,
bool randomize_states = true,
bool randomize_edges = true);
bool randomize_states = true,
bool randomize_edges = true);
}

View file

@ -38,10 +38,10 @@ namespace spot
auto s = seen.begin();
while (s != seen.end())
{
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
}
}
@ -57,34 +57,34 @@ namespace spot
const state* t;
while ((t = next_state()))
{
assert(seen.find(t) != seen.end());
int tn = seen[t];
twa_succ_iterator* si = aut_->succ_iter(t);
process_state(t, tn, si);
if (si->first())
do
{
const state* current = si->dst();
auto s = seen.find(current);
bool ws = want_state(current);
if (s == seen.end())
{
seen[current] = ++n;
if (ws)
{
add_state(current);
process_link(t, tn, current, n, si);
}
}
else
{
if (ws)
process_link(t, tn, s->first, s->second, si);
current->destroy();
}
}
while (si->next());
aut_->release_iter(si);
assert(seen.find(t) != seen.end());
int tn = seen[t];
twa_succ_iterator* si = aut_->succ_iter(t);
process_state(t, tn, si);
if (si->first())
do
{
const state* current = si->dst();
auto s = seen.find(current);
bool ws = want_state(current);
if (s == seen.end())
{
seen[current] = ++n;
if (ws)
{
add_state(current);
process_link(t, tn, current, n, si);
}
}
else
{
if (ws)
process_link(t, tn, s->first, s->second, si);
current->destroy();
}
}
while (si->next());
aut_->release_iter(si);
}
end();
}
@ -107,14 +107,14 @@ namespace spot
void
twa_reachable_iterator::process_state(const state*, int,
twa_succ_iterator*)
twa_succ_iterator*)
{
}
void
twa_reachable_iterator::process_link(const state*, int,
const state*, int,
const twa_succ_iterator*)
const state*, int,
const twa_succ_iterator*)
{
}
@ -157,10 +157,10 @@ namespace spot
auto s = seen.begin();
while (s != seen.end())
{
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
ptr->destroy();
}
}
@ -195,46 +195,46 @@ namespace spot
const state* dst;
while (!todo.empty())
{
twa_succ_iterator* si = todo.back().it;
if (si->done())
{
pop();
continue;
}
twa_succ_iterator* si = todo.back().it;
if (si->done())
{
pop();
continue;
}
dst = si->dst();
auto res = seen.emplace(dst, n);
if (!res.second)
{
// The state has already been seen.
dst->destroy();
// 0-numbered states are not wanted.
if (res.first->second == 0)
{
si->next();
continue;
}
dst = res.first->first;
}
else if (!want_state(dst))
{
// Mark this state as non-wanted in case we see it again.
res.first->second = 0;
si->next();
continue;
}
else
{
++n;
}
dst = si->dst();
auto res = seen.emplace(dst, n);
if (!res.second)
{
// The state has already been seen.
dst->destroy();
// 0-numbered states are not wanted.
if (res.first->second == 0)
{
si->next();
continue;
}
dst = res.first->first;
}
else if (!want_state(dst))
{
// Mark this state as non-wanted in case we see it again.
res.first->second = 0;
si->next();
continue;
}
else
{
++n;
}
int dst_n = res.first->second;
process_link(todo.back().src, todo.back().src_n, dst, dst_n, si);
int dst_n = res.first->second;
process_link(todo.back().src, todo.back().src_n, dst, dst_n, si);
if (res.second)
push(dst, dst_n);
else
si->next();
if (res.second)
push(dst, dst_n);
else
si->next();
}
end();
}
@ -257,14 +257,14 @@ namespace spot
void
twa_reachable_iterator_depth_first::process_state(const state*, int,
twa_succ_iterator*)
twa_succ_iterator*)
{
}
void
twa_reachable_iterator_depth_first::process_link(const state*, int,
const state*, int,
const twa_succ_iterator*)
const state*, int,
const twa_succ_iterator*)
{
}

View file

@ -84,13 +84,13 @@ namespace spot
/// spot::twa_reachable_iterator instance and destroyed when the
/// instance is destroyed.
virtual void process_link(const state* in_s, int in,
const state* out_s, int out,
const twa_succ_iterator* si);
const state* out_s, int out,
const twa_succ_iterator* si);
protected:
const_twa_ptr aut_; ///< The spot::tgba to explore.
const_twa_ptr aut_; ///< The spot::tgba to explore.
state_map<int> seen; ///< States already seen.
state_map<int> seen; ///< States already seen.
};
/// \ingroup twa_generic
@ -152,13 +152,13 @@ namespace spot
/// spot::twa_reachable_iterator instance and destroyed when the
/// instance is destroyed.
virtual void process_link(const state* in_s, int in,
const state* out_s, int out,
const twa_succ_iterator* si);
const state* out_s, int out,
const twa_succ_iterator* si);
protected:
const_twa_ptr aut_; ///< The spot::tgba to explore.
const_twa_ptr aut_; ///< The spot::tgba to explore.
state_map<int> seen; ///< States already seen.
state_map<int> seen; ///< States already seen.
struct stack_item
{
const state* src;

View file

@ -30,10 +30,10 @@ namespace spot
vars.reserve(relmap->size());
for (auto& p: *relmap)
{
int oldv = aut->register_ap(p.first);
int newv = aut->register_ap(p.second);
bdd_setpair(pairs, oldv, newv);
vars.push_back(oldv);
int oldv = aut->register_ap(p.first);
int newv = aut->register_ap(p.second);
bdd_setpair(pairs, oldv, newv);
vars.push_back(oldv);
}
for (auto& t: aut->edges())
t.cond = bdd_replace(t.cond, pairs);

View file

@ -27,5 +27,5 @@ namespace spot
/// replace atomic propositions in an automaton
SPOT_API void
relabel_here(twa_graph_ptr& aut,
relabeling_map* relmap);
relabeling_map* relmap);
}

File diff suppressed because it is too large Load diff

View file

@ -33,9 +33,9 @@ namespace spot
std::ostringstream out;
out << "unexpected ";
if (isprint(*pos))
out << '\'' << *pos << '\'';
out << '\'' << *pos << '\'';
else
out << "character";
out << "character";
out << " at position " << pos - arg << " in '";
out << arg << '\'';
throw std::invalid_argument(out.str());
@ -48,77 +48,77 @@ namespace spot
auto start = arg;
while (*start)
{
while (*start == ' ' || *start == '\t')
++start;
if (!*start)
break;
if (*start == ',' || *start == '=')
unexpected_char(arg, start);
formula the_ap = nullptr;
while (*start == ' ' || *start == '\t')
++start;
if (!*start)
break;
if (*start == ',' || *start == '=')
unexpected_char(arg, start);
formula the_ap = nullptr;
if (*start == '"')
{
auto end = ++start;
while (*end && *end != '"')
{
if (*end == '\\')
++end;
++end;
}
if (!*end)
{
std::string s = "missing closing '\"' in ";
s += arg;
throw std::invalid_argument(s);
}
std::string ap(start, end - start);
the_ap = formula::ap(ap);
do
++end;
while (*end == ' ' || *end == '\t');
start = end;
}
else
{
auto end = start;
while (*end && *end != ',' && *end != '=')
++end;
auto rend = end;
while (rend > start && (rend[-1] == ' ' || rend[-1] == '\t'))
--rend;
std::string ap(start, rend - start);
the_ap = formula::ap(ap);
start = end;
}
if (*start)
{
if (!(*start == ',' || *start == '='))
unexpected_char(arg, start);
if (*start == '=')
{
do
++start;
while (*start == ' ' || *start == '\t');
if (*start == '0')
props_neg.insert(the_ap);
else if (*start == '1')
props_pos.insert(the_ap);
else
unexpected_char(arg, start);
the_ap = nullptr;
do
++start;
while (*start == ' ' || *start == '\t');
}
if (*start)
{
if (*start != ',')
unexpected_char(arg, start);
++start;
}
}
if (the_ap)
props_exist.insert(the_ap);
if (*start == '"')
{
auto end = ++start;
while (*end && *end != '"')
{
if (*end == '\\')
++end;
++end;
}
if (!*end)
{
std::string s = "missing closing '\"' in ";
s += arg;
throw std::invalid_argument(s);
}
std::string ap(start, end - start);
the_ap = formula::ap(ap);
do
++end;
while (*end == ' ' || *end == '\t');
start = end;
}
else
{
auto end = start;
while (*end && *end != ',' && *end != '=')
++end;
auto rend = end;
while (rend > start && (rend[-1] == ' ' || rend[-1] == '\t'))
--rend;
std::string ap(start, rend - start);
the_ap = formula::ap(ap);
start = end;
}
if (*start)
{
if (!(*start == ',' || *start == '='))
unexpected_char(arg, start);
if (*start == '=')
{
do
++start;
while (*start == ' ' || *start == '\t');
if (*start == '0')
props_neg.insert(the_ap);
else if (*start == '1')
props_pos.insert(the_ap);
else
unexpected_char(arg, start);
the_ap = nullptr;
do
++start;
while (*start == ' ' || *start == '\t');
}
if (*start)
{
if (*start != ',')
unexpected_char(arg, start);
++start;
}
}
if (the_ap)
props_exist.insert(the_ap);
}
}
@ -135,37 +135,37 @@ namespace spot
for (auto ap: props_exist)
{
int v = d->has_registered_proposition(ap, aut);
if (v >= 0)
{
exist &= bdd_ithvar(v);
d->unregister_variable(v, res);
}
int v = d->has_registered_proposition(ap, aut);
if (v >= 0)
{
exist &= bdd_ithvar(v);
d->unregister_variable(v, res);
}
}
for (auto ap: props_pos)
{
int v = d->has_registered_proposition(ap, aut);
if (v >= 0)
{
restrict &= bdd_ithvar(v);
d->unregister_variable(v, res);
}
int v = d->has_registered_proposition(ap, aut);
if (v >= 0)
{
restrict &= bdd_ithvar(v);
d->unregister_variable(v, res);
}
}
for (auto ap: props_neg)
{
int v = d->has_registered_proposition(ap, aut);
if (v >= 0)
{
restrict &= bdd_nithvar(v);
d->unregister_variable(v, res);
}
int v = d->has_registered_proposition(ap, aut);
if (v >= 0)
{
restrict &= bdd_nithvar(v);
d->unregister_variable(v, res);
}
}
transform_accessible(aut, res, [&](unsigned, bdd& cond,
acc_cond::mark_t&, unsigned)
acc_cond::mark_t&, unsigned)
{
cond = bdd_restrict(bdd_exist(cond, exist),
restrict);
cond = bdd_restrict(bdd_exist(cond, exist),
restrict);
});
return res;
}

View file

@ -43,15 +43,15 @@ namespace spot
auto new_state =
[&](unsigned state, acc_cond::mark_t m) -> unsigned
{
pair_t x(state, m);
auto p = s2n.emplace(x, 0);
if (p.second) // This is a new state
{
unsigned s = res->new_state();
p.first->second = s;
todo.emplace_back(x, s);
}
return p.first->second;
pair_t x(state, m);
auto p = s2n.emplace(x, 0);
if (p.second) // This is a new state
{
unsigned s = res->new_state();
p.first->second = s;
todo.emplace_back(x, s);
}
return p.first->second;
};
// Find any edge going into the initial state, and use its
@ -60,21 +60,21 @@ namespace spot
unsigned old_init = old->get_init_state_number();
for (auto& t: old->edges())
if (t.dst == old_init)
{
init_acc = t.acc;
break;
}
{
init_acc = t.acc;
break;
}
res->set_init_state(new_state(old_init, init_acc));
while (!todo.empty())
{
auto one = todo.back();
todo.pop_back();
for (auto& t: old->out(one.first.first))
res->new_edge(one.second,
new_state(t.dst, t.acc),
t.cond,
one.first.second);
auto one = todo.back();
todo.pop_back();
for (auto& t: old->out(one.first.first))
res->new_edge(one.second,
new_state(t.dst, t.acc),
t.cond,
one.first.second);
}
return res;
}

View file

@ -42,25 +42,25 @@ namespace spot
{
scc_info* si;
id_filter(scc_info* si)
: si(si)
: si(si)
{
}
// Accept all states
bool state(unsigned)
{
return true;
return true;
}
void fix_acceptance(const twa_graph_ptr& out)
{
out->copy_acceptance_of(this->si->get_aut());
out->copy_acceptance_of(this->si->get_aut());
}
// Accept all edges, unmodified
filtered_trans trans(unsigned, unsigned, bdd cond, acc_cond::mark_t acc)
{
return filtered_trans{true, cond, acc};
return filtered_trans{true, cond, acc};
}
};
@ -70,13 +70,13 @@ namespace spot
{
template<typename... Args>
state_filter(scc_info* si, Args&&... args)
: next_filter(si, std::forward<Args>(args)...)
: next_filter(si, std::forward<Args>(args)...)
{
}
bool state(unsigned s)
{
return this->next_filter::state(s) && this->si->is_useful_state(s);
return this->next_filter::state(s) && this->si->is_useful_state(s);
}
};
@ -90,37 +90,37 @@ namespace spot
template<typename... Args>
susp_filter(scc_info* si,
bdd suspvars, bdd ignoredvars, bool early_susp,
Args&&... args)
: next_filter(si, std::forward<Args>(args)...),
suspvars(suspvars),
ignoredvars(ignoredvars),
early_susp(early_susp)
bdd suspvars, bdd ignoredvars, bool early_susp,
Args&&... args)
: next_filter(si, std::forward<Args>(args)...),
suspvars(suspvars),
ignoredvars(ignoredvars),
early_susp(early_susp)
{
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, acc_cond::mark_t acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
if (keep)
{
// Always remove ignored variables
cond = bdd_exist(cond, ignoredvars);
if (keep)
{
// Always remove ignored variables
cond = bdd_exist(cond, ignoredvars);
// Remove the suspension variables only if
// the destination in a rejecting SCC,
// or if we are between SCC with early_susp unset.
unsigned u = this->si->scc_of(dst);
if (this->si->is_rejecting_scc(u)
|| (!early_susp && (u != this->si->scc_of(src))))
cond = bdd_exist(cond, suspvars);
}
// Remove the suspension variables only if
// the destination in a rejecting SCC,
// or if we are between SCC with early_susp unset.
unsigned u = this->si->scc_of(dst);
if (this->si->is_rejecting_scc(u)
|| (!early_susp && (u != this->si->scc_of(src))))
cond = bdd_exist(cond, suspvars);
}
return filtered_trans(keep, cond, acc);
return filtered_trans(keep, cond, acc);
}
};
@ -136,68 +136,68 @@ namespace spot
template<typename... Args>
acc_filter_mask(scc_info* si, Args&&... args)
: next_filter(si, std::forward<Args>(args)...)
: next_filter(si, std::forward<Args>(args)...)
{
acc_cond::mark_t fin;
acc_cond::mark_t inf;
std::tie(inf, fin) =
si->get_aut()->acc().get_acceptance().used_inf_fin_sets();
// If an SCC is rejecting, we can mask all the sets that are
// used only as Inf in the acceptance.
accmask = ~(inf - fin);
acc_cond::mark_t fin;
acc_cond::mark_t inf;
std::tie(inf, fin) =
si->get_aut()->acc().get_acceptance().used_inf_fin_sets();
// If an SCC is rejecting, we can mask all the sets that are
// used only as Inf in the acceptance.
accmask = ~(inf - fin);
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, acc_cond::mark_t acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
if (keep)
{
unsigned u = this->si->scc_of(src);
unsigned v = this->si->scc_of(dst);
// The basic rules are as follows:
//
// - If an edge is between two SCCs, is OK to remove
// all acceptance sets, as this edge cannot be part
// of any loop.
// - If an edge is in an non-accepting SCC, we can only
// remove the Inf sets, as removinf the Fin sets
// might make the SCC accepting.
//
// The above rules are made more complex with two flags:
//
// - If PreserveSBA is set, we have to tree a transition
// leaving an SCC as other transitions inside the SCC,
// otherwise we will break the property that all
// transitions leaving the same state have identical set
// membership.
// - If RemoveAll is false, we like to keep the membership
// of transitions entering an SCC. This can only be
// done if PreserveSBA is unset, unfortunately.
if (u == v)
{
if (this->si->is_rejecting_scc(u))
acc &= accmask;
}
else if (PreserveSBA && this->si->is_rejecting_scc(u))
{
if (!this->si->is_trivial(u))
acc &= accmask; // No choice.
else if (RemoveAll)
acc = 0U;
}
else if (!PreserveSBA)
{
if (RemoveAll)
acc = 0U;
else if (this->si->is_rejecting_scc(v))
acc &= accmask;
}
}
return filtered_trans(keep, cond, acc);
if (keep)
{
unsigned u = this->si->scc_of(src);
unsigned v = this->si->scc_of(dst);
// The basic rules are as follows:
//
// - If an edge is between two SCCs, is OK to remove
// all acceptance sets, as this edge cannot be part
// of any loop.
// - If an edge is in an non-accepting SCC, we can only
// remove the Inf sets, as removinf the Fin sets
// might make the SCC accepting.
//
// The above rules are made more complex with two flags:
//
// - If PreserveSBA is set, we have to tree a transition
// leaving an SCC as other transitions inside the SCC,
// otherwise we will break the property that all
// transitions leaving the same state have identical set
// membership.
// - If RemoveAll is false, we like to keep the membership
// of transitions entering an SCC. This can only be
// done if PreserveSBA is unset, unfortunately.
if (u == v)
{
if (this->si->is_rejecting_scc(u))
acc &= accmask;
}
else if (PreserveSBA && this->si->is_rejecting_scc(u))
{
if (!this->si->is_trivial(u))
acc &= accmask; // No choice.
else if (RemoveAll)
acc = 0U;
}
else if (!PreserveSBA)
{
if (RemoveAll)
acc = 0U;
else if (this->si->is_rejecting_scc(v))
acc &= accmask;
}
}
return filtered_trans(keep, cond, acc);
}
};
@ -210,75 +210,75 @@ namespace spot
template<typename... Args>
acc_filter_simplify(scc_info* si, Args&&... args)
: next_filter(si, std::forward<Args>(args)...)
: next_filter(si, std::forward<Args>(args)...)
{
}
void fix_acceptance(const twa_graph_ptr& out)
{
auto& acc = this->si->get_aut()->acc();
if (!acc.is_generalized_buchi())
throw std::runtime_error
("simplification of SCC acceptance works only with "
"generalized Büchi acceptance");
auto& acc = this->si->get_aut()->acc();
if (!acc.is_generalized_buchi())
throw std::runtime_error
("simplification of SCC acceptance works only with "
"generalized Büchi acceptance");
unsigned scc_count = this->si->scc_count();
auto used_acc = this->si->used_acc();
assert(used_acc.size() == scc_count);
strip_.resize(scc_count);
std::vector<unsigned> cnt(scc_count); // # of useful sets in each SCC
unsigned max = 0; // Max number of useful sets
for (unsigned n = 0; n < scc_count; ++n)
{
if (this->si->is_rejecting_scc(n))
continue;
strip_[n] = acc.useless(used_acc[n].begin(), used_acc[n].end());
cnt[n] = acc.num_sets() - strip_[n].count();
if (cnt[n] > max)
max = cnt[n];
}
// Now that we know about the max number of acceptance
// conditions, add extra acceptance conditions to those SCC
// that do not have enough.
for (unsigned n = 0; n < scc_count; ++n)
{
if (this->si->is_rejecting_scc(n))
continue;
if (cnt[n] < max)
strip_[n].remove_some(max - cnt[n]);
}
unsigned scc_count = this->si->scc_count();
auto used_acc = this->si->used_acc();
assert(used_acc.size() == scc_count);
strip_.resize(scc_count);
std::vector<unsigned> cnt(scc_count); // # of useful sets in each SCC
unsigned max = 0; // Max number of useful sets
for (unsigned n = 0; n < scc_count; ++n)
{
if (this->si->is_rejecting_scc(n))
continue;
strip_[n] = acc.useless(used_acc[n].begin(), used_acc[n].end());
cnt[n] = acc.num_sets() - strip_[n].count();
if (cnt[n] > max)
max = cnt[n];
}
// Now that we know about the max number of acceptance
// conditions, add extra acceptance conditions to those SCC
// that do not have enough.
for (unsigned n = 0; n < scc_count; ++n)
{
if (this->si->is_rejecting_scc(n))
continue;
if (cnt[n] < max)
strip_[n].remove_some(max - cnt[n]);
}
out->set_generalized_buchi(max);
out->set_generalized_buchi(max);
}
filtered_trans trans(unsigned src, unsigned dst, bdd cond,
acc_cond::mark_t acc)
acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
if (keep && acc)
{
unsigned u = this->si->scc_of(dst);
if (keep && acc)
{
unsigned u = this->si->scc_of(dst);
if (this->si->is_rejecting_scc(u))
acc = 0U;
else
acc = acc.strip(strip_[u]);
}
return filtered_trans{keep, cond, acc};
if (this->si->is_rejecting_scc(u))
acc = 0U;
else
acc = acc.strip(strip_[u]);
}
return filtered_trans{keep, cond, acc};
}
};
template<class F, typename... Args>
twa_graph_ptr scc_filter_apply(const_twa_graph_ptr aut,
scc_info* given_si, Args&&... args)
scc_info* given_si, Args&&... args)
{
unsigned in_n = aut->num_states();
if (in_n == 0) // nothing to filter.
return make_twa_graph(aut, twa::prop_set::all());
if (in_n == 0) // nothing to filter.
return make_twa_graph(aut, twa::prop_set::all());
twa_graph_ptr filtered = make_twa_graph(aut->get_dict());
filtered->copy_ap_of(aut);
@ -286,44 +286,44 @@ namespace spot
// Compute scc_info if not supplied.
scc_info* si = given_si;
if (!si)
si = new scc_info(aut);
si = new scc_info(aut);
si->determine_unknown_acceptance();
F filter(si, std::forward<Args>(args)...);
// Renumber all useful states.
unsigned out_n = 0; // Number of output states.
unsigned out_n = 0; // Number of output states.
std::vector<unsigned> inout; // Associate old states to new ones.
inout.reserve(in_n);
for (unsigned i = 0; i < in_n; ++i)
if (filter.state(i))
inout.push_back(out_n++);
else
inout.push_back(-1U);
if (filter.state(i))
inout.push_back(out_n++);
else
inout.push_back(-1U);
filter.fix_acceptance(filtered);
filtered->new_states(out_n);
for (unsigned isrc = 0; isrc < in_n; ++isrc)
{
unsigned osrc = inout[isrc];
if (osrc >= out_n)
continue;
for (auto& t: aut->out(isrc))
{
unsigned odst = inout[t.dst];
if (odst >= out_n)
continue;
bool want;
bdd cond;
acc_cond::mark_t acc;
std::tie(want, cond, acc) =
filter.trans(isrc, t.dst, t.cond, t.acc);
if (want)
filtered->new_edge(osrc, odst, cond, acc);
}
}
{
unsigned osrc = inout[isrc];
if (osrc >= out_n)
continue;
for (auto& t: aut->out(isrc))
{
unsigned odst = inout[t.dst];
if (odst >= out_n)
continue;
bool want;
bdd cond;
acc_cond::mark_t acc;
std::tie(want, cond, acc) =
filter.trans(isrc, t.dst, t.cond, t.acc);
if (want)
filtered->new_edge(osrc, odst, cond, acc);
}
}
if (!given_si)
delete si;
delete si;
// If the initial state has been filtered out, we have to create
// a new one (not doing so may cause empty automata, which in turn
// cause all sort of issue with algorithms assuming an automaton
@ -338,92 +338,92 @@ namespace spot
twa_graph_ptr
scc_filter_states(const const_twa_graph_ptr& aut, bool remove_all_useless,
scc_info* given_si)
scc_info* given_si)
{
twa_graph_ptr res;
if (remove_all_useless)
res = scc_filter_apply<state_filter
<acc_filter_mask<true, true>>>(aut, given_si);
<acc_filter_mask<true, true>>>(aut, given_si);
else
res = scc_filter_apply<state_filter
<acc_filter_mask<false, true>>>(aut, given_si);
<acc_filter_mask<false, true>>>(aut, given_si);
res->prop_copy(aut, { true, true, true, true });
return res;
}
twa_graph_ptr
scc_filter(const const_twa_graph_ptr& aut, bool remove_all_useless,
scc_info* given_si)
scc_info* given_si)
{
twa_graph_ptr res;
// acc_filter_simplify only works for generalized Büchi
if (aut->acc().is_generalized_buchi())
{
if (remove_all_useless)
res =
scc_filter_apply<state_filter
<acc_filter_mask
<true, false,
acc_filter_simplify<>>>>(aut, given_si);
else
res =
scc_filter_apply<state_filter
<acc_filter_mask
<false, false,
acc_filter_simplify<>>>>(aut, given_si);
if (remove_all_useless)
res =
scc_filter_apply<state_filter
<acc_filter_mask
<true, false,
acc_filter_simplify<>>>>(aut, given_si);
else
res =
scc_filter_apply<state_filter
<acc_filter_mask
<false, false,
acc_filter_simplify<>>>>(aut, given_si);
}
else
{
if (remove_all_useless)
res = scc_filter_apply<state_filter
<acc_filter_mask
<true, false>>>(aut, given_si);
else
res = scc_filter_apply<state_filter
<acc_filter_mask
<false, false>>>(aut, given_si);
if (remove_all_useless)
res = scc_filter_apply<state_filter
<acc_filter_mask
<true, false>>>(aut, given_si);
else
res = scc_filter_apply<state_filter
<acc_filter_mask
<false, false>>>(aut, given_si);
}
res->merge_edges();
res->prop_copy(aut,
{ false, // state-based acceptance is not preserved
true,
true,
true,
});
{ false, // state-based acceptance is not preserved
true,
true,
true,
});
return res;
}
twa_graph_ptr
scc_filter_susp(const const_twa_graph_ptr& aut, bool remove_all_useless,
bdd suspvars, bdd ignoredvars, bool early_susp,
scc_info* given_si)
bdd suspvars, bdd ignoredvars, bool early_susp,
scc_info* given_si)
{
twa_graph_ptr res;
if (remove_all_useless)
res = scc_filter_apply<susp_filter
<state_filter
<acc_filter_mask
<true, false,
acc_filter_simplify<>>>>>(aut, given_si,
suspvars,
ignoredvars,
early_susp);
<state_filter
<acc_filter_mask
<true, false,
acc_filter_simplify<>>>>>(aut, given_si,
suspvars,
ignoredvars,
early_susp);
else
res = scc_filter_apply<susp_filter
<state_filter
<acc_filter_mask
<false, false,
acc_filter_simplify<>>>>>(aut, given_si,
suspvars,
ignoredvars,
early_susp);
<state_filter
<acc_filter_mask
<false, false,
acc_filter_simplify<>>>>>(aut, given_si,
suspvars,
ignoredvars,
early_susp);
res->merge_edges();
res->prop_copy(aut,
{ false, // state-based acceptance is not preserved
true,
false, // determinism may not be preserved
false, // stutter inv. of suspvars probably altered
});
{ false, // state-based acceptance is not preserved
true,
false, // determinism may not be preserved
false, // stutter inv. of suspvars probably altered
});
return res;
}

View file

@ -59,7 +59,7 @@ namespace spot
/// instead.
SPOT_API twa_graph_ptr
scc_filter(const const_twa_graph_ptr& aut, bool remove_all_useless = false,
scc_info* given_si = nullptr);
scc_info* given_si = nullptr);
/// \brief Prune unaccepting SCCs.
///
@ -70,8 +70,8 @@ namespace spot
/// property.
SPOT_API twa_graph_ptr
scc_filter_states(const const_twa_graph_ptr& aut,
bool remove_all_useless = false,
scc_info* given_si = nullptr);
bool remove_all_useless = false,
scc_info* given_si = nullptr);
/// \brief Prune unaccepting SCCs, superfluous acceptance
/// sets, and suspension variables.
@ -85,6 +85,6 @@ namespace spot
/// other use.
SPOT_API twa_graph_ptr
scc_filter_susp(const const_twa_graph_ptr& aut, bool remove_all_useless,
bdd suspvars, bdd ignoredvars, bool early_susp,
scc_info* given_si = nullptr);
bdd suspvars, bdd ignoredvars, bool early_susp,
scc_info* given_si = nullptr);
}

View file

@ -35,15 +35,15 @@ namespace spot
{
public:
scc(int index, acc_cond::mark_t in_acc):
in_acc(in_acc), index(index)
in_acc(in_acc), index(index)
{
}
acc_cond::mark_t in_acc; // Acceptance sets on the incoming transition
acc_cond::mark_t acc = 0U; // union of all acceptance sets in the SCC
int index; // Index of the SCC
bool trivial = true; // Whether the SCC has no cycle
bool accepting = false; // Necessarily accepting
int index; // Index of the SCC
bool trivial = true; // Whether the SCC has no cycle
bool accepting = false; // Necessarily accepting
};
}
@ -54,165 +54,165 @@ namespace spot
sccof_.resize(n, -1U);
std::deque<unsigned> live;
std::deque<scc> root_; // Stack of SCC roots.
std::deque<scc> root_; // Stack of SCC roots.
std::vector<int> h_(n, 0);
// Map of visited states. Values > 0 designate maximal SCC.
// Values < 0 number states that are part of incomplete SCCs being
// completed. 0 denotes non-visited states.
int num_; // Number of visited nodes, negated.
int num_; // Number of visited nodes, negated.
typedef twa_graph::graph_t::const_iterator iterator;
typedef std::pair<unsigned, iterator> pair_state_iter;
std::stack<pair_state_iter> todo_; // DFS stack. Holds (STATE,
// ITERATOR) pairs where
// ITERATOR is an iterator over
// the successors of STATE.
// ITERATOR should always be
// freed when TODO is popped,
// but STATE should not because
// it is used as a key in H.
// ITERATOR) pairs where
// ITERATOR is an iterator over
// the successors of STATE.
// ITERATOR should always be
// freed when TODO is popped,
// but STATE should not because
// it is used as a key in H.
// Setup depth-first search from the initial state.
if (n > 0)
{
unsigned init = aut->get_init_state_number();
num_ = -1;
h_[init] = num_;
root_.emplace_back(num_, 0U);
todo_.emplace(init, aut->out(init).begin());
live.emplace_back(init);
unsigned init = aut->get_init_state_number();
num_ = -1;
h_[init] = num_;
root_.emplace_back(num_, 0U);
todo_.emplace(init, aut->out(init).begin());
live.emplace_back(init);
}
while (!todo_.empty())
{
// We are looking at the next successor in SUCC.
iterator succ = todo_.top().second;
// We are looking at the next successor in SUCC.
iterator succ = todo_.top().second;
// If there is no more successor, backtrack.
if (!succ)
{
// We have explored all successors of state CURR.
unsigned curr = todo_.top().first;
// If there is no more successor, backtrack.
if (!succ)
{
// We have explored all successors of state CURR.
unsigned curr = todo_.top().first;
// Backtrack TODO_.
todo_.pop();
// Backtrack TODO_.
todo_.pop();
// When backtracking the root of an SCC, we must also
// remove that SCC from the ARC/ROOT stacks. We must
// discard from H all reachable states from this SCC.
assert(!root_.empty());
if (root_.back().index == h_[curr])
{
unsigned num = node_.size();
auto acc = root_.back().acc;
bool triv = root_.back().trivial;
node_.emplace_back(acc, triv);
// When backtracking the root of an SCC, we must also
// remove that SCC from the ARC/ROOT stacks. We must
// discard from H all reachable states from this SCC.
assert(!root_.empty());
if (root_.back().index == h_[curr])
{
unsigned num = node_.size();
auto acc = root_.back().acc;
bool triv = root_.back().trivial;
node_.emplace_back(acc, triv);
// Move all elements of this SCC from the live stack
// to the the node.
auto i = std::find(live.rbegin(), live.rend(), curr);
assert(i != live.rend());
++i; // Because base() does -1
auto& nbs = node_.back().states_;
nbs.insert(nbs.end(), i.base(), live.end());
live.erase(i.base(), live.end());
// Move all elements of this SCC from the live stack
// to the the node.
auto i = std::find(live.rbegin(), live.rend(), curr);
assert(i != live.rend());
++i; // Because base() does -1
auto& nbs = node_.back().states_;
nbs.insert(nbs.end(), i.base(), live.end());
live.erase(i.base(), live.end());
std::set<unsigned> dests;
unsigned np1 = num + 1;
for (unsigned s: nbs)
{
sccof_[s] = num;
h_[s] = np1;
}
// Gather all successor SCCs
for (unsigned s: nbs)
for (auto& t: aut->out(s))
{
unsigned n = sccof_[t.dst];
assert(n != -1U);
if (n == num)
continue;
dests.insert(n);
}
auto& succ = node_.back().succ_;
succ.insert(succ.end(), dests.begin(), dests.end());
node_.back().accepting_ =
!triv && root_.back().accepting;
node_.back().rejecting_ =
triv || !aut->acc().inf_satisfiable(acc);
root_.pop_back();
}
continue;
}
std::set<unsigned> dests;
unsigned np1 = num + 1;
for (unsigned s: nbs)
{
sccof_[s] = num;
h_[s] = np1;
}
// Gather all successor SCCs
for (unsigned s: nbs)
for (auto& t: aut->out(s))
{
unsigned n = sccof_[t.dst];
assert(n != -1U);
if (n == num)
continue;
dests.insert(n);
}
auto& succ = node_.back().succ_;
succ.insert(succ.end(), dests.begin(), dests.end());
node_.back().accepting_ =
!triv && root_.back().accepting;
node_.back().rejecting_ =
triv || !aut->acc().inf_satisfiable(acc);
root_.pop_back();
}
continue;
}
// We have a successor to look at.
// Fetch the values we are interested in...
unsigned dest = succ->dst;
auto acc = succ->acc;
++todo_.top().second;
// We have a successor to look at.
// Fetch the values we are interested in...
unsigned dest = succ->dst;
auto acc = succ->acc;
++todo_.top().second;
// We do not need SUCC from now on.
// We do not need SUCC from now on.
// Are we going to a new state?
int spi = h_[dest];
if (spi == 0)
{
// Yes. Number it, stack it, and register its successors
// for later processing.
h_[dest] = --num_;
root_.emplace_back(num_, acc);
todo_.emplace(dest, aut->out(dest).begin());
live.emplace_back(dest);
continue;
}
// Are we going to a new state?
int spi = h_[dest];
if (spi == 0)
{
// Yes. Number it, stack it, and register its successors
// for later processing.
h_[dest] = --num_;
root_.emplace_back(num_, acc);
todo_.emplace(dest, aut->out(dest).begin());
live.emplace_back(dest);
continue;
}
// We already know the state.
// We already know the state.
// Have we reached a maximal SCC?
if (spi > 0)
continue;
// Have we reached a maximal SCC?
if (spi > 0)
continue;
// Now this is the most interesting case. We have reached a
// state S1 which is already part of a non-dead SCC. Any such
// non-dead SCC has necessarily been crossed by our path to
// this state: there is a state S2 in our path which belongs
// to this SCC too. We are going to merge all states between
// this S1 and S2 into this SCC..
//
// This merge is easy to do because the order of the SCC in
// ROOT is descending: we just have to merge all SCCs from the
// top of ROOT that have an index lesser than the one of
// the SCC of S2 (called the "threshold").
int threshold = spi;
bool is_accepting = false;
// If this is a self-loop, check its acceptance alone.
if (dest == succ->src)
is_accepting = aut->acc().accepting(acc);
// Now this is the most interesting case. We have reached a
// state S1 which is already part of a non-dead SCC. Any such
// non-dead SCC has necessarily been crossed by our path to
// this state: there is a state S2 in our path which belongs
// to this SCC too. We are going to merge all states between
// this S1 and S2 into this SCC..
//
// This merge is easy to do because the order of the SCC in
// ROOT is descending: we just have to merge all SCCs from the
// top of ROOT that have an index lesser than the one of
// the SCC of S2 (called the "threshold").
int threshold = spi;
bool is_accepting = false;
// If this is a self-loop, check its acceptance alone.
if (dest == succ->src)
is_accepting = aut->acc().accepting(acc);
assert(!root_.empty());
while (threshold > root_.back().index)
{
acc |= root_.back().acc;
acc |= root_.back().in_acc;
is_accepting |= root_.back().accepting;
root_.pop_back();
assert(!root_.empty());
}
assert(!root_.empty());
while (threshold > root_.back().index)
{
acc |= root_.back().acc;
acc |= root_.back().in_acc;
is_accepting |= root_.back().accepting;
root_.pop_back();
assert(!root_.empty());
}
// Note that we do not always have
// threshold == root_.back().index
// after this loop, the SCC whose index is threshold might have
// been merged with a higher SCC.
// Note that we do not always have
// threshold == root_.back().index
// after this loop, the SCC whose index is threshold might have
// been merged with a higher SCC.
// Accumulate all acceptance conditions, states, SCC
// successors, and conditions into the merged SCC.
root_.back().acc |= acc;
root_.back().accepting |= is_accepting
|| aut->acc().accepting(root_.back().acc);
// This SCC is no longer trivial.
root_.back().trivial = false;
// Accumulate all acceptance conditions, states, SCC
// successors, and conditions into the merged SCC.
root_.back().acc |= acc;
root_.back().accepting |= is_accepting
|| aut->acc().accepting(root_.back().acc);
// This SCC is no longer trivial.
root_.back().trivial = false;
}
determine_usefulness();
@ -225,18 +225,18 @@ namespace spot
unsigned scccount = scc_count();
for (unsigned i = 0; i < scccount; ++i)
{
if (!node_[i].is_rejecting())
{
node_[i].useful_ = true;
continue;
}
node_[i].useful_ = false;
for (unsigned j: node_[i].succ())
if (node_[j].is_useful())
{
node_[i].useful_ = true;
break;
}
if (!node_[i].is_rejecting())
{
node_[i].useful_ = true;
continue;
}
node_[i].useful_ = false;
for (unsigned j: node_[i].succ())
if (node_[j].is_useful())
{
node_[i].useful_ = true;
break;
}
}
}
@ -246,8 +246,8 @@ namespace spot
std::set<acc_cond::mark_t> res;
for (auto src: states_of(scc))
for (auto& t: aut_->out(src))
if (scc_of(t.dst) == scc)
res.insert(t.acc);
if (scc_of(t.dst) == scc)
res.insert(t.acc);
return res;
}
@ -256,8 +256,8 @@ namespace spot
acc_cond::mark_t res = 0U;
for (auto src: states_of(scc))
for (auto& t: aut_->out(src))
if (scc_of(t.dst) == scc)
res |= t.acc;
if (scc_of(t.dst) == scc)
res |= t.acc;
return res;
}
@ -268,16 +268,16 @@ namespace spot
for (unsigned src = 0; src < n; ++src)
{
unsigned src_scc = scc_of(src);
if (src_scc == -1U || is_rejecting_scc(src_scc))
continue;
auto& s = result[src_scc];
for (auto& t: aut_->out(src))
{
if (scc_of(t.dst) != src_scc)
continue;
s.insert(t.acc);
}
unsigned src_scc = scc_of(src);
if (src_scc == -1U || is_rejecting_scc(src_scc))
continue;
auto& s = result[src_scc];
for (auto& t: aut_->out(src))
{
if (scc_of(t.dst) != src_scc)
continue;
s.insert(t.acc);
}
}
return result;
}
@ -297,7 +297,7 @@ namespace spot
bdd support = bddtrue;
for (auto s: states_of(scc))
for (auto& t: aut_->out(s))
support &= bdd_support(t.cond);
support &= bdd_support(t.cond);
return support;
}
@ -308,25 +308,25 @@ namespace spot
bool changed = false;
for (unsigned s = 0; s < n; ++s)
if (!is_rejecting_scc(s) && !is_accepting_scc(s))
{
auto& node = node_[s];
if (k.empty())
k.resize(aut_->num_states());
for (auto i: node.states_)
k[i] = true;
if (mask_keep_states(aut_, k, node.states_.front())->is_empty())
node.rejecting_ = true;
else
node.accepting_ = true;
changed = true;
}
{
auto& node = node_[s];
if (k.empty())
k.resize(aut_->num_states());
for (auto i: node.states_)
k[i] = true;
if (mask_keep_states(aut_, k, node.states_.front())->is_empty())
node.rejecting_ = true;
else
node.accepting_ = true;
changed = true;
}
if (changed)
determine_usefulness();
}
std::ostream&
dump_scc_info_dot(std::ostream& out,
const_twa_graph_ptr aut, scc_info* sccinfo)
const_twa_graph_ptr aut, scc_info* sccinfo)
{
scc_info* m = sccinfo ? sccinfo : new scc_info(aut);
@ -341,29 +341,29 @@ namespace spot
q.push(start);
while (!q.empty())
{
int state = q.front();
q.pop();
int state = q.front();
q.pop();
out << " " << state << " [shape=box,"
out << " " << state << " [shape=box,"
<< (aut->acc().accepting(m->acc(state)) ? "style=bold," : "")
<< "label=\"" << state;
{
size_t n = m->states_of(state).size();
out << " (" << n << " state";
if (n > 1)
out << 's';
out << ')';
}
out << "\"]\n";
{
size_t n = m->states_of(state).size();
out << " (" << n << " state";
if (n > 1)
out << 's';
out << ')';
}
out << "\"]\n";
for (unsigned dest: m->succ(state))
{
out << " " << state << " -> " << dest << '\n';
if (seen[dest])
continue;
seen[dest] = true;
q.push(dest);
}
for (unsigned dest: m->succ(state))
{
out << " " << state << " -> " << dest << '\n';
if (seen[dest])
continue;
seen[dest] = true;
q.push(dest);
}
}
out << "}\n";

View file

@ -37,25 +37,25 @@ namespace spot
acc_cond::mark_t acc_;
std::vector<unsigned> states_; // States of the component
bool trivial_:1;
bool accepting_:1; // Necessarily accepting
bool rejecting_:1; // Necessarily rejecting
bool accepting_:1; // Necessarily accepting
bool rejecting_:1; // Necessarily rejecting
bool useful_:1;
public:
scc_node():
acc_(0U), trivial_(true), accepting_(false),
rejecting_(false), useful_(false)
acc_(0U), trivial_(true), accepting_(false),
rejecting_(false), useful_(false)
{
}
scc_node(acc_cond::mark_t acc, bool trivial):
acc_(acc), trivial_(trivial), accepting_(false),
rejecting_(false), useful_(false)
acc_(acc), trivial_(trivial), accepting_(false),
rejecting_(false), useful_(false)
{
}
bool is_trivial() const
{
return trivial_;
return trivial_;
}
/// \brief True if we are sure that the SCC is accepting
@ -64,7 +64,7 @@ namespace spot
/// false if an SCC interesects a mix of Fin and Inf sets.
bool is_accepting() const
{
return accepting_;
return accepting_;
}
// True if we are sure that the SCC is rejecting
@ -73,27 +73,27 @@ namespace spot
/// false if an SCC interesects a mix of Fin and Inf sets.
bool is_rejecting() const
{
return rejecting_;
return rejecting_;
}
bool is_useful() const
{
return useful_;
return useful_;
}
acc_cond::mark_t acc_marks() const
{
return acc_;
return acc_;
}
const std::vector<unsigned>& states() const
{
return states_;
return states_;
}
const scc_succs& succ() const
{
return succ_;
return succ_;
}
};
@ -224,6 +224,6 @@ namespace spot
/// If \a sccinfo is not given, it will be computed.
SPOT_API std::ostream&
dump_scc_info_dot(std::ostream& out,
const_twa_graph_ptr aut, scc_info* sccinfo = nullptr);
const_twa_graph_ptr aut, scc_info* sccinfo = nullptr);
}

View file

@ -55,7 +55,7 @@ namespace spot
/// \pre The automaton \a a must have at most one acceptance
/// condition (i.e. it is a TBA).
se05_search(const const_twa_ptr a, size_t size,
option_map o = option_map())
option_map o = option_map())
: emptiness_check(a, o),
h(size)
{
@ -89,8 +89,8 @@ namespace spot
/// visits only a finite set of accepting paths.
virtual emptiness_check_result_ptr check() override
{
auto t = std::static_pointer_cast<se05_search>
(this->emptiness_check::shared_from_this());
auto t = std::static_pointer_cast<se05_search>
(this->emptiness_check::shared_from_this());
if (st_red.empty())
{
assert(st_blue.empty());
@ -130,27 +130,27 @@ namespace spot
virtual bool safe() const override
{
return heap::Safe;
return heap::Safe;
}
const heap& get_heap() const
{
return h;
return h;
}
const stack_type& get_st_blue() const
{
return st_blue;
return st_blue;
}
const stack_type& get_st_red() const
{
return st_red;
return st_red;
}
private:
void push(stack_type& st, const state* s,
const bdd& label, acc_cond::mark_t acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
twa_succ_iterator* i = a_->succ_iter(s);
@ -201,7 +201,7 @@ namespace spot
}
else if (c.get_color() == CYAN && (a_->acc().accepting(acc) ||
(f.s->compare(s_prime) != 0
&& a_->acc().accepting(f.acc))))
&& a_->acc().accepting(f.acc))))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
@ -238,7 +238,7 @@ namespace spot
typename heap::color_ref c = h.get_color_ref(f_dest.s);
assert(!c.is_white());
if (!st_blue.empty() &&
a_->acc().accepting(f_dest.acc) && c.get_color() != RED)
a_->acc().accepting(f_dest.acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -383,7 +383,7 @@ namespace spot
return 0;
}
private:
std::shared_ptr<se05_search> ms_;
std::shared_ptr<se05_search> ms_;
};
# define FROM_STACK "ar:from_stack"
@ -392,7 +392,7 @@ namespace spot
{
public:
se05_result(const std::shared_ptr<se05_search>& m,
option_map o = option_map())
option_map o = option_map())
: emptiness_check_result(m->automaton(), o), ms(m)
{
if (options()[FROM_STACK])
@ -432,7 +432,7 @@ namespace spot
private:
emptiness_check_result* computer;
std::shared_ptr<se05_search> ms;
std::shared_ptr<se05_search> ms;
};
};
@ -573,7 +573,7 @@ namespace spot
{
private:
typedef std::unordered_set<const state*,
state_ptr_hash, state_ptr_equal> hcyan_type;
state_ptr_hash, state_ptr_equal> hcyan_type;
public:
enum { Safe = 0 };
@ -681,7 +681,7 @@ namespace spot
emptiness_check_ptr
bit_state_hashing_se05_search(const const_twa_ptr& a,
size_t size, option_map o)
size_t size, option_map o)
{
return std::make_shared<se05_search<bsh_se05_search_heap>>(a, size, o);
}

View file

@ -132,7 +132,7 @@ namespace spot
///
SPOT_API emptiness_check_ptr
bit_state_hashing_se05_search(const const_twa_ptr& a, size_t size,
option_map o = option_map());
option_map o = option_map());
/// \brief Wrapper for the two se05 implementations.

View file

@ -48,8 +48,8 @@ namespace spot
{
unsigned base = aut->acc().add_sets(common.count());
for (auto s: common.sets())
map.emplace_back(acc_cond::mark_t({s}),
acc_cond::mark_t({base++}));
map.emplace_back(acc_cond::mark_t({s}),
acc_cond::mark_t({base++}));
}
// Fix the acceptance condition
@ -60,38 +60,38 @@ namespace spot
acc_cond::acc_word* start = &code.front();
while (pos > start)
{
switch (pos->op)
{
case acc_cond::acc_op::Or:
case acc_cond::acc_op::And:
--pos;
break;
case acc_cond::acc_op::Fin:
case acc_cond::acc_op::FinNeg:
if ((pos[-1].mark & common) == 0U)
break;
for (auto p: map)
if (pos[-1].mark & p.first)
{
pos[-1].mark -= p.first;
pos[-1].mark |= p.second;
}
/* fall through */
case acc_cond::acc_op::Inf:
case acc_cond::acc_op::InfNeg:
pos -= 2;
break;
}
switch (pos->op)
{
case acc_cond::acc_op::Or:
case acc_cond::acc_op::And:
--pos;
break;
case acc_cond::acc_op::Fin:
case acc_cond::acc_op::FinNeg:
if ((pos[-1].mark & common) == 0U)
break;
for (auto p: map)
if (pos[-1].mark & p.first)
{
pos[-1].mark -= p.first;
pos[-1].mark |= p.second;
}
/* fall through */
case acc_cond::acc_op::Inf:
case acc_cond::acc_op::InfNeg:
pos -= 2;
break;
}
}
// Fix the edges
for (auto& t: aut->edges())
{
if ((t.acc & common) == 0U)
continue;
for (auto p: map)
if (t.acc & p.first)
t.acc |= p.second;
if ((t.acc & common) == 0U)
continue;
for (auto p: map)
if (t.acc & p.first)
t.acc |= p.second;
}
return aut;
}

View file

@ -109,8 +109,8 @@ namespace spot
void set_size(const twa_graph_ptr& a)
{
states = a->num_states();
edges = a->num_edges();
states = a->num_states();
edges = a->num_edges();
}
inline bool operator!=(const automaton_size& r)
@ -166,23 +166,23 @@ namespace spot
bdd mark_to_bdd(acc_cond::mark_t m)
{
// FIXME: Use a cache.
bdd res = bddtrue;
for (auto n: m.sets())
res &= bdd_ithvar(acc_vars + n);
return res;
// FIXME: Use a cache.
bdd res = bddtrue;
for (auto n: m.sets())
res &= bdd_ithvar(acc_vars + n);
return res;
}
acc_cond::mark_t bdd_to_mark(bdd b)
{
// FIXME: Use a cache.
std::vector<unsigned> res;
while (b != bddtrue)
{
res.push_back(bdd_var(b) - acc_vars);
b = bdd_high(b);
}
return acc_cond::mark_t(res.begin(), res.end());
// FIXME: Use a cache.
std::vector<unsigned> res;
while (b != bddtrue)
{
res.push_back(bdd_var(b) - acc_vars);
b = bdd_high(b);
}
return acc_cond::mark_t(res.begin(), res.end());
}
direct_simulation(const const_twa_graph_ptr& in)
@ -190,104 +190,104 @@ namespace spot
all_class_var_(bddtrue),
original_(in)
{
if (!has_separate_sets(in))
throw std::runtime_error
("direct_simulation() requires separate Inf and Fin sets");
if (!has_separate_sets(in))
throw std::runtime_error
("direct_simulation() requires separate Inf and Fin sets");
// Call get_init_state_number() before anything else as it
// might add a state.
unsigned init_state_number = in->get_init_state_number();
// Call get_init_state_number() before anything else as it
// might add a state.
unsigned init_state_number = in->get_init_state_number();
scc_info_.reset(new scc_info(in));
unsigned ns = in->num_states();
assert(ns > 0);
size_a_ = ns;
unsigned ns = in->num_states();
assert(ns > 0);
size_a_ = ns;
auto all_inf = in->get_acceptance().used_inf_fin_sets().first;
all_inf_ = all_inf;
auto all_inf = in->get_acceptance().used_inf_fin_sets().first;
all_inf_ = all_inf;
// Replace all the acceptance conditions by their complements.
// (In the case of Cosimulation, we also flip the edges.)
if (Cosimulation)
{
a_ = make_twa_graph(in->get_dict());
a_->copy_ap_of(in);
a_->copy_acceptance_of(in);
a_->new_states(ns);
// Replace all the acceptance conditions by their complements.
// (In the case of Cosimulation, we also flip the edges.)
if (Cosimulation)
{
a_ = make_twa_graph(in->get_dict());
a_->copy_ap_of(in);
a_->copy_acceptance_of(in);
a_->new_states(ns);
for (unsigned s = 0; s < ns; ++s)
{
for (auto& t: in->out(s))
{
acc_cond::mark_t acc;
if (Sba)
{
// If the acceptance is interpreted as
// state-based, to apply the reverse simulation
// on a SBA, we should pull the acceptance of
// the destination state on its incoming arcs
// (which now become outgoing arcs after
// transposition).
acc = 0U;
for (auto& td: in->out(t.dst))
{
acc = td.acc ^ all_inf;
break;
}
}
else
{
acc = t.acc ^ all_inf;
}
a_->new_edge(t.dst, s, t.cond, acc);
}
a_->set_init_state(init_state_number);
}
}
else
{
a_ = make_twa_graph(in, twa::prop_set::all());
for (auto& t: a_->edges())
t.acc ^= all_inf;
}
assert(a_->num_states() == size_a_);
for (unsigned s = 0; s < ns; ++s)
{
for (auto& t: in->out(s))
{
acc_cond::mark_t acc;
if (Sba)
{
// If the acceptance is interpreted as
// state-based, to apply the reverse simulation
// on a SBA, we should pull the acceptance of
// the destination state on its incoming arcs
// (which now become outgoing arcs after
// transposition).
acc = 0U;
for (auto& td: in->out(t.dst))
{
acc = td.acc ^ all_inf;
break;
}
}
else
{
acc = t.acc ^ all_inf;
}
a_->new_edge(t.dst, s, t.cond, acc);
}
a_->set_init_state(init_state_number);
}
}
else
{
a_ = make_twa_graph(in, twa::prop_set::all());
for (auto& t: a_->edges())
t.acc ^= all_inf;
}
assert(a_->num_states() == size_a_);
// Now, we have to get the bdd which will represent the
// class. We register one bdd by state, because in the worst
// case, |Class| == |State|.
unsigned set_num = a_->get_dict()
->register_anonymous_variables(size_a_ + 1, this);
// Now, we have to get the bdd which will represent the
// class. We register one bdd by state, because in the worst
// case, |Class| == |State|.
unsigned set_num = a_->get_dict()
->register_anonymous_variables(size_a_ + 1, this);
unsigned n_acc = a_->num_sets();
acc_vars = a_->get_dict()
->register_anonymous_variables(n_acc, this);
unsigned n_acc = a_->num_sets();
acc_vars = a_->get_dict()
->register_anonymous_variables(n_acc, this);
all_proms_ = bddtrue;
for (unsigned v = acc_vars; v < acc_vars + n_acc; ++v)
all_proms_ &= bdd_ithvar(v);
all_proms_ = bddtrue;
for (unsigned v = acc_vars; v < acc_vars + n_acc; ++v)
all_proms_ &= bdd_ithvar(v);
bdd_initial = bdd_ithvar(set_num++);
bdd init = bdd_ithvar(set_num++);
bdd init = bdd_ithvar(set_num++);
used_var_.push_back(init);
used_var_.push_back(init);
// Initialize all classes to init.
previous_class_.resize(size_a_);
for (unsigned s = 0; s < size_a_; ++s)
previous_class_[s] = init;
// Initialize all classes to init.
previous_class_.resize(size_a_);
for (unsigned s = 0; s < size_a_; ++s)
previous_class_[s] = init;
// Put all the anonymous variable in a queue, and record all
// of these in a variable all_class_var_ which will be used
// to understand the destination part in the signature when
// building the resulting automaton.
all_class_var_ = init;
for (unsigned i = set_num; i < set_num + size_a_ - 1; ++i)
// Put all the anonymous variable in a queue, and record all
// of these in a variable all_class_var_ which will be used
// to understand the destination part in the signature when
// building the resulting automaton.
all_class_var_ = init;
for (unsigned i = set_num; i < set_num + size_a_ - 1; ++i)
{
free_var_.push(i);
all_class_var_ &= bdd_ithvar(i);
}
relation_[init] = init;
relation_[init] = init;
}
@ -296,40 +296,40 @@ namespace spot
// function simulation.
virtual ~direct_simulation()
{
a_->get_dict()->unregister_all_my_variables(this);
a_->get_dict()->unregister_all_my_variables(this);
}
// Update the name of the classes.
void update_previous_class()
{
std::list<bdd>::iterator it_bdd = used_var_.begin();
std::list<bdd>::iterator it_bdd = used_var_.begin();
// We run through the map bdd/list<state>, and we update
// the previous_class_ with the new data.
for (auto& p: bdd_lstate_)
// We run through the map bdd/list<state>, and we update
// the previous_class_ with the new data.
for (auto& p: bdd_lstate_)
{
// If the signature of a state is bddfalse (no
// edges) the class of this state is bddfalse
// instead of an anonymous variable. It allows
// simplifications in the signature by removing a
// edge which has as a destination a state with
// no outgoing edge.
if (p.first == bddfalse)
for (auto s: p.second)
previous_class_[s] = bddfalse;
else
for (auto s: p.second)
previous_class_[s] = *it_bdd;
++it_bdd;
// If the signature of a state is bddfalse (no
// edges) the class of this state is bddfalse
// instead of an anonymous variable. It allows
// simplifications in the signature by removing a
// edge which has as a destination a state with
// no outgoing edge.
if (p.first == bddfalse)
for (auto s: p.second)
previous_class_[s] = bddfalse;
else
for (auto s: p.second)
previous_class_[s] = *it_bdd;
++it_bdd;
}
}
void main_loop()
{
unsigned int nb_partition_before = 0;
unsigned int nb_po_before = po_size_ - 1;
while (nb_partition_before != bdd_lstate_.size()
|| nb_po_before != po_size_)
unsigned int nb_partition_before = 0;
unsigned int nb_po_before = po_size_ - 1;
while (nb_partition_before != bdd_lstate_.size()
|| nb_po_before != po_size_)
{
update_previous_class();
nb_partition_before = bdd_lstate_.size();
@ -340,14 +340,14 @@ namespace spot
go_to_next_it();
}
update_previous_class();
update_previous_class();
}
// The core loop of the algorithm.
twa_graph_ptr run(std::map<int, bdd>* implications = nullptr)
{
main_loop();
return build_result(implications);
return build_result(implications);
}
// Take a state and compute its signature.
@ -359,13 +359,13 @@ namespace spot
{
bdd acc = mark_to_bdd(t.acc);
// to_add is a conjunction of the acceptance condition,
// the label of the edge and the class of the
// destination and all the class it implies.
bdd to_add = acc & t.cond & relation_[previous_class_[t.dst]];
// to_add is a conjunction of the acceptance condition,
// the label of the edge and the class of the
// destination and all the class it implies.
bdd to_add = acc & t.cond & relation_[previous_class_[t.dst]];
res |= to_add;
}
res |= to_add;
}
// When we Cosimulate, we add a special flag to differentiate
// the initial state from the other.
@ -378,20 +378,20 @@ namespace spot
void update_sig()
{
for (unsigned s = 0; s < size_a_; ++s)
bdd_lstate_[compute_sig(s)].push_back(s);
for (unsigned s = 0; s < size_a_; ++s)
bdd_lstate_[compute_sig(s)].push_back(s);
}
// This method rename the color set, update the partial order.
void go_to_next_it()
{
int nb_new_color = bdd_lstate_.size() - used_var_.size();
int nb_new_color = bdd_lstate_.size() - used_var_.size();
// If we have created more partitions, we need to use more
// variables.
for (int i = 0; i < nb_new_color; ++i)
for (int i = 0; i < nb_new_color; ++i)
{
assert(!free_var_.empty());
used_var_.push_back(bdd_ithvar(free_var_.front()));
@ -401,7 +401,7 @@ namespace spot
// If we have reduced the number of partition, we 'free' them
// in the free_var_ list.
for (int i = 0; i > nb_new_color; --i)
for (int i = 0; i > nb_new_color; --i)
{
assert(!used_var_.empty());
free_var_.push(bdd_var(used_var_.front()));
@ -409,36 +409,36 @@ namespace spot
}
assert((bdd_lstate_.size() == used_var_.size())
assert((bdd_lstate_.size() == used_var_.size())
|| (bdd_lstate_.find(bddfalse) != bdd_lstate_.end()
&& bdd_lstate_.size() == used_var_.size() + 1));
// Now we make a temporary hash_table which links the tuple
// "C^(i-1), N^(i-1)" to the new class coloring. If we
// rename the class before updating the partial order, we
// loose the information, and if we make it after, I can't
// figure out how to apply this renaming on rel_.
// It adds a data structure but it solves our problem.
map_bdd_bdd now_to_next;
// Now we make a temporary hash_table which links the tuple
// "C^(i-1), N^(i-1)" to the new class coloring. If we
// rename the class before updating the partial order, we
// loose the information, and if we make it after, I can't
// figure out how to apply this renaming on rel_.
// It adds a data structure but it solves our problem.
map_bdd_bdd now_to_next;
std::list<bdd>::iterator it_bdd = used_var_.begin();
std::list<bdd>::iterator it_bdd = used_var_.begin();
for (auto& p: bdd_lstate_)
for (auto& p: bdd_lstate_)
{
// If the signature of a state is bddfalse (no
// edges) the class of this state is bddfalse
// instead of an anonymous variable. It allows
// simplifications in the signature by removing a
// edge which has as a destination a state with
// no outgoing edge.
bdd acc = bddfalse;
if (p.first != bddfalse)
acc = *it_bdd;
now_to_next[p.first] = acc;
++it_bdd;
// If the signature of a state is bddfalse (no
// edges) the class of this state is bddfalse
// instead of an anonymous variable. It allows
// simplifications in the signature by removing a
// edge which has as a destination a state with
// no outgoing edge.
bdd acc = bddfalse;
if (p.first != bddfalse)
acc = *it_bdd;
now_to_next[p.first] = acc;
++it_bdd;
}
update_po(now_to_next, relation_);
update_po(now_to_next, relation_);
}
// This function computes the new po with previous_class_ and
@ -451,17 +451,17 @@ namespace spot
void update_po(const container_bdd_bdd& now_to_next,
map_bdd_bdd& relation)
{
// This loop follows the pattern given by the paper.
// foreach class do
// | foreach class do
// | | update po if needed
// | od
// od
// This loop follows the pattern given by the paper.
// foreach class do
// | foreach class do
// | | update po if needed
// | od
// od
for (typename container_bdd_bdd::const_iterator it1
for (typename container_bdd_bdd::const_iterator it1
= now_to_next.begin();
it1 != now_to_next.end();
++it1)
it1 != now_to_next.end();
++it1)
{
bdd accu = it1->second;
for (typename container_bdd_bdd::const_iterator it2
@ -486,31 +486,31 @@ namespace spot
// Build the minimal resulting automaton.
twa_graph_ptr build_result(std::map<int, bdd>* implications = nullptr)
{
twa_graph_ptr res = make_twa_graph(a_->get_dict());
res->copy_ap_of(a_);
res->copy_acceptance_of(a_);
twa_graph_ptr res = make_twa_graph(a_->get_dict());
res->copy_ap_of(a_);
res->copy_acceptance_of(a_);
// Non atomic propositions variables (= acc and class)
bdd nonapvars = all_proms_ & bdd_support(all_class_var_);
// Non atomic propositions variables (= acc and class)
bdd nonapvars = all_proms_ & bdd_support(all_class_var_);
auto* gb = res->create_namer<int>();
auto* gb = res->create_namer<int>();
// Create one state per partition.
for (auto& p: bdd_lstate_)
// Create one state per partition.
for (auto& p: bdd_lstate_)
{
bdd cl = previous_class_[p.second.front()];
// A state may be referred to either by
// its class, or by all the implied classes.
auto s = gb->new_state(cl.id());
gb->alias_state(s, relation_[cl].id());
// A state may be referred to either by
// its class, or by all the implied classes.
auto s = gb->new_state(cl.id());
gb->alias_state(s, relation_[cl].id());
if (implications)
(*implications)[s] = relation_[cl];
}
// Acceptance of states. Only used if Sba && Cosimulation.
std::vector<acc_cond::mark_t> accst;
if (Sba && Cosimulation)
accst.resize(res->num_states(), 0U);
// Acceptance of states. Only used if Sba && Cosimulation.
std::vector<acc_cond::mark_t> accst;
if (Sba && Cosimulation)
accst.resize(res->num_states(), 0U);
stat.states = bdd_lstate_.size();
stat.edges = 0;
@ -518,14 +518,14 @@ namespace spot
unsigned nb_satoneset = 0;
unsigned nb_minato = 0;
auto all_inf = all_inf_;
// For each class, we will create
// all the edges between the states.
for (auto& p: bdd_lstate_)
auto all_inf = all_inf_;
// For each class, we will create
// all the edges between the states.
for (auto& p: bdd_lstate_)
{
// All states in p.second have the same class, so just
// pick the class of the first one first one.
bdd src = previous_class_[p.second.front()];
// All states in p.second have the same class, so just
// pick the class of the first one first one.
bdd src = previous_class_[p.second.front()];
// Get the signature to derive successors.
bdd sig = compute_sig(p.second.front());
@ -544,108 +544,108 @@ namespace spot
// proposition.
bdd all_atomic_prop = bdd_exist(sig, nonapvars);
// First loop over all possible valuations atomic properties.
// First loop over all possible valuations atomic properties.
while (all_atomic_prop != bddfalse)
{
bdd one = bdd_satoneset(all_atomic_prop,
sup_all_atomic_prop,
bddtrue);
all_atomic_prop -= one;
{
bdd one = bdd_satoneset(all_atomic_prop,
sup_all_atomic_prop,
bddtrue);
all_atomic_prop -= one;
// For each possible valuation, iterate over all possible
// destination classes. We use minato_isop here, because
// if the same valuation of atomic properties can go
// to two different classes C1 and C2, iterating on
// C1 + C2 with the above bdd_satoneset loop will see
// C1 then (!C1)C2, instead of C1 then C2.
// With minatop_isop, we ensure that the no negative
// class variable will be seen (likewise for promises).
minato_isop isop(sig & one);
// For each possible valuation, iterate over all possible
// destination classes. We use minato_isop here, because
// if the same valuation of atomic properties can go
// to two different classes C1 and C2, iterating on
// C1 + C2 with the above bdd_satoneset loop will see
// C1 then (!C1)C2, instead of C1 then C2.
// With minatop_isop, we ensure that the no negative
// class variable will be seen (likewise for promises).
minato_isop isop(sig & one);
++nb_satoneset;
bdd cond_acc_dest;
while ((cond_acc_dest = isop.next()) != bddfalse)
{
bdd cond_acc_dest;
while ((cond_acc_dest = isop.next()) != bddfalse)
{
++stat.edges;
++nb_minato;
// Take the edge, and keep only the variable which
// are used to represent the class.
bdd dst = bdd_existcomp(cond_acc_dest,
all_class_var_);
// Take the edge, and keep only the variable which
// are used to represent the class.
bdd dst = bdd_existcomp(cond_acc_dest,
all_class_var_);
// Keep only ones who are acceptance condition.
auto acc = bdd_to_mark(bdd_existcomp(cond_acc_dest,
all_proms_));
// Keep only ones who are acceptance condition.
auto acc = bdd_to_mark(bdd_existcomp(cond_acc_dest,
all_proms_));
// Keep the other!
bdd cond = bdd_existcomp(cond_acc_dest,
sup_all_atomic_prop);
// Keep the other!
bdd cond = bdd_existcomp(cond_acc_dest,
sup_all_atomic_prop);
// Because we have complemented all the Inf
// acceptance conditions on the input automaton,
// we must revert them to create a new edge.
acc ^= all_inf;
// Because we have complemented all the Inf
// acceptance conditions on the input automaton,
// we must revert them to create a new edge.
acc ^= all_inf;
if (Cosimulation)
{
if (Sba)
{
// acc should be attached to src, or rather,
// in our edge-based representation)
// to all edges leaving src. As we
// can't do this here, store this in a table
// so we can fix it later.
accst[gb->get_state(src.id())] = acc;
acc = 0U;
}
gb->new_edge(dst.id(), src.id(), cond, acc);
}
else
{
gb->new_edge(src.id(), dst.id(), cond, acc);
}
}
}
if (Cosimulation)
{
if (Sba)
{
// acc should be attached to src, or rather,
// in our edge-based representation)
// to all edges leaving src. As we
// can't do this here, store this in a table
// so we can fix it later.
accst[gb->get_state(src.id())] = acc;
acc = 0U;
}
gb->new_edge(dst.id(), src.id(), cond, acc);
}
else
{
gb->new_edge(src.id(), dst.id(), cond, acc);
}
}
}
}
res->set_init_state(gb->get_state(previous_class_
[a_->get_init_state_number()].id()));
res->set_init_state(gb->get_state(previous_class_
[a_->get_init_state_number()].id()));
res->merge_edges(); // FIXME: is this really needed?
res->merge_edges(); // FIXME: is this really needed?
// Mark all accepting state in a second pass, when
// dealing with SBA in cosimulation.
if (Sba && Cosimulation)
{
unsigned ns = res->num_states();
for (unsigned s = 0; s < ns; ++s)
{
acc_cond::mark_t acc = accst[s];
if (acc == 0U)
continue;
for (auto& t: res->out(s))
t.acc = acc;
}
}
// Mark all accepting state in a second pass, when
// dealing with SBA in cosimulation.
if (Sba && Cosimulation)
{
unsigned ns = res->num_states();
for (unsigned s = 0; s < ns; ++s)
{
acc_cond::mark_t acc = accst[s];
if (acc == 0U)
continue;
for (auto& t: res->out(s))
t.acc = acc;
}
}
res->purge_unreachable_states();
res->purge_unreachable_states();
delete gb;
res->prop_copy(original_,
{ false, // state-based acc forced below
true, // weakness preserved,
true, // determinism checked and overridden below
// and "unambiguous" property preserved
true, // stutter inv.
});
res->prop_copy(original_,
{ false, // state-based acc forced below
true, // weakness preserved,
true, // determinism checked and overridden below
// and "unambiguous" property preserved
true, // stutter inv.
});
if (nb_minato == nb_satoneset && !Cosimulation)
res->prop_deterministic(true);
if (Sba)
res->prop_state_acc(true);
return res;
res->prop_deterministic(true);
if (Sba)
res->prop_state_acc(true);
return res;
}
@ -656,21 +656,21 @@ namespace spot
// where is the new class name.
void print_partition()
{
for (auto& p: bdd_lstate_)
for (auto& p: bdd_lstate_)
{
std::cerr << "partition: "
<< bdd_format_isop(a_->get_dict(), p.first)
<< std::endl;
for (auto s: p.second)
std::cerr << " - "
<< a_->format_state(a_->state_from_number(s))
<< '\n';
std::cerr << " - "
<< a_->format_state(a_->state_from_number(s))
<< '\n';
}
std::cerr << "\nPrevious iteration\n" << std::endl;
std::cerr << "\nPrevious iteration\n" << std::endl;
unsigned ps = previous_class_.size();
for (unsigned p = 0; p < ps; ++p)
unsigned ps = previous_class_.size();
for (unsigned p = 0; p < ps; ++p)
{
std::cerr << a_->format_state(a_->state_from_number(p))
<< " was in "
@ -781,15 +781,15 @@ namespace spot
direct_simulation<false, Sba> simul(res ? res : t);
res = simul.run();
if (res->prop_deterministic())
break;
break;
direct_simulation<true, Sba> cosimul(res);
res = cosimul.run();
res = cosimul.run();
if (Sba)
res = scc_filter_states(res, false);
else
res = scc_filter(res, false);
if (Sba)
res = scc_filter_states(res, false);
else
res = scc_filter(res, false);
next.set_size(res);
}

View file

@ -41,7 +41,7 @@ namespace spot
author = {Kousha Etessami and Gerard J. Holzmann},
title = {Optimizing {B\"u}chi Automata},
booktitle = {Proceedings of the 11th International Conference on
Concurrency Theory (Concur'00)},
Concurrency Theory (Concur'00)},
pages = {153--167},
year = {2000},
editor = {C. Palamidessi},
@ -87,8 +87,8 @@ namespace spot
/// but generalized to handle TωA directly.
/** \verbatim
@InProceedings{ somenzi.00.cav,
author = {Fabio Somenzi and Roderick Bloem},
title = {Efficient {B\"u}chi Automata for {LTL} Formul{\ae}},
author = {Fabio Somenzi and Roderick Bloem},
title = {Efficient {B\"u}chi Automata for {LTL} Formul{\ae}},
booktitle = {Proceedings of the 12th International Conference on
Computer Aided Verification (CAV'00)},
pages = {247--263},

View file

@ -37,21 +37,21 @@ namespace spot
{
public:
stats_bfs(const const_twa_ptr& a, twa_statistics& s)
: twa_reachable_iterator_breadth_first(a), s_(s)
: twa_reachable_iterator_breadth_first(a), s_(s)
{
}
void
process_state(const state*, int, twa_succ_iterator*) override final
{
++s_.states;
++s_.states;
}
void
process_link(const state*, int, const state*, int,
const twa_succ_iterator*) override
const twa_succ_iterator*) override
{
++s_.edges;
++s_.edges;
}
private:
@ -62,38 +62,38 @@ namespace spot
{
public:
sub_stats_bfs(const const_twa_ptr& a, twa_sub_statistics& s)
: stats_bfs(a, s), s_(s), seen_(bddtrue)
: stats_bfs(a, s), s_(s), seen_(bddtrue)
{
}
void
process_link(const state*, int, const state*, int,
const twa_succ_iterator* it) override
const twa_succ_iterator* it) override
{
++s_.edges;
++s_.edges;
bdd cond = it->cond();
bdd newvars = bdd_exist(bdd_support(cond), seen_);
if (newvars != bddtrue)
{
seen_ &= newvars;
int count = 0;
while (newvars != bddtrue)
{
++count;
newvars = bdd_high(newvars);
}
// If we discover one new variable, that means that all
// transitions we counted so far are actually double
// subtransitions. If we have two new variables, they where
// quadruple transitions, etc.
s_.transitions <<= count;
}
while (cond != bddfalse)
{
cond -= bdd_satoneset(cond, seen_, bddtrue);
++s_.transitions;
}
bdd cond = it->cond();
bdd newvars = bdd_exist(bdd_support(cond), seen_);
if (newvars != bddtrue)
{
seen_ &= newvars;
int count = 0;
while (newvars != bddtrue)
{
++count;
newvars = bdd_high(newvars);
}
// If we discover one new variable, that means that all
// transitions we counted so far are actually double
// subtransitions. If we have two new variables, they where
// quadruple transitions, etc.
s_.transitions <<= count;
}
while (cond != bddfalse)
{
cond -= bdd_satoneset(cond, seen_, bddtrue);
++s_.transitions;
}
}
private:
@ -153,7 +153,7 @@ namespace spot
declare('p', &complete_);
declare('r', &run_time_);
declare('s', &states_);
declare('S', &scc_); // Historical. Deprecated. Use %c instead.
declare('S', &scc_); // Historical. Deprecated. Use %c instead.
declare('t', &trans_);
set_output(os);
if (format)
@ -162,23 +162,23 @@ namespace spot
std::ostream&
stat_printer::print(const const_twa_graph_ptr& aut,
formula f, double run_time)
formula f, double run_time)
{
form_ = f;
run_time_ = run_time;
if (has('t'))
{
twa_sub_statistics s = sub_stats_reachable(aut);
states_ = s.states;
edges_ = s.edges;
trans_ = s.transitions;
twa_sub_statistics s = sub_stats_reachable(aut);
states_ = s.states;
edges_ = s.edges;
trans_ = s.transitions;
}
else if (has('s') || has('e'))
{
twa_sub_statistics s = sub_stats_reachable(aut);
states_ = s.states;
edges_ = s.edges;
twa_sub_statistics s = sub_stats_reachable(aut);
states_ = s.states;
edges_ = s.edges;
}
if (has('a'))
@ -189,25 +189,25 @@ namespace spot
if (has('n'))
{
nondetstates_ = count_nondet_states(aut);
deterministic_ = (nondetstates_ == 0);
nondetstates_ = count_nondet_states(aut);
deterministic_ = (nondetstates_ == 0);
}
else if (has('d'))
{
// This is more efficient than calling count_nondet_state().
deterministic_ = is_deterministic(aut);
// This is more efficient than calling count_nondet_state().
deterministic_ = is_deterministic(aut);
}
if (has('p'))
{
complete_ = is_complete(aut);
complete_ = is_complete(aut);
}
if (has('g'))
{
std::ostringstream os;
os << aut->get_acceptance();
gen_acc_ = os.str();
std::ostringstream os;
os << aut->get_acceptance();
gen_acc_ = os.str();
}
return format(format_);

View file

@ -85,7 +85,7 @@ namespace spot
/// to be output, and so is \a run_time).
std::ostream&
print(const const_twa_graph_ptr& aut, formula f = nullptr,
double run_time = -1.);
double run_time = -1.);
private:
const char* format_;

View file

@ -33,7 +33,7 @@ namespace spot
// Create an scc_info if the user did not give one to us.
bool need_si = !si;
if (need_si)
si = new scc_info(aut);
si = new scc_info(aut);
si->determine_unknown_acceptance();
bool is_inweak = true;
@ -41,58 +41,58 @@ namespace spot
bool is_term = true;
unsigned n = si->scc_count();
for (unsigned i = 0; i < n; ++i)
{
if (si->is_trivial(i))
continue;
bool first = true;
acc_cond::mark_t m = 0U;
if (is_weak)
for (auto src: si->states_of(i))
for (auto& t: aut->out(src))
if (si->scc_of(t.dst) == i)
{
if (first)
{
first = false;
m = t.acc;
}
else if (m != t.acc)
{
is_weak = false;
if (!inweak)
goto exit;
}
}
if (!is_weak && si->is_accepting_scc(i))
{
assert(inweak);
if (scc_has_rejecting_cycle(*si, i))
{
is_inweak = false;
break;
}
}
if (terminal && si->is_accepting_scc(i) && !is_complete_scc(*si, i))
{
is_term = false;
if (!set)
break;
}
}
{
if (si->is_trivial(i))
continue;
bool first = true;
acc_cond::mark_t m = 0U;
if (is_weak)
for (auto src: si->states_of(i))
for (auto& t: aut->out(src))
if (si->scc_of(t.dst) == i)
{
if (first)
{
first = false;
m = t.acc;
}
else if (m != t.acc)
{
is_weak = false;
if (!inweak)
goto exit;
}
}
if (!is_weak && si->is_accepting_scc(i))
{
assert(inweak);
if (scc_has_rejecting_cycle(*si, i))
{
is_inweak = false;
break;
}
}
if (terminal && si->is_accepting_scc(i) && !is_complete_scc(*si, i))
{
is_term = false;
if (!set)
break;
}
}
exit:
if (need_si)
delete si;
delete si;
if (set)
{
if (terminal && is_term && is_weak)
aut->prop_terminal(true);
if (is_weak)
aut->prop_weak(true);
if (is_inweak)
aut->prop_inherently_weak(true);
}
{
if (terminal && is_term && is_weak)
aut->prop_terminal(true);
if (is_weak)
aut->prop_weak(true);
if (is_inweak)
aut->prop_inherently_weak(true);
}
if (inweak)
return is_inweak;
return is_inweak;
return is_weak && is_term;
}
}
@ -113,7 +113,7 @@ namespace spot
if (v.is_known())
return v.is_true();
return is_type_automaton<false>(std::const_pointer_cast<twa_graph>(aut),
si);
si);
}
bool
@ -135,11 +135,11 @@ namespace spot
{
if (!(aut->acc().is_buchi() || aut->acc().is_all()))
throw std::runtime_error
("is_safety_mwdba() should be called on a Buchi automaton");
("is_safety_mwdba() should be called on a Buchi automaton");
for (auto& t: aut->edges())
if (!aut->acc().accepting(t.acc))
return false;
return false;
return true;
}
@ -149,7 +149,7 @@ namespace spot
{
if (keep_opt == nullptr || *keep_opt == 0)
throw std::runtime_error
(std::string("option for decompose_strength() should not be empty"));
(std::string("option for decompose_strength() should not be empty"));
enum strength {
Ignore = 0,
@ -157,30 +157,30 @@ namespace spot
WeakStrict = 2,
Weak = Terminal | WeakStrict,
Strong = 4,
Needed = 8, // Needed SCCs are those that lead to
// the SCCs we want to keep.
Needed = 8, // Needed SCCs are those that lead to
// the SCCs we want to keep.
};
unsigned char keep = Ignore;
while (auto c = *keep_opt++)
switch (c)
{
case 's':
keep |= Strong;
break;
case 't':
keep |= Terminal;
break;
case 'w':
keep |= WeakStrict;
break;
default:
throw std::runtime_error
(std::string("unknown option for decompose_strength(): ") + c);
}
{
case 's':
keep |= Strong;
break;
case 't':
keep |= Terminal;
break;
case 'w':
keep |= WeakStrict;
break;
default:
throw std::runtime_error
(std::string("unknown option for decompose_strength(): ") + c);
}
auto p = aut->acc().unsat_mark();
bool all_accepting = !p.first;
acc_cond::mark_t wacc = 0U; // Acceptance for weak SCCs
acc_cond::mark_t wacc = 0U; // Acceptance for weak SCCs
acc_cond::mark_t uacc = p.second; // Acceptance for "needed" SCCs, that
// we only want to traverse.
@ -189,9 +189,9 @@ namespace spot
// case syntactically) and not output any strong part.
if (all_accepting)
{
keep &= ~Strong;
if (keep == Ignore)
return nullptr;
keep &= ~Strong;
if (keep == Ignore)
return nullptr;
}
scc_info si(aut);
@ -204,33 +204,33 @@ namespace spot
for (unsigned i = 0; i < n; ++i) // SCC are topologically ordered
{
if (si.is_accepting_scc(i))
{
if (all_accepting | is_inherently_weak_scc(si, i))
{
if (keep & Weak)
{
if ((keep & Weak) == Weak)
want[i] = Weak;
else
want[i] = keep &
(is_complete_scc(si, i) ? Terminal : WeakStrict);
}
}
else
{
want[i] = keep & Strong;
strong_seen = true;
}
nonempty |= want[i];
}
// An SCC is needed if one of its successor is.
for (unsigned j: si.succ(i))
if (want[j])
{
want[i] |= Needed;
break;
}
if (si.is_accepting_scc(i))
{
if (all_accepting | is_inherently_weak_scc(si, i))
{
if (keep & Weak)
{
if ((keep & Weak) == Weak)
want[i] = Weak;
else
want[i] = keep &
(is_complete_scc(si, i) ? Terminal : WeakStrict);
}
}
else
{
want[i] = keep & Strong;
strong_seen = true;
}
nonempty |= want[i];
}
// An SCC is needed if one of its successor is.
for (unsigned j: si.succ(i))
if (want[j])
{
want[i] |= Needed;
break;
}
}
if (!nonempty)
@ -248,35 +248,35 @@ namespace spot
auto fun = [&si, &want, uacc, wacc, keep]
(unsigned src, bdd& cond, acc_cond::mark_t& acc, unsigned dst)
{
if (want[si.scc_of(dst)] == Ignore)
{
cond = bddfalse;
return;
}
if (want[si.scc_of(src)] == Needed)
{
acc = uacc;
return;
}
if (keep & Strong)
return;
acc = wacc;
if (want[si.scc_of(dst)] == Ignore)
{
cond = bddfalse;
return;
}
if (want[si.scc_of(src)] == Needed)
{
acc = uacc;
return;
}
if (keep & Strong)
return;
acc = wacc;
};
transform_accessible(aut, res, fun);
if (!(keep & Strong))
{
res->prop_weak(true);
if (!(keep & WeakStrict))
{
assert(keep & Terminal);
res->prop_terminal(true);
}
res->prop_weak(true);
if (!(keep & WeakStrict))
{
assert(keep & Terminal);
res->prop_terminal(true);
}
}
else
{
res->prop_weak(!strong_seen);
res->prop_weak(!strong_seen);
}
return res;
}

View file

@ -59,7 +59,7 @@ namespace spot
/// will be built otherwise).
SPOT_API bool
is_inherently_weak_automaton(const const_twa_graph_ptr& aut,
scc_info* sm = nullptr);
scc_info* sm = nullptr);
/// \brief Whether a minimized WDBA represents a safety property.
///
@ -105,19 +105,19 @@ namespace spot
/** \verbatim
@inproceedings{renault.13.tacas,
author = {Etienne Renault and Alexandre Duret-Lutz and Fabrice
Kordon and Denis Poitrenaud},
Kordon and Denis Poitrenaud},
title = {Strength-Based Decomposition of the Property {B\"u}chi
Automaton for Faster Model Checking},
Automaton for Faster Model Checking},
booktitle = {Proceedings of the 19th International Conference on Tools
and Algorithms for the Construction and Analysis of Systems
(TACAS'13)},
and Algorithms for the Construction and Analysis of Systems
(TACAS'13)},
editor = {Nir Piterman and Scott A. Smolka},
year = {2013},
month = mar,
pages = {580--593},
publisher = {Springer},
series = {Lecture Notes in Computer Science},
volume = {7795},
year = {2013},
month = mar,
pages = {580--593},
publisher = {Springer},
series = {Lecture Notes in Computer Science},
volume = {7795},
doi = {10.1007/978-3-642-36742-7_42}
}
\endverbatim */

View file

@ -27,7 +27,7 @@ namespace spot
unsigned n = a->num_states();
for (unsigned s = 0; s < n; ++s)
for (auto& t: a->out(s))
t.acc = 0U;
t.acc = 0U;
a->set_generalized_buchi(0);
a->release_named_properties();
}

View file

@ -98,7 +98,7 @@ namespace spot
{
public:
twasl_succ_iterator(twa_succ_iterator* it, const state_tgbasl* state,
bdd_dict_ptr d, bdd atomic_propositions)
bdd_dict_ptr d, bdd atomic_propositions)
: it_(it), state_(state), aps_(atomic_propositions), d_(d)
{
}
@ -207,33 +207,33 @@ namespace spot
{
public:
tgbasl(const const_twa_ptr& a, bdd atomic_propositions)
: twa(a->get_dict()), a_(a), aps_(atomic_propositions)
: twa(a->get_dict()), a_(a), aps_(atomic_propositions)
{
get_dict()->register_all_propositions_of(&a_, this);
assert(num_sets() == 0);
set_generalized_buchi(a_->num_sets());
get_dict()->register_all_propositions_of(&a_, this);
assert(num_sets() == 0);
set_generalized_buchi(a_->num_sets());
}
virtual const state* get_init_state() const override
{
return new state_tgbasl(a_->get_init_state(), bddfalse);
return new state_tgbasl(a_->get_init_state(), bddfalse);
}
virtual twa_succ_iterator* succ_iter(const state* state) const override
{
const state_tgbasl* s = down_cast<const state_tgbasl*>(state);
assert(s);
return new twasl_succ_iterator(a_->succ_iter(s->real_state()), s,
a_->get_dict(), aps_);
const state_tgbasl* s = down_cast<const state_tgbasl*>(state);
assert(s);
return new twasl_succ_iterator(a_->succ_iter(s->real_state()), s,
a_->get_dict(), aps_);
}
virtual std::string format_state(const state* state) const override
{
const state_tgbasl* s = down_cast<const state_tgbasl*>(state);
assert(s);
return (a_->format_state(s->real_state())
+ ", "
+ bdd_format_formula(a_->get_dict(), s->cond()));
const state_tgbasl* s = down_cast<const state_tgbasl*>(state);
assert(s);
return (a_->format_state(s->real_state())
+ ", "
+ bdd_format_formula(a_->get_dict(), s->cond()));
}
private:
@ -257,13 +257,13 @@ namespace spot
size_t
operator()(const stutter_state& s) const
{
return wang32_hash(s.first) ^ wang32_hash(s.second.id());
return wang32_hash(s.first) ^ wang32_hash(s.second.id());
}
};
// Associate the stutter state to its number.
typedef std::unordered_map<stutter_state, unsigned,
stutter_state_hash> ss2num_map;
stutter_state_hash> ss2num_map;
// Queue of state to be processed.
typedef std::deque<stutter_state> queue_t;
@ -303,43 +303,43 @@ namespace spot
while (!todo.empty())
{
s = todo.front();
todo.pop_front();
unsigned src = ss2num[s];
s = todo.front();
todo.pop_front();
unsigned src = ss2num[s];
bool self_loop_needed = true;
bool self_loop_needed = true;
for (auto& t : a->out(s.first))
{
bdd all = t.cond;
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, atomic_propositions, bddtrue);
all -= one;
for (auto& t : a->out(s.first))
{
bdd all = t.cond;
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, atomic_propositions, bddtrue);
all -= one;
stutter_state d(t.dst, one);
stutter_state d(t.dst, one);
auto r = ss2num.emplace(d, ss2num.size());
unsigned dest = r.first->second;
auto r = ss2num.emplace(d, ss2num.size());
unsigned dest = r.first->second;
if (r.second)
{
todo.push_back(d);
unsigned u = res->new_state();
assert(u == dest);
(void)u;
}
if (r.second)
{
todo.push_back(d);
unsigned u = res->new_state();
assert(u == dest);
(void)u;
}
// Create the edge.
res->new_edge(src, dest, one, t.acc);
// Create the edge.
res->new_edge(src, dest, one, t.acc);
if (src == dest)
self_loop_needed = false;
}
}
if (src == dest)
self_loop_needed = false;
}
}
if (self_loop_needed && s.second != bddfalse)
res->new_edge(src, src, s.second, 0U);
if (self_loop_needed && s.second != bddfalse)
res->new_edge(src, src, s.second, 0U);
}
res->merge_edges();
return res;
@ -358,53 +358,53 @@ namespace spot
// state.
for (auto& t: a->edges())
if (t.src == t.dst)
selfloops[t.src] |= t.cond;
selfloops[t.src] |= t.cond;
for (unsigned t = 1; t <= num_edges; ++t)
{
auto& td = a->edge_storage(t);
if (a->is_dead_edge(td))
continue;
auto& td = a->edge_storage(t);
if (a->is_dead_edge(td))
continue;
unsigned src = td.src;
unsigned dst = td.dst;
if (src != dst)
{
bdd all = td.cond;
// If there is a self-loop with the whole condition on
// either end of the edge, do not bother with it.
if (bdd_implies(all, selfloops[src])
|| bdd_implies(all, selfloops[dst]))
continue;
// Do not use td in the loop because the new_edge()
// might invalidate it.
auto acc = td.acc;
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, atomic_propositions, bddtrue);
all -= one;
// Skip if there is a loop for this particular letter.
if (bdd_implies(one, selfloops[src])
|| bdd_implies(one, selfloops[dst]))
continue;
auto p = newstates.emplace(std::make_pair(dst, one.id()), 0);
if (p.second)
p.first->second = a->new_state();
unsigned tmp = p.first->second; // intermediate state
unsigned i = a->new_edge(src, tmp, one, acc);
assert(i > num_edges);
i = a->new_edge(tmp, tmp, one, 0U);
assert(i > num_edges);
// No acceptance here to preserve the state-based property.
i = a->new_edge(tmp, dst, one, 0U);
assert(i > num_edges);
(void)i;
}
}
unsigned src = td.src;
unsigned dst = td.dst;
if (src != dst)
{
bdd all = td.cond;
// If there is a self-loop with the whole condition on
// either end of the edge, do not bother with it.
if (bdd_implies(all, selfloops[src])
|| bdd_implies(all, selfloops[dst]))
continue;
// Do not use td in the loop because the new_edge()
// might invalidate it.
auto acc = td.acc;
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, atomic_propositions, bddtrue);
all -= one;
// Skip if there is a loop for this particular letter.
if (bdd_implies(one, selfloops[src])
|| bdd_implies(one, selfloops[dst]))
continue;
auto p = newstates.emplace(std::make_pair(dst, one.id()), 0);
if (p.second)
p.first->second = a->new_state();
unsigned tmp = p.first->second; // intermediate state
unsigned i = a->new_edge(src, tmp, one, acc);
assert(i > num_edges);
i = a->new_edge(tmp, tmp, one, 0U);
assert(i > num_edges);
// No acceptance here to preserve the state-based property.
i = a->new_edge(tmp, dst, one, 0U);
assert(i > num_edges);
(void)i;
}
}
}
if (num_states != a->num_states())
a->prop_keep({true, // state_based
false, // inherently_weak
false, // deterministic
a->prop_keep({true, // state_based
false, // inherently_weak
false, // deterministic
false, // stutter inv.
});
a->merge_edges();
@ -415,16 +415,16 @@ namespace spot
sl2(const const_twa_graph_ptr& a, bdd atomic_propositions)
{
return sl2(make_twa_graph(a, twa::prop_set::all()),
atomic_propositions);
atomic_propositions);
}
twa_graph_ptr
closure(twa_graph_ptr&& a)
{
a->prop_keep({false, // state_based
false, // inherently_weak
false, // deterministic
a->prop_keep({false, // state_based
false, // inherently_weak
false, // deterministic
false, // stutter inv.
});
@ -434,26 +434,26 @@ namespace spot
for (unsigned state = 0; state < n; ++state)
{
auto trans = a->out(state);
auto trans = a->out(state);
for (auto it = trans.begin(); it != trans.end(); ++it)
{
todo.push_back(it.trans());
dst2trans[it->dst].push_back(it.trans());
}
for (auto it = trans.begin(); it != trans.end(); ++it)
{
todo.push_back(it.trans());
dst2trans[it->dst].push_back(it.trans());
}
while (!todo.empty())
{
auto t1 = a->edge_storage(todo.back());
todo.pop_back();
while (!todo.empty())
{
auto t1 = a->edge_storage(todo.back());
todo.pop_back();
for (auto& t2 : a->out(t1.dst))
{
bdd cond = t1.cond & t2.cond;
if (cond != bddfalse)
{
for (auto& t2 : a->out(t1.dst))
{
bdd cond = t1.cond & t2.cond;
if (cond != bddfalse)
{
bool need_new_trans = true;
acc_cond::mark_t acc = t1.acc | t2.acc;
acc_cond::mark_t acc = t1.acc | t2.acc;
for (auto& t: dst2trans[t2.dst])
{
auto& ts = a->edge_storage(t);
@ -467,34 +467,34 @@ namespace spot
todo.push_back(t);
}
need_new_trans = false;
break;
break;
}
else if (cond == ts.cond)
{
acc |= ts.acc;
if (ts.acc != acc)
{
ts.acc = acc;
if (std::find(todo.begin(), todo.end(), t)
== todo.end())
todo.push_back(t);
}
else if (cond == ts.cond)
{
acc |= ts.acc;
if (ts.acc != acc)
{
ts.acc = acc;
if (std::find(todo.begin(), todo.end(), t)
== todo.end())
todo.push_back(t);
}
need_new_trans = false;
break;
}
break;
}
}
if (need_new_trans)
{
// Load t2.dst first, because t2 can be
// invalidated by new_edge().
auto dst = t2.dst;
// Load t2.dst first, because t2 can be
// invalidated by new_edge().
auto dst = t2.dst;
auto i = a->new_edge(state, dst, cond, acc);
dst2trans[dst].push_back(i);
todo.push_back(i);
}
}
}
}
}
}
}
for (auto& it: dst2trans)
it.clear();
}
@ -514,16 +514,16 @@ namespace spot
static const char* stutter_check = getenv("SPOT_STUTTER_CHECK");
if (stutter_check)
{
char* endptr;
long res = strtol(stutter_check, &endptr, 10);
if (*endptr || res < 0 || res > 9)
throw
std::runtime_error("invalid value for SPOT_STUTTER_CHECK.");
return res;
char* endptr;
long res = strtol(stutter_check, &endptr, 10);
if (*endptr || res < 0 || res > 9)
throw
std::runtime_error("invalid value for SPOT_STUTTER_CHECK.");
return res;
}
else
{
return 8; // The best variant, according to our benchmarks.
return 8; // The best variant, according to our benchmarks.
}
}
@ -538,23 +538,23 @@ namespace spot
if (algo == 0 || algo == 9)
// Etessami's check via syntactic transformation.
{
if (!f.is_ltl_formula())
throw std::runtime_error("Cannot use the syntactic "
"stutter-invariance check "
"for non-LTL formulas");
formula g = remove_x(f);
bool res;
if (algo == 0) // Equivalence check
{
tl_simplifier ls;
res = ls.are_equivalent(f, g);
}
else
{
formula h = formula::Xor(f, g);
res = ltl_to_tgba_fm(h, make_bdd_dict())->is_empty();
}
return res;
if (!f.is_ltl_formula())
throw std::runtime_error("Cannot use the syntactic "
"stutter-invariance check "
"for non-LTL formulas");
formula g = remove_x(f);
bool res;
if (algo == 0) // Equivalence check
{
tl_simplifier ls;
res = ls.are_equivalent(f, g);
}
else
{
formula h = formula::Xor(f, g);
res = ltl_to_tgba_fm(h, make_bdd_dict())->is_empty();
}
return res;
}
// Prepare for an automata-based check.
@ -575,33 +575,33 @@ namespace spot
switch (algo)
{
case 1: // sl(aut_f) x sl(aut_nf)
return product(sl(std::move(aut_f), aps),
sl(std::move(aut_nf), aps))->is_empty();
return product(sl(std::move(aut_f), aps),
sl(std::move(aut_nf), aps))->is_empty();
case 2: // sl(cl(aut_f)) x aut_nf
return product(sl(closure(std::move(aut_f)), aps),
std::move(aut_nf))->is_empty();
return product(sl(closure(std::move(aut_f)), aps),
std::move(aut_nf))->is_empty();
case 3: // (cl(sl(aut_f)) x aut_nf
return product(closure(sl(std::move(aut_f), aps)),
std::move(aut_nf))->is_empty();
return product(closure(sl(std::move(aut_f), aps)),
std::move(aut_nf))->is_empty();
case 4: // sl2(aut_f) x sl2(aut_nf)
return product(sl2(std::move(aut_f), aps),
sl2(std::move(aut_nf), aps))->is_empty();
return product(sl2(std::move(aut_f), aps),
sl2(std::move(aut_nf), aps))->is_empty();
case 5: // sl2(cl(aut_f)) x aut_nf
return product(sl2(closure(std::move(aut_f)), aps),
std::move(aut_nf))->is_empty();
return product(sl2(closure(std::move(aut_f)), aps),
std::move(aut_nf))->is_empty();
case 6: // (cl(sl2(aut_f)) x aut_nf
return product(closure(sl2(std::move(aut_f), aps)),
std::move(aut_nf))->is_empty();
return product(closure(sl2(std::move(aut_f), aps)),
std::move(aut_nf))->is_empty();
case 7: // on-the-fly sl(aut_f) x sl(aut_nf)
return otf_product(make_tgbasl(aut_f, aps),
make_tgbasl(aut_nf, aps))->is_empty();
return otf_product(make_tgbasl(aut_f, aps),
make_tgbasl(aut_nf, aps))->is_empty();
case 8: // cl(aut_f) x cl(aut_nf)
return product(closure(std::move(aut_f)),
closure(std::move(aut_nf)))->is_empty();
return product(closure(std::move(aut_f)),
closure(std::move(aut_nf)))->is_empty();
default:
throw std::runtime_error("invalid algorithm number for "
"is_stutter_invariant()");
SPOT_UNREACHABLE();
throw std::runtime_error("invalid algorithm number for "
"is_stutter_invariant()");
SPOT_UNREACHABLE();
}
}
@ -615,20 +615,20 @@ namespace spot
twa_graph_ptr neg = nullptr;
if (f)
{
neg = translator(aut->get_dict()).run(formula::Not(f));
neg = translator(aut->get_dict()).run(formula::Not(f));
}
else
{
// If the automaton is deterministic, we
// know how to complement it.
aut->prop_deterministic(is_deterministic(aut));
if (!aut->prop_deterministic())
return trival::maybe();
neg = remove_fin(dtwa_complement(aut));
// If the automaton is deterministic, we
// know how to complement it.
aut->prop_deterministic(is_deterministic(aut));
if (!aut->prop_deterministic())
return trival::maybe();
neg = remove_fin(dtwa_complement(aut));
}
is_stut = is_stutter_invariant(make_twa_graph(aut, twa::prop_set::all()),
std::move(neg), aut->ap_vars());
std::move(neg), aut->ap_vars());
aut->prop_stutter_invariant(is_stut);
return is_stut;
}

View file

@ -55,8 +55,8 @@ namespace spot
SPOT_API bool
is_stutter_invariant(twa_graph_ptr&& aut_f,
twa_graph_ptr&& aut_nf, bdd aps,
int algo = 0);
twa_graph_ptr&& aut_nf, bdd aps,
int algo = 0);
/// \brief Check whether \a aut is stutter-invariant
///
@ -68,5 +68,5 @@ namespace spot
/// the result will be returned as trival::maybe().
SPOT_API trival
check_stutter_invariance(const twa_graph_ptr& aut,
formula f = nullptr);
formula f = nullptr);
}

View file

@ -91,8 +91,8 @@ namespace spot
inc_states();
h.add_new_state(s0, BLUE);
push(st_blue, s0, bddfalse, 0U);
auto t = std::static_pointer_cast<tau03_search>
(this->emptiness_check::shared_from_this());
auto t = std::static_pointer_cast<tau03_search>
(this->emptiness_check::shared_from_this());
if (dfs_blue())
return std::make_shared<ndfs_result<tau03_search<heap>, heap>>(t);
return nullptr;
@ -123,7 +123,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, acc_cond::mark_t acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
twa_succ_iterator* i = a_->succ_iter(s);
@ -187,7 +187,7 @@ namespace spot
<< std::endl;
typename heap::color_ref c = h.get_color_ref(f.s);
assert(!c.is_white());
for (auto i: a_->succ(f.s))
for (auto i: a_->succ(f.s))
{
inc_transitions();
const state *s_prime = i->dst();
@ -198,7 +198,7 @@ namespace spot
auto acc = i->acc();
typename heap::color_ref c_prime = h.get_color_ref(s_prime);
assert(!c_prime.is_white());
auto acu = acc | c.get_acc();
auto acu = acc | c.get_acc();
if ((c_prime.get_acc() & acu) != acu)
{
trace << " a propagation is needed, go down"
@ -250,7 +250,7 @@ namespace spot
trace << " It is white, pop it" << std::endl;
s_prime->destroy();
}
else if ((c_prime.get_acc() & acu) != acu)
else if ((c_prime.get_acc() & acu) != acu)
{
trace << " It is blue and propagation "
<< "is needed, go down" << std::endl;
@ -302,7 +302,7 @@ namespace spot
void cumulate_acc(acc_cond::mark_t a)
{
assert(!is_white());
*acc |= a;
*acc |= a;
}
bool is_white() const
{
@ -310,7 +310,7 @@ namespace spot
}
private:
color *p;
acc_cond::mark_t* acc;
acc_cond::mark_t* acc;
};
explicit_tau03_search_heap(size_t)
@ -346,8 +346,8 @@ namespace spot
{
assert(h.find(s) == h.end());
h.emplace(std::piecewise_construct,
std::forward_as_tuple(s),
std::forward_as_tuple(c, 0U));
std::forward_as_tuple(s),
std::forward_as_tuple(c, 0U));
}
void pop_notify(const state*) const

View file

@ -69,10 +69,10 @@ namespace spot
: emptiness_check(a, o),
current_weight(a->acc()),
h(size),
use_condition_stack(o.get("condstack")),
use_ordering(use_condition_stack && o.get("ordering")),
use_weights(o.get("weights", 1)),
use_red_weights(use_weights && o.get("redweights", 1))
use_condition_stack(o.get("condstack")),
use_ordering(use_condition_stack && o.get("ordering")),
use_weights(o.get("weights", 1)),
use_red_weights(use_weights && o.get("redweights", 1))
{
}
@ -106,8 +106,8 @@ namespace spot
inc_states();
h.add_new_state(s0, CYAN, current_weight);
push(st_blue, s0, bddfalse, 0U);
auto t = std::static_pointer_cast<tau03_opt_search>
(this->emptiness_check::shared_from_this());
auto t = std::static_pointer_cast<tau03_opt_search>
(this->emptiness_check::shared_from_this());
if (dfs_blue())
return std::make_shared<ndfs_result<tau03_opt_search<heap>, heap>>(t);
return nullptr;
@ -138,7 +138,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, acc_cond::mark_t acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
twa_succ_iterator* i = a_->succ_iter(s);
@ -155,14 +155,14 @@ namespace spot
acc_cond::mark_t project_acc(acc_cond::mark_t acc) const
{
if (!use_ordering)
return acc;
// FIXME: This should be improved.
std::vector<unsigned> res;
unsigned max = a_->num_sets();
for (unsigned n = 0; n < max && acc.has(n); ++n)
res.push_back(n);
return acc_cond::mark_t(res.begin(), res.end());
if (!use_ordering)
return acc;
// FIXME: This should be improved.
std::vector<unsigned> res;
unsigned max = a_->num_sets();
for (unsigned n = 0; n < max && acc.has(n); ++n)
res.push_back(n);
return acc_cond::mark_t(res.begin(), res.end());
}
/// \brief weight of the state on top of the blue stack.
@ -208,8 +208,8 @@ namespace spot
if (c_prime.is_white())
{
trace << " It is white, go down" << std::endl;
if (use_weights)
current_weight.add(acc);
if (use_weights)
current_weight.add(acc);
inc_states();
h.add_new_state(s_prime, CYAN, current_weight);
push(st_blue, s_prime, label, acc);
@ -219,9 +219,9 @@ namespace spot
typename heap::color_ref c = h.get_color_ref(f.s);
assert(!c.is_white());
if (c_prime.get_color() == CYAN
&& a_->acc().accepting
(current_weight.diff(a_->acc(), c_prime. get_weight())
| c.get_acc() | acc | c_prime.get_acc()))
&& a_->acc().accepting
(current_weight.diff(a_->acc(), c_prime. get_weight())
| c.get_acc() | acc | c_prime.get_acc()))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
@ -259,8 +259,8 @@ namespace spot
trace << " All the successors have been visited" << std::endl;
stack_item f_dest(f);
pop(st_blue);
if (use_weights)
current_weight.sub(f_dest.acc);
if (use_weights)
current_weight.sub(f_dest.acc);
typename heap::color_ref c_prime = h.get_color_ref(f_dest.s);
assert(!c_prime.is_white());
c_prime.set_color(BLUE);
@ -303,11 +303,11 @@ namespace spot
{
assert(!st_red.empty());
// These are useful only when USE_CONDITION_STACK is set.
typedef std::pair<acc_cond::mark_t, unsigned> cond_level;
std::stack<cond_level> condition_stack;
unsigned depth = 1;
condition_stack.emplace(0U, 0);
// These are useful only when USE_CONDITION_STACK is set.
typedef std::pair<acc_cond::mark_t, unsigned> cond_level;
std::stack<cond_level> condition_stack;
unsigned depth = 1;
condition_stack.emplace(0U, 0);
while (!st_red.empty())
{
@ -330,49 +330,49 @@ namespace spot
s_prime->destroy();
continue;
}
else if (c_prime.get_color() == CYAN &&
a_->acc().accepting
(acc | acu | c_prime.get_acc() |
(use_red_weights ?
current_weight.diff(a_->acc(),
c_prime.
get_weight())
: acc_cond::mark_t(0U))))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
c_prime.cumulate_acc(a_->acc().all_sets());
push(st_red, s_prime, label, acc);
return true;
}
acc_cond::mark_t acp;
if (use_ordering)
acp = project_acc(acu | acc | c_prime.get_acc());
else if (use_condition_stack)
acp = acu | acc;
else
acp = acu;
if ((c_prime.get_acc() & acp) != acp)
{
trace << " It is cyan or blue and propagation "
<< "is needed, go down"
<< std::endl;
c_prime.cumulate_acc(acp);
push(st_red, s_prime, label, acc);
if (use_condition_stack)
{
auto old = acu;
acu |= acc;
condition_stack.emplace(acu - old, depth);
}
++depth;
}
else
{
trace << " It is cyan or blue and no propagation "
<< "is needed , pop it" << std::endl;
h.pop_notify(s_prime);
}
else if (c_prime.get_color() == CYAN &&
a_->acc().accepting
(acc | acu | c_prime.get_acc() |
(use_red_weights ?
current_weight.diff(a_->acc(),
c_prime.
get_weight())
: acc_cond::mark_t(0U))))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
c_prime.cumulate_acc(a_->acc().all_sets());
push(st_red, s_prime, label, acc);
return true;
}
acc_cond::mark_t acp;
if (use_ordering)
acp = project_acc(acu | acc | c_prime.get_acc());
else if (use_condition_stack)
acp = acu | acc;
else
acp = acu;
if ((c_prime.get_acc() & acp) != acp)
{
trace << " It is cyan or blue and propagation "
<< "is needed, go down"
<< std::endl;
c_prime.cumulate_acc(acp);
push(st_red, s_prime, label, acc);
if (use_condition_stack)
{
auto old = acu;
acu |= acc;
condition_stack.emplace(acu - old, depth);
}
++depth;
}
else
{
trace << " It is cyan or blue and no propagation "
<< "is needed , pop it" << std::endl;
h.pop_notify(s_prime);
}
}
else // Backtrack
{
@ -380,16 +380,16 @@ namespace spot
<< std::endl;
h.pop_notify(f.s);
pop(st_red);
--depth;
if (condition_stack.top().second == depth)
{
acu -= condition_stack.top().first;
condition_stack.pop();
}
--depth;
if (condition_stack.top().second == depth)
{
acu -= condition_stack.top().first;
condition_stack.pop();
}
}
}
assert(depth == 0);
assert(condition_stack.empty());
assert(depth == 0);
assert(condition_stack.empty());
return false;
}
@ -404,7 +404,7 @@ namespace spot
{
public:
color_ref(hash_type* h, hcyan_type* hc, const state* s,
const weight* w, acc_cond::mark_t* a)
const weight* w, acc_cond::mark_t* a)
: is_cyan(true), w(w), ph(h), phc(hc), ps(s), acc(a)
{
}
@ -442,7 +442,7 @@ namespace spot
*pc=c;
}
}
acc_cond::mark_t get_acc() const
acc_cond::mark_t get_acc() const
{
assert(!is_white());
return *acc;
@ -463,8 +463,8 @@ namespace spot
hcyan_type* phc; // point to the hash table hcyan
const state* ps; // point to the state in hcyan
color *pc; // point to the color of a state stored in main hash table
acc_cond::mark_t* acc; // point to the acc set of a state stored
// in main hash table or hcyan
acc_cond::mark_t* acc; // point to the acc set of a state stored
// in main hash table or hcyan
};
explicit_tau03_opt_search_heap(size_t)
@ -513,7 +513,7 @@ namespace spot
}
// cyan state
return color_ref(&h, &hc, ic->first,
&ic->second.first, &ic->second.second);
&ic->second.first, &ic->second.second);
}
void add_new_state(const state* s, color c, const weight& w)
@ -522,8 +522,8 @@ namespace spot
assert(c == CYAN);
(void)c;
hc.emplace(std::piecewise_construct,
std::forward_as_tuple(s),
std::forward_as_tuple(w, 0U));
std::forward_as_tuple(s),
std::forward_as_tuple(w, 0U));
}
void pop_notify(const state*) const
@ -562,7 +562,7 @@ namespace spot
{
return
std::make_shared<tau03_opt_search<explicit_tau03_opt_search_heap>>(a,
0, o);
0, o);
}
}

View file

@ -98,7 +98,7 @@ namespace spot
///
SPOT_API emptiness_check_ptr
explicit_tau03_opt_search(const const_twa_ptr& a,
option_map o = option_map());
option_map o = option_map());
/// @}
}

View file

@ -35,7 +35,7 @@ namespace spot
unsigned s;
st2gba_state(unsigned st, acc_cond::mark_t bv = -1U):
pend(bv), s(st)
pend(bv), s(st)
{
}
};
@ -45,8 +45,8 @@ namespace spot
size_t
operator()(const st2gba_state& s) const
{
std::hash<acc_cond::mark_t> h;
return s.s ^ h(s.pend);
std::hash<acc_cond::mark_t> h;
return s.s ^ h(s.pend);
}
};
@ -56,9 +56,9 @@ namespace spot
operator()(const st2gba_state& left,
const st2gba_state& right) const
{
if (left.s != right.s)
return false;
return left.pend == right.pend;
if (left.s != right.s)
return false;
return left.pend == right.pend;
}
};
@ -71,21 +71,21 @@ namespace spot
auto pos = &code.back();
auto end = &code.front();
if (pos->op == acc_cond::acc_op::And)
--pos;
--pos;
while (pos >= end)
{
auto term_end = pos - 1 - pos->size;
if (pos->op == acc_cond::acc_op::Or)
--pos;
acc_cond::mark_t m = 0U;
while (pos > term_end)
{
assert(pos->op == acc_cond::acc_op::Inf);
m |= pos[-1].mark;
pos -= 2;
}
res.push_back(m);
}
{
auto term_end = pos - 1 - pos->size;
if (pos->op == acc_cond::acc_op::Or)
--pos;
acc_cond::mark_t m = 0U;
while (pos > term_end)
{
assert(pos->op == acc_cond::acc_op::Inf);
m |= pos[-1].mark;
pos -= 2;
}
res.push_back(m);
}
return res;
}
}
@ -119,7 +119,7 @@ namespace spot
int p = in->acc().is_streett();
if (p <= 0)
throw std::runtime_error("streett_to_generalized_buchi() should only be"
" called on automata with Streett acceptance");
" called on automata with Streett acceptance");
// In Streett acceptance, inf sets are odd, while fin sets are
// even.
@ -136,12 +136,12 @@ namespace spot
sccfi.reserve(nscc);
for (unsigned s = 0; s < nscc; ++s)
{
auto acc = si.acc_sets_of(s); // {0,1,2,3,4,6,7,9}
auto acc_fin = acc & fin; // {0, 2, 4,6}
auto acc_inf = acc & inf; // { 1, 3, 7,9}
auto fin_wo_inf = acc_fin - (acc_inf >> 1U); // {4}
auto inf_wo_fin = acc_inf - (acc_fin << 1U); // {9}
sccfi.emplace_back(fin_wo_inf, inf_wo_fin, acc_fin == 0U);
auto acc = si.acc_sets_of(s); // {0,1,2,3,4,6,7,9}
auto acc_fin = acc & fin; // {0, 2, 4,6}
auto acc_inf = acc & inf; // { 1, 3, 7,9}
auto fin_wo_inf = acc_fin - (acc_inf >> 1U); // {4}
auto inf_wo_fin = acc_inf - (acc_fin << 1U); // {9}
sccfi.emplace_back(fin_wo_inf, inf_wo_fin, acc_fin == 0U);
}
auto out = make_twa_graph(in->get_dict());
@ -152,8 +152,8 @@ namespace spot
// Map st2gba pairs to the state numbers used in out.
typedef std::unordered_map<st2gba_state, unsigned,
st2gba_state_hash,
st2gba_state_equal> bs2num_map;
st2gba_state_hash,
st2gba_state_equal> bs2num_map;
bs2num_map bs2num;
// Queue of states to be processed.
@ -171,115 +171,115 @@ namespace spot
while (!todo.empty())
{
s = todo.front();
todo.pop_front();
unsigned src = bs2num[s];
s = todo.front();
todo.pop_front();
unsigned src = bs2num[s];
unsigned scc_src = si.scc_of(s.s);
bool maybe_acc_scc = !si.is_rejecting_scc(scc_src);
unsigned scc_src = si.scc_of(s.s);
bool maybe_acc_scc = !si.is_rejecting_scc(scc_src);
acc_cond::mark_t scc_fin_wo_inf;
acc_cond::mark_t scc_inf_wo_fin;
bool no_fin;
std::tie(scc_fin_wo_inf, scc_inf_wo_fin, no_fin) = sccfi[scc_src];
acc_cond::mark_t scc_fin_wo_inf;
acc_cond::mark_t scc_inf_wo_fin;
bool no_fin;
std::tie(scc_fin_wo_inf, scc_inf_wo_fin, no_fin) = sccfi[scc_src];
for (auto& t: in->out(s.s))
{
acc_cond::mark_t pend = s.pend;
acc_cond::mark_t acc = 0U;
for (auto& t: in->out(s.s))
{
acc_cond::mark_t pend = s.pend;
acc_cond::mark_t acc = 0U;
bool maybe_acc = maybe_acc_scc && (scc_src == si.scc_of(t.dst));
bool maybe_acc = maybe_acc_scc && (scc_src == si.scc_of(t.dst));
if (pend != orig_copy)
{
if (!maybe_acc)
continue;
// No point going to some place we will never leave
if (t.acc & scc_fin_wo_inf)
continue;
// For any Fin set we see, we want to see the
// corresponding Inf set.
pend |= (t.acc & fin) << 1U;
pend -= t.acc & inf;
// Label this transition with all non-pending
// inf sets. The strip will shift everything
// to the correct numbers in the targets.
acc = (inf - pend).strip(fin) & outall;
// Adjust the pending sets to what will be necessary
// required on the destination state.
if (sbacc)
{
auto a = in->state_acc_sets(t.dst);
if (a & scc_fin_wo_inf)
continue;
pend |= (a & fin) << 1U;
pend -= a & inf;
}
pend |= scc_inf_wo_fin;
}
else if (no_fin && maybe_acc)
{
assert(maybe_acc);
acc = outall;
}
if (pend != orig_copy)
{
if (!maybe_acc)
continue;
// No point going to some place we will never leave
if (t.acc & scc_fin_wo_inf)
continue;
// For any Fin set we see, we want to see the
// corresponding Inf set.
pend |= (t.acc & fin) << 1U;
pend -= t.acc & inf;
// Label this transition with all non-pending
// inf sets. The strip will shift everything
// to the correct numbers in the targets.
acc = (inf - pend).strip(fin) & outall;
// Adjust the pending sets to what will be necessary
// required on the destination state.
if (sbacc)
{
auto a = in->state_acc_sets(t.dst);
if (a & scc_fin_wo_inf)
continue;
pend |= (a & fin) << 1U;
pend -= a & inf;
}
pend |= scc_inf_wo_fin;
}
else if (no_fin && maybe_acc)
{
assert(maybe_acc);
acc = outall;
}
st2gba_state d(t.dst, pend);
// Have we already seen this destination?
unsigned dest;
auto dres = bs2num.emplace(d, 0);
if (!dres.second)
{
dest = dres.first->second;
}
else // No, this is a new state
{
dest = dres.first->second = out->new_state();
todo.push_back(d);
}
out->new_edge(src, dest, t.cond, acc);
st2gba_state d(t.dst, pend);
// Have we already seen this destination?
unsigned dest;
auto dres = bs2num.emplace(d, 0);
if (!dres.second)
{
dest = dres.first->second;
}
else // No, this is a new state
{
dest = dres.first->second = out->new_state();
todo.push_back(d);
}
out->new_edge(src, dest, t.cond, acc);
// Nondeterministically jump to level ∅. We need to do
// that only once per cycle. As an approximation, we
// only to that for transition where t.src >= t.dst as
// this has to occur at least once per cycle.
if (pend == orig_copy && (t.src >= t.dst) && maybe_acc && !no_fin)
{
acc_cond::mark_t pend = 0U;
if (sbacc)
{
auto a = in->state_acc_sets(t.dst);
if (a & scc_fin_wo_inf)
continue;
pend = (a & fin) << 1U;
pend -= a & inf;
}
st2gba_state d(t.dst, pend | scc_inf_wo_fin);
// Have we already seen this destination?
unsigned dest;
auto dres = bs2num.emplace(d, 0);
if (!dres.second)
{
dest = dres.first->second;
}
else // No, this is a new state
{
dest = dres.first->second = out->new_state();
todo.push_back(d);
}
out->new_edge(src, dest, t.cond);
}
}
// Nondeterministically jump to level ∅. We need to do
// that only once per cycle. As an approximation, we
// only to that for transition where t.src >= t.dst as
// this has to occur at least once per cycle.
if (pend == orig_copy && (t.src >= t.dst) && maybe_acc && !no_fin)
{
acc_cond::mark_t pend = 0U;
if (sbacc)
{
auto a = in->state_acc_sets(t.dst);
if (a & scc_fin_wo_inf)
continue;
pend = (a & fin) << 1U;
pend -= a & inf;
}
st2gba_state d(t.dst, pend | scc_inf_wo_fin);
// Have we already seen this destination?
unsigned dest;
auto dres = bs2num.emplace(d, 0);
if (!dres.second)
{
dest = dres.first->second;
}
else // No, this is a new state
{
dest = dres.first->second = out->new_state();
todo.push_back(d);
}
out->new_edge(src, dest, t.cond);
}
}
}
// for (auto s: bs2num)
// {
// std::cerr << s.second << " ("
// << s.first.s << ", ";
// if (s.first.pend == orig_copy)
// std::cerr << "-)\n";
// else
// std::cerr << s.first.pend << ")\n";
// std::cerr << s.second << " ("
// << s.first.s << ", ";
// if (s.first.pend == orig_copy)
// std::cerr << "-)\n";
// else
// std::cerr << s.first.pend << ")\n";
// }
return out;
}
@ -290,11 +290,11 @@ namespace spot
static int min = [&]() {
const char* c = getenv("SPOT_STREETT_CONV_MIN");
if (!c)
return 3;
return 3;
errno = 0;
int val = strtol(c, nullptr, 10);
if (val < 0 || errno != 0)
throw std::runtime_error("unexpected value for SPOT_STREETT_CONV_MIN");
throw std::runtime_error("unexpected value for SPOT_STREETT_CONV_MIN");
return val;
}();
if (min == 0 || min > in->acc().is_streett())
@ -319,11 +319,11 @@ namespace spot
auto cnf = res->get_acceptance().to_cnf();
// If we are very lucky, building a CNF actually gave us a GBA...
if (cnf.empty() ||
(cnf.size() == 2 && cnf.back().op == acc_cond::acc_op::Inf))
(cnf.size() == 2 && cnf.back().op == acc_cond::acc_op::Inf))
{
res->set_acceptance(res->num_sets(), cnf);
cleanup_acceptance_here(res);
return res;
res->set_acceptance(res->num_sets(), cnf);
cleanup_acceptance_here(res);
return res;
}
// Handle false specifically. We want the output
@ -331,14 +331,14 @@ namespace spot
// state without successor.
if (cnf.size() == 2 && cnf.back().op == acc_cond::acc_op::Fin)
{
assert(cnf.front().mark == 0U);
res = make_twa_graph(aut->get_dict());
res->set_init_state(res->new_state());
res->prop_state_acc(true);
res->prop_weak(true);
res->prop_deterministic(true);
res->prop_stutter_invariant(true);
return res;
assert(cnf.front().mark == 0U);
res = make_twa_graph(aut->get_dict());
res->set_init_state(res->new_state());
res->prop_state_acc(true);
res->prop_weak(true);
res->prop_deterministic(true);
res->prop_stutter_invariant(true);
return res;
}
auto terms = cnf_terms(cnf);
@ -348,12 +348,12 @@ namespace spot
for (auto& t: res->edges())
{
acc_cond::mark_t cur_m = t.acc;
acc_cond::mark_t new_m = 0U;
for (unsigned n = 0; n < nterms; ++n)
if (cur_m & terms[n])
new_m.set(n);
t.acc = new_m;
acc_cond::mark_t cur_m = t.acc;
acc_cond::mark_t new_m = 0U;
for (unsigned n = 0; n < nterms; ++n)
if (cur_m & terms[n])
new_m.set(n);
t.acc = new_m;
}
return res;
}

View file

@ -35,9 +35,9 @@ namespace spot
comp_susp_ = opt->get("comp-susp", 0);
if (comp_susp_ == 1)
{
early_susp_ = opt->get("early-susp", 0);
skel_wdba_ = opt->get("skel-wdba", -1);
skel_simul_ = opt->get("skel-simul", 1);
early_susp_ = opt->get("early-susp", 0);
skel_wdba_ = opt->get("skel-wdba", -1);
skel_simul_ = opt->get("skel-simul", 1);
}
}
@ -47,16 +47,16 @@ namespace spot
switch (level_)
{
case High:
options.containment_checks = true;
options.containment_checks_stronger = true;
// fall through
options.containment_checks = true;
options.containment_checks_stronger = true;
// fall through
case Medium:
options.synt_impl = true;
// fall through
options.synt_impl = true;
// fall through
case Low:
options.reduce_basics = true;
options.event_univ = true;
// fall through
options.reduce_basics = true;
options.event_univ = true;
// fall through
}
simpl_owned_ = simpl_ = new tl_simplifier(options, dict);
}
@ -66,10 +66,10 @@ namespace spot
bool unambiguous = (pref_ & postprocessor::Unambiguous);
if (unambiguous && type_ == postprocessor::Monitor)
{
// Deterministic monitor are unambiguous, so the unambiguous
// option is not really relevant for monitors.
unambiguous = false;
set_pref(pref_ | postprocessor::Deterministic);
// Deterministic monitor are unambiguous, so the unambiguous
// option is not really relevant for monitors.
unambiguous = false;
set_pref(pref_ | postprocessor::Deterministic);
}
formula r = simpl_->simplify(*f);
@ -82,21 +82,21 @@ namespace spot
twa_graph_ptr aut;
if (comp_susp_ > 0)
{
// FIXME: Handle unambiguous_ automata?
int skel_wdba = skel_wdba_;
if (skel_wdba < 0)
skel_wdba = (pref_ == postprocessor::Deterministic) ? 1 : 2;
// FIXME: Handle unambiguous_ automata?
int skel_wdba = skel_wdba_;
if (skel_wdba < 0)
skel_wdba = (pref_ == postprocessor::Deterministic) ? 1 : 2;
aut = compsusp(r, simpl_->get_dict(), skel_wdba == 0,
skel_simul_ == 0, early_susp_ != 0,
comp_susp_ == 2, skel_wdba == 2, false);
aut = compsusp(r, simpl_->get_dict(), skel_wdba == 0,
skel_simul_ == 0, early_susp_ != 0,
comp_susp_ == 2, skel_wdba == 2, false);
}
else
{
bool exprop = unambiguous || level_ == postprocessor::High;
aut = ltl_to_tgba_fm(r, simpl_->get_dict(), exprop,
true, false, false, nullptr, nullptr,
unambiguous);
bool exprop = unambiguous || level_ == postprocessor::High;
aut = ltl_to_tgba_fm(r, simpl_->get_dict(), exprop,
true, false, false, nullptr, nullptr,
unambiguous);
}
aut = this->postprocessor::run(aut, r);
return aut;

View file

@ -54,12 +54,12 @@ namespace spot
{
bdd all = bddtrue;
for (auto& i: cycle)
all &= i;
all &= i;
if (all != bddfalse)
{
cycle.clear();
cycle.push_back(all);
}
{
cycle.clear();
cycle.push_back(all);
}
}
// If the last formula of the prefix is compatible with the
// last formula of the cycle, we can shift the cycle and
@ -71,12 +71,12 @@ namespace spot
// !a|!b; cycle{a&b}
while (!prefix.empty())
{
bdd a = prefix.back() & cycle.back();
if (a == bddfalse)
break;
prefix.pop_back();
cycle.pop_back();
cycle.push_front(a);
bdd a = prefix.back() & cycle.back();
if (a == bddfalse)
break;
prefix.pop_back();
cycle.pop_back();
cycle.push_front(a);
}
// Get rid of any disjunction.
//
@ -98,18 +98,18 @@ namespace spot
auto d = w.get_dict();
if (!w.prefix.empty())
for (auto& i: w.prefix)
{
bdd_print_formula(os, d, i);
os << "; ";
}
{
bdd_print_formula(os, d, i);
os << "; ";
}
bool notfirst = false;
os << "cycle{";
for (auto& i: w.cycle)
{
if (notfirst)
os << "; ";
notfirst = true;
bdd_print_formula(os, d, i);
if (notfirst)
os << "; ";
notfirst = true;
bdd_print_formula(os, d, i);
}
os << '}';
return os;
@ -118,7 +118,7 @@ namespace spot
namespace
{
static void word_parse_error(const std::string& word,
size_t i, parsed_formula pf)
size_t i, parsed_formula pf)
{
std::ostringstream os;
pf.format_errors(os, word, i);
@ -126,14 +126,14 @@ namespace spot
}
static void word_parse_error(const std::string& word, size_t i,
const std::string& message)
const std::string& message)
{
if (i == std::string::npos)
i = word.size();
i = word.size();
std::ostringstream s;
s << ">>> " << word << '\n';
for (auto j = i + 4; j > 0; --j)
s << ' ';
s << ' ';
s << '^' << '\n';
s << message << '\n';
throw parse_error(s.str());
@ -144,17 +144,17 @@ namespace spot
bool quoted = false;
auto size = word.size();
for (auto j = begin; j < size; ++j)
{
auto c = word[j];
if (!quoted && (c == ';' || c == '}'))
return j;
if (c == '"')
quoted = !quoted;
else if (quoted && c == '\\')
++j;
}
{
auto c = word[j];
if (!quoted && (c == ';' || c == '}'))
return j;
if (c == '"')
quoted = !quoted;
else if (quoted && c == '\\')
++j;
}
if (quoted)
word_parse_error(word, word.size(), "Unclosed string");
word_parse_error(word, word.size(), "Unclosed string");
return std::string::npos;
}
}
@ -170,49 +170,49 @@ namespace spot
auto extract_bdd =
[&](typename twa_word::seq_t& seq)
{
auto sub = word.substr(i, ind - i);
auto pf = spot::parse_infix_boolean(sub);
if (!pf.errors.empty())
word_parse_error(word, i, pf);
atomic_prop_collect(pf.f, &aps);
seq.push_back(tls.as_bdd(pf.f));
if (word[ind] == '}')
return true;
// Skip blanks after semi-colon
i = word.find_first_not_of(' ', ind + 1);
return false;
auto sub = word.substr(i, ind - i);
auto pf = spot::parse_infix_boolean(sub);
if (!pf.errors.empty())
word_parse_error(word, i, pf);
atomic_prop_collect(pf.f, &aps);
seq.push_back(tls.as_bdd(pf.f));
if (word[ind] == '}')
return true;
// Skip blanks after semi-colon
i = word.find_first_not_of(' ', ind + 1);
return false;
};
// Parse the prefix part. Can be empty.
while (word.substr(i, 6) != std::string("cycle{"))
{
ind = skip_next_formula(word, i);
if (ind == std::string::npos)
word_parse_error(word, word.size(),
"A twa_word must contain a cycle");
if (word[ind] == '}')
word_parse_error(word, ind, "Expected ';' delimiter: "
"'}' stands for ending a cycle");
// Exract formula, convert it to bdd and add it to the prefix sequence
extract_bdd(tw->prefix);
if (i == std::string::npos)
word_parse_error(word, ind + 1, "Missing cycle in formula");
ind = skip_next_formula(word, i);
if (ind == std::string::npos)
word_parse_error(word, word.size(),
"A twa_word must contain a cycle");
if (word[ind] == '}')
word_parse_error(word, ind, "Expected ';' delimiter: "
"'}' stands for ending a cycle");
// Exract formula, convert it to bdd and add it to the prefix sequence
extract_bdd(tw->prefix);
if (i == std::string::npos)
word_parse_error(word, ind + 1, "Missing cycle in formula");
}
// Consume "cycle{"
i += 6;
while (true)
{
ind = skip_next_formula(word, i);
if (ind == std::string::npos)
word_parse_error(word, word.size(),
"Missing ';' or '}' after formula");
// Extract formula, convert it to bdd and add it to the cycle sequence
// Break if an '}' is encountered
if (extract_bdd(tw->cycle))
break;
if (i == std::string::npos)
word_parse_error(word, ind + 1,
"Missing end of cycle character: '}'");
ind = skip_next_formula(word, i);
if (ind == std::string::npos)
word_parse_error(word, word.size(),
"Missing ';' or '}' after formula");
// Extract formula, convert it to bdd and add it to the cycle sequence
// Break if an '}' is encountered
if (extract_bdd(tw->cycle))
break;
if (i == std::string::npos)
word_parse_error(word, ind + 1,
"Missing end of cycle character: '}'");
}
if (ind != word.size() - 1)
word_parse_error(word, ind + 1, "Input should be finished after cycle");
@ -232,31 +232,31 @@ namespace spot
{
bdd support = bddtrue;
for (auto b: prefix)
support &= bdd_support(b);
support &= bdd_support(b);
for (auto b: cycle)
support &= bdd_support(b);
support &= bdd_support(b);
while (support != bddtrue)
{
int v = bdd_var(support);
support = bdd_high(support);
aut->register_ap(dict_->bdd_map[v].f);
}
{
int v = bdd_var(support);
support = bdd_high(support);
aut->register_ap(dict_->bdd_map[v].f);
}
}
size_t i = 0;
aut->new_states(prefix.size() + cycle.size());
for (auto b: prefix)
{
aut->new_edge(i, i + 1, b);
++i;
aut->new_edge(i, i + 1, b);
++i;
}
size_t j = i;
auto b = cycle.begin();
auto end = --cycle.end();
for (; b != end; ++b)
{
aut->new_edge(i, i + 1, *b);
++i;
aut->new_edge(i, i + 1, *b);
++i;
}
// Close the loop
aut->new_edge(i, j, *b);