Store membership to acceptance sets using bitsets, not BDDs.

This is a huge patch, that took over a month to complete.  The bit sets
are currently restricted to what 'unsigned can store', but it should be
easy to extend it to 'uint64_t' should we need it.

* NEWS: Update.
* src/tgba/acc.hh: New file.
* src/tgbatest/acc.cc, src/tgbatest/acc.test: Test it.
* src/tgba/tgbakvcomplement.cc, src/tgba/tgbakvcomplement.hh,
src/tgba/tgbasgba.cc, src/tgba/tgbasgba.hh: Delete.  The KV
complementation is too slow to be used in practice, and I somehow broke
it during the conversion to bitsets.  The tgba->sgba conversion was only
used for the KV complementation, and should be better redone on
tgba_digraph_ptr should it be needed again.
* src/bin/ltlcross.cc, src/dstarparse/dra2ba.cc,
src/dstarparse/nsa2tgba.cc, src/graphtest/tgbagraph.cc,
src/graphtest/tgbagraph.test, src/kripke/fairkripke.cc,
src/kripke/fairkripke.hh, src/kripke/kripke.cc, src/kripke/kripke.hh,
src/kripke/kripkeexplicit.cc, src/kripke/kripkeexplicit.hh,
src/misc/hash.hh, src/neverparse/neverclaimparse.yy, src/priv/accmap.hh,
src/ta/ta.cc, src/ta/ta.hh, src/ta/taexplicit.cc, src/ta/taexplicit.hh,
src/ta/taproduct.cc, src/ta/taproduct.hh, src/ta/tgta.cc,
src/ta/tgta.hh, src/ta/tgtaexplicit.cc, src/ta/tgtaexplicit.hh,
src/ta/tgtaproduct.cc, src/ta/tgtaproduct.hh, src/taalgos/dotty.cc,
src/taalgos/emptinessta.cc, src/taalgos/minimize.cc,
src/taalgos/tgba2ta.cc, src/tgba/Makefile.am, src/tgba/fwd.hh,
src/tgba/taatgba.cc, src/tgba/taatgba.hh, src/tgba/tgba.cc,
src/tgba/tgba.hh, src/tgba/tgbagraph.cc, src/tgba/tgbagraph.hh,
src/tgba/tgbamask.cc, src/tgba/tgbamask.hh, src/tgba/tgbaproduct.cc,
src/tgba/tgbaproduct.hh, src/tgba/tgbaproxy.cc, src/tgba/tgbaproxy.hh,
src/tgba/tgbasafracomplement.cc, src/tgba/tgbasafracomplement.hh,
src/tgbaalgos/bfssteps.cc, src/tgbaalgos/complete.cc,
src/tgbaalgos/compsusp.cc, src/tgbaalgos/degen.cc,
src/tgbaalgos/dotty.cc, src/tgbaalgos/dtbasat.cc,
src/tgbaalgos/dtgbacomp.cc, src/tgbaalgos/dtgbasat.cc,
src/tgbaalgos/dupexp.cc, src/tgbaalgos/emptiness.cc,
src/tgbaalgos/emptiness.hh, src/tgbaalgos/gtec/ce.cc,
src/tgbaalgos/gtec/gtec.cc, src/tgbaalgos/gtec/gtec.hh,
src/tgbaalgos/gtec/sccstack.cc, src/tgbaalgos/gtec/sccstack.hh,
src/tgbaalgos/gv04.cc, src/tgbaalgos/hoaf.cc,
src/tgbaalgos/isweakscc.cc, src/tgbaalgos/lbtt.cc,
src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/magic.cc,
src/tgbaalgos/ndfs_result.hxx, src/tgbaalgos/neverclaim.cc,
src/tgbaalgos/postproc.cc, src/tgbaalgos/powerset.cc,
src/tgbaalgos/randomgraph.cc, src/tgbaalgos/randomgraph.hh,
src/tgbaalgos/reducerun.cc, src/tgbaalgos/replayrun.cc,
src/tgbaalgos/safety.cc, src/tgbaalgos/save.cc, src/tgbaalgos/scc.cc,
src/tgbaalgos/scc.hh, src/tgbaalgos/sccfilter.cc,
src/tgbaalgos/sccinfo.cc, src/tgbaalgos/sccinfo.hh,
src/tgbaalgos/se05.cc, src/tgbaalgos/simulation.cc,
src/tgbaalgos/simulation.hh, src/tgbaalgos/stats.cc,
src/tgbaalgos/stripacc.cc, src/tgbaalgos/tau03.cc,
src/tgbaalgos/tau03opt.cc, src/tgbaalgos/weight.cc,
src/tgbaalgos/weight.hh, src/tgbaparse/tgbaparse.yy,
src/tgbatest/Makefile.am, src/tgbatest/complementation.cc,
src/tgbatest/complementation.test, src/tgbatest/degenlskip.test,
src/tgbatest/det.test, src/tgbatest/dstar.test, src/tgbatest/emptchk.cc,
src/tgbatest/explpro2.test, src/tgbatest/explpro3.test,
src/tgbatest/explpro4.test, src/tgbatest/explprod.test,
src/tgbatest/ltl2tgba.cc, src/tgbatest/ltl2tgba.test,
src/tgbatest/maskacc.cc, src/tgbatest/maskacc.test,
src/tgbatest/neverclaimread.test, src/tgbatest/randtgba.cc,
src/tgbatest/readsave.test, src/tgbatest/sim.test,
src/tgbatest/sim2.test, src/tgbatest/spotlbtt.test,
src/tgbatest/tgbaread.test, src/tgbatest/tripprod.test,
iface/dve2/dve2.cc: Adjust or use to the new acceptance interface.
This commit is contained in:
Alexandre Duret-Lutz 2014-09-29 18:17:34 +02:00
parent 37ece2b878
commit 2c764fb3c7
125 changed files with 1950 additions and 3254 deletions

38
NEWS
View file

@ -56,12 +56,35 @@ New in spot 1.99a (not yet released)
Where the virtual calls to done() and delete have been avoided.
- tgba::support_variables() and tgba::compute_support_variables()
- tgba::succ_iter() now takes only one argument. The optional
global_state and global_automaton arguments have been removed.
- The following methods have been removed from the TGBA interface and
all their subclasses:
- tgba::support_variables()
- tgba::compute_support_variables()
- tgba::all_acceptance_conditions() // use acc().accepting(...)
- tgba::neg_acceptance_conditions()
- tgba::number_of_acceptance_conditions() // use acc().num_sets()
methods have been removed from the TGBA interface and all
subclasses.
- tgba::succ_iter() now takes only one argument. The optional
global_state and global_automaton arguments have been removed.
- Membership to acceptance sets are now stored using bit sets,
currently limited to 32 bits. Each TGBA has a acc() method that
returns a reference to an acceptance object (of type
spot::acc_cond), able to operate on acceptance marks
(spot::acc_cond::mark_t).
Instead of writing
i->current_acceptance_conditions() == aut->all_acceptance_conditions()
we now write
aut->acc().accepting(i->current_acceptance_conditions())
Similarly,
aut->number_of_acceptance_conditions()
is now
aut->acc().num_sets()
* Removed features
@ -87,6 +110,15 @@ New in spot 1.99a (not yet released)
automata (when viewed explictely), using the above and non
longuer supported tgba_bdd_concrete class.
- Our implementation of the Kupferman-Vardi complementation has
been removed: it was useless in practice beause of the size of
the automata built, and it did not survive the conversion of
acceptance sets from BDDs to bitsets.
- Conversion from TGBA to state-based Generalized Büchi automata
has been removed too, because it was only used by the KV
complementation.
New in spot 1.2.5a (not yet released)
* New features:

View file

@ -606,7 +606,8 @@ namespace spot
dve2_kripke(const dve2_interface* d, const bdd_dict_ptr& dict,
const prop_set* ps, const ltl::formula* dead, int compress)
: d_(d),
: kripke(dict),
d_(d),
state_size_(d_->get_state_variable_count()),
dict_(dict), ps_(ps),
compress_(compress == 0 ? 0

View file

@ -1047,7 +1047,7 @@ namespace
st->states = s.states;
st->edges = s.transitions;
st->transitions = s.sub_transitions;
st->acc = res->number_of_acceptance_conditions();
st->acc = res->acc().num_sets();
spot::scc_map m(res);
m.build_map();
unsigned c = m.scc_count();

View file

@ -23,6 +23,7 @@
#include "tgbaalgos/reachiter.hh"
#include "tgbaalgos/gtec/gtec.hh"
#include "tgbaalgos/sccfilter.hh"
#include "tgbaalgos/dotty.hh"
namespace spot
{
@ -55,7 +56,7 @@ namespace spot
{
typedef std::list<const state*> state_list;
// The function that takes aut and dra is first arguments are
// The functions that take aut and dra as first arguments are
// either called on the main automaton, in which case dra->aut ==
// aut, or it is called on a sub-automaton in which case aut is a
// masked version of dra->aut. So we should always explore the
@ -293,7 +294,7 @@ namespace spot
tgba_digraph_ptr out_;
const state_set& final_;
size_t num_states_;
bdd acc_;
acc_cond::mark_t acc_;
const scc_map& sm_;
const std::vector<bool>& realizable_;
};

View file

@ -129,7 +129,7 @@ namespace spot
for (auto& t: a->out(s.s))
{
bitvect* pend = 0;
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
if (s.pend)
{
pend = s.pend->clone();

View file

@ -35,21 +35,20 @@ void f1()
auto* f2 = e.require("p2");
bdd p1 = bdd_ithvar(d->register_proposition(f1, tg));
bdd p2 = bdd_ithvar(d->register_proposition(f2, tg));
bdd a1 = bdd_ithvar(d->register_acceptance_variable(f1, tg));
bdd a2 = bdd_ithvar(d->register_acceptance_variable(f2, tg));
tg->acc().add_sets(2);
f1->destroy();
f2->destroy();
auto s1 = tg->new_state();
auto s2 = tg->new_state();
auto s3 = tg->new_state();
tg->new_transition(s1, s1, bddfalse, bddfalse);
tg->new_transition(s1, s2, p1, bddfalse);
tg->new_transition(s1, s3, p2, (!a1) & a2);
tg->new_transition(s2, s3, p1 & p2, a1 & !a2);
tg->new_transition(s3, s1, p1 | p2, ((!a1) & a2) | (a1 & !a2));
tg->new_transition(s3, s2, p1 >> p2, bddfalse);
tg->new_transition(s3, s3, bddtrue, ((!a1) & a2) | (a1 & !a2));
tg->new_transition(s1, s1, bddfalse, 0U);
tg->new_transition(s1, s2, p1, 0U);
tg->new_transition(s1, s3, p2, tg->acc().mark(1));
tg->new_transition(s2, s3, p1 & p2, tg->acc().mark(0));
tg->new_transition(s3, s1, p1 | p2, tg->acc().marks({0, 1}));
tg->new_transition(s3, s2, p1 >> p2, 0U);
tg->new_transition(s3, s3, bddtrue, tg->acc().marks({0, 1}));
spot::dotty_reachable(std::cout, tg);
@ -69,9 +68,10 @@ void f1()
spot::dotty_reachable(std::cout, tg);
}
tg->new_transition(s3, s1, p1 | p2, ((!a1) & a2) | (a1 & !a2));
tg->new_transition(s3, s2, p1 >> p2, bddfalse);
tg->new_transition(s3, s1, bddtrue, ((!a1) & a2) | (a1 & !a2));
auto all = tg->acc().marks({0, 1});
tg->new_transition(s3, s1, p1 | p2, all);
tg->new_transition(s3, s2, p1 >> p2, 0U);
tg->new_transition(s3, s1, bddtrue, all);
std::cerr << tg->num_transitions() << '\n';
assert(tg->num_transitions() == 7);

View file

@ -37,76 +37,76 @@ digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0"]
1 -> 1 [label="0\n"]
1 -> 2 [label="p1\n"]
1 -> 3 [label="p2\n{Acc[p2]}"]
1 -> 1 [label="0"]
1 -> 2 [label="p1"]
1 -> 3 [label="p2\n{1}"]
2 [label="1"]
2 -> 3 [label="p1 & p2\n{Acc[p1]}"]
2 -> 3 [label="p1 & p2\n{0}"]
3 [label="2"]
3 -> 1 [label="p1 | p2\n{Acc[p2], Acc[p1]}"]
3 -> 2 [label="!p1 | p2\n"]
3 -> 3 [label="1\n{Acc[p2], Acc[p1]}"]
3 -> 1 [label="p1 | p2\n{0,1}"]
3 -> 2 [label="!p1 | p2"]
3 -> 3 [label="1\n{0,1}"]
}
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0"]
1 -> 1 [label="0\n"]
1 -> 2 [label="p1\n"]
1 -> 3 [label="p2\n{Acc[p2]}"]
1 -> 1 [label="0"]
1 -> 2 [label="p1"]
1 -> 3 [label="p2\n{1}"]
2 [label="1"]
2 -> 3 [label="p1 & p2\n{Acc[p1]}"]
2 -> 3 [label="p1 & p2\n{0}"]
3 [label="2"]
3 -> 1 [label="p1 | p2\n{Acc[p2], Acc[p1]}"]
3 -> 1 [label="p1 | p2\n{0,1}"]
}
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0"]
1 -> 1 [label="0\n"]
1 -> 2 [label="p1\n"]
1 -> 3 [label="p2\n{Acc[p2]}"]
1 -> 1 [label="0"]
1 -> 2 [label="p1"]
1 -> 3 [label="p2\n{1}"]
2 [label="1"]
2 -> 3 [label="p1 & p2\n{Acc[p1]}"]
2 -> 3 [label="p1 & p2\n{0}"]
3 [label="2"]
}
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0"]
1 -> 1 [label="0\n"]
1 -> 2 [label="p1\n"]
1 -> 3 [label="p2\n{Acc[p2]}"]
1 -> 1 [label="0"]
1 -> 2 [label="p1"]
1 -> 3 [label="p2\n{1}"]
2 [label="1"]
2 -> 3 [label="p1 & p2\n{Acc[p1]}"]
2 -> 3 [label="p1 & p2\n{0}"]
3 [label="2"]
3 -> 1 [label="p1 | p2\n{Acc[p2], Acc[p1]}"]
3 -> 2 [label="!p1 | p2\n"]
3 -> 1 [label="1\n{Acc[p2], Acc[p1]}"]
3 -> 1 [label="p1 | p2\n{0,1}"]
3 -> 2 [label="!p1 | p2"]
3 -> 1 [label="1\n{0,1}"]
}
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0"]
1 -> 2 [label="p1\n"]
1 -> 3 [label="p2\n{Acc[p2]}"]
1 -> 2 [label="p1"]
1 -> 3 [label="p2\n{1}"]
2 [label="1"]
2 -> 3 [label="p1 & p2\n{Acc[p1]}"]
2 -> 3 [label="p1 & p2\n{0}"]
3 [label="2"]
3 -> 1 [label="1\n{Acc[p2], Acc[p1]}"]
3 -> 2 [label="!p1 | p2\n"]
3 -> 1 [label="1\n{0,1}"]
3 -> 2 [label="!p1 | p2"]
}
digraph G {
0 [label="", style=invis, height=0]
0 -> 1
1 [label="0"]
1 -> 2 [label="p1\n"]
1 -> 3 [label="p2\n{Acc[p2]}"]
1 -> 2 [label="p1"]
1 -> 3 [label="p2\n{1}"]
2 [label="1"]
2 -> 3 [label="p1 & p2\n{Acc[p1]}"]
2 -> 3 [label="p1 & p2\n{0}"]
3 [label="2"]
3 -> 1 [label="1\n{Acc[p2], Acc[p1]}"]
3 -> 2 [label="!p1 | p2\n"]
3 -> 1 [label="1\n{0,1}"]
3 -> 2 [label="!p1 | p2"]
}
EOF

View file

@ -22,8 +22,8 @@
namespace spot
{
fair_kripke_succ_iterator::fair_kripke_succ_iterator(const bdd& cond,
const bdd& acc_cond)
fair_kripke_succ_iterator::fair_kripke_succ_iterator
(const bdd& cond, acc_cond::mark_t acc_cond)
: cond_(cond), acc_cond_(acc_cond)
{
}
@ -40,7 +40,7 @@ namespace spot
return cond_;
}
bdd
acc_cond::mark_t
fair_kripke_succ_iterator::current_acceptance_conditions() const
{
// Do not assert(!done()) here. It is OK to call

View file

@ -52,14 +52,14 @@ namespace spot
/// The \a cond and \a acc_cond arguments will be those returned
/// by fair_kripke_succ_iterator::current_condition(),
/// and fair_kripke_succ_iterator::current_acceptance_conditions().
fair_kripke_succ_iterator(const bdd& cond, const bdd& acc_cond);
fair_kripke_succ_iterator(const bdd& cond, acc_cond::mark_t acc_cond);
virtual ~fair_kripke_succ_iterator();
virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const;
virtual acc_cond::mark_t current_acceptance_conditions() const;
protected:
bdd cond_;
bdd acc_cond_;
acc_cond::mark_t acc_cond_;
};
/// \ingroup kripke
@ -86,16 +86,22 @@ namespace spot
/// class and need not be defined.
///
/// See also spot::fair_kripke_succ_iterator.
class SPOT_API fair_kripke : public tgba
class SPOT_API fair_kripke: public tgba
{
public:
fair_kripke(const bdd_dict_ptr& d)
: tgba(d)
{
}
/// \brief The condition that label the state \a s.
///
/// This should be a conjunction of atomic propositions.
virtual bdd state_condition(const state* s) const = 0;
/// \brief The set of acceptance conditions that label the state \a s.
virtual bdd state_acceptance_conditions(const state* s) const = 0;
virtual acc_cond::mark_t
state_acceptance_conditions(const state* s) const = 0;
protected:
virtual bdd compute_support_conditions(const state* s) const;

View file

@ -34,33 +34,21 @@ namespace spot
return cond_;
}
bdd
acc_cond::mark_t
kripke_succ_iterator::current_acceptance_conditions() const
{
// Do not assert(!done()) here. It is OK to call
// this function on a state without successor.
return bddfalse;
return 0U;
}
kripke::~kripke()
{
}
bdd
acc_cond::mark_t
kripke::state_acceptance_conditions(const state*) const
{
return bddtrue;
return 0U;
}
bdd kripke::all_acceptance_conditions() const
{
// There is no acceptance conditions.
return bddfalse;
}
bdd kripke::neg_acceptance_conditions() const
{
return bddtrue;
}
}

View file

@ -61,7 +61,7 @@ namespace spot
virtual ~kripke_succ_iterator();
virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const;
virtual acc_cond::mark_t current_acceptance_conditions() const;
protected:
bdd cond_;
};
@ -92,11 +92,15 @@ namespace spot
class SPOT_API kripke: public fair_kripke
{
public:
kripke(const bdd_dict_ptr& d)
: fair_kripke(d)
{
}
virtual ~kripke();
virtual bdd state_acceptance_conditions(const state*) const;
virtual bdd neg_acceptance_conditions() const;
virtual bdd all_acceptance_conditions() const;
virtual acc_cond::mark_t state_acceptance_conditions(const state*) const;
};

View file

@ -128,8 +128,8 @@ namespace spot
kripke_explicit::kripke_explicit(const bdd_dict_ptr& dict,
state_kripke* init)
: dict_(dict),
init_ (init)
: kripke(dict),
init_(init)
{
}
@ -148,7 +148,7 @@ namespace spot
kripke_explicit::~kripke_explicit()
{
dict_->unregister_all_my_variables(this);
get_dict()->unregister_all_my_variables(this);
std::map<const std::string, state_kripke*>::iterator it;
for (it = ns_nodes_.begin(); it != ns_nodes_.end(); ++it)
{
@ -163,12 +163,6 @@ namespace spot
return init_;
}
bdd_dict_ptr
kripke_explicit::get_dict() const
{
return dict_;
}
// FIXME: Change the bddtrue.
kripke_explicit_succ_iterator*
kripke_explicit::succ_iter(const spot::state* st) const
@ -269,7 +263,7 @@ namespace spot
void kripke_explicit::add_condition(const ltl::formula* f,
std::string on_me)
{
add_conditions(formula_to_bdd(f, dict_, this), on_me);
add_conditions(formula_to_bdd(f, get_dict(), this), on_me);
f->destroy();
}

View file

@ -117,7 +117,6 @@ namespace spot
kripke_explicit(const bdd_dict_ptr&, state_kripke* = nullptr);
~kripke_explicit();
bdd_dict_ptr get_dict() const;
state_kripke* get_init_state() const;
/// \brief Allow to get an iterator on the state we passed in
@ -174,7 +173,6 @@ namespace spot
void add_transition(state_kripke* source,
const state_kripke* dest);
bdd_dict_ptr dict_;
state_kripke* init_;
std::map<const std::string, state_kripke*> ns_nodes_;
std::map<const state_kripke*, std::string> sn_nodes_;

View file

@ -82,8 +82,11 @@ namespace spot
template<typename T, typename U>
std::size_t operator()(const std::pair<T, U> &p) const
{
return wang32_hash(static_cast<size_t>(p.first) ^
static_cast<size_t>(p.second));
std::hash<T> th;
std::hash<U> uh;
return wang32_hash(static_cast<size_t>(th(p.first)) ^
static_cast<size_t>(uh(p.second)));
}
};

View file

@ -169,17 +169,16 @@ state:
namer->new_transition(*$1, *$1, bddtrue,
!strncmp("accept", $1->c_str(), 6) ?
result->all_acceptance_conditions() :
static_cast<const bdd>(bddfalse));
result->acc().all_sets() :
spot::acc_cond::mark_t(0U));
delete $1;
}
| ident_list { delete $1; }
| ident_list "false" { delete $1; }
| ident_list transition_block
{
bdd acc = !strncmp("accept", $1->c_str(), 6) ?
result->all_acceptance_conditions() :
static_cast<const bdd>(bddfalse);
auto acc = !strncmp("accept", $1->c_str(), 6) ?
result->acc().all_sets() : spot::acc_cond::mark_t(0U);
for (auto& p: *$2)
namer->new_transition(*$1, *p.second, *p.first, acc);
// Free the list

View file

@ -34,10 +34,9 @@ namespace spot
bdd_dict_ptr dict_;
tgba_digraph_ptr aut_;
ltl::environment& env_;
bdd neg_;
acc_mapper_common(const tgba_digraph_ptr& aut, ltl::environment& env)
: dict_(aut->get_dict()), aut_(aut), env_(env), neg_(bddtrue)
: dict_(aut->get_dict()), aut_(aut), env_(env)
{
}
@ -46,17 +45,11 @@ namespace spot
{
return env_;
}
// Commit all acceptance set to the automaton.
void commit()
{
aut_->set_acceptance_conditions(neg_);
}
};
class acc_mapper_string: public acc_mapper_common
{
std::unordered_map<std::string, int> map_;
std::unordered_map<std::string, unsigned> map_;
public:
acc_mapper_string(const tgba_digraph_ptr& aut,
@ -72,24 +65,17 @@ namespace spot
auto i = map_.find(name);
if (i != map_.end())
return true;
auto f = env_.require(name);
if (!f)
return false;
int v = dict_->register_acceptance_variable(f, aut_);
f->destroy();
auto v = aut_->acc().add_set();
map_[name] = v;
neg_ &= bdd_nithvar(v);
return true;
}
std::pair<bool, bdd> lookup(std::string name) const
std::pair<bool, acc_cond::mark_t> lookup(std::string name) const
{
auto p = map_.find(name);
if (p == map_.end())
return std::make_pair(false, bddfalse);
return std::make_pair(true, bdd_compose(neg_,
bdd_nithvar(p->second),
p->second));
return std::make_pair(false, 0U);
return std::make_pair(true, aut_->acc().marks({p->second}));
}
};
@ -97,42 +83,23 @@ namespace spot
// The acceptance sets are named using count consecutive integers.
class acc_mapper_consecutive_int: public acc_mapper_common
{
protected:
std::vector<bdd> vec_;
std::map<int, bdd> map_;
public:
acc_mapper_consecutive_int(const tgba_digraph_ptr& aut,
unsigned count,
ltl::environment& env =
ltl::default_environment::instance())
: acc_mapper_common(aut, env), vec_(count)
: acc_mapper_common(aut, env)
{
std::vector<int> vmap(count);
for (unsigned n = 0; n < count; ++n)
{
std::ostringstream s;
s << n;
auto f = env.require(s.str());
int v = dict_->register_acceptance_variable(f, aut_);
f->destroy();
vmap[n] = v;
neg_ &= bdd_nithvar(v);
}
for (unsigned n = 0; n < count; ++n)
{
int v = vmap[n];
vec_[n] = bdd_compose(neg_, bdd_nithvar(v), v);
}
commit();
std::vector<unsigned> vmap(count);
aut->acc().add_sets(count);
}
std::pair<bool, bdd> lookup(unsigned n)
std::pair<bool, acc_cond::mark_t> lookup(unsigned n)
{
if (n < vec_.size())
return std::make_pair(true, vec_[n]);
if (n < aut_->acc().num_sets())
return std::make_pair(true, aut_->acc().marks({n}));
else
return std::make_pair(false, bddfalse);
return std::make_pair(false, 0U);
}
};
@ -141,7 +108,7 @@ namespace spot
class acc_mapper_int: public acc_mapper_consecutive_int
{
unsigned used_;
std::map<int, bdd> map_;
std::map<unsigned, acc_cond::mark_t> map_;
public:
acc_mapper_int(const tgba_digraph_ptr& aut,
@ -152,18 +119,18 @@ namespace spot
{
}
std::pair<bool, bdd> lookup(unsigned n)
std::pair<bool, acc_cond::mark_t> lookup(unsigned n)
{
auto p = map_.find(n);
if (p != map_.end())
return std::make_pair(true, p->second);
if (used_ < vec_.size())
if (used_ < aut_->acc().num_sets())
{
bdd res = vec_[used_++];
auto res = aut_->acc().marks({used_++});
map_[n] = res;
return std::make_pair(true, res);
}
return std::make_pair(false, bddfalse);
return std::make_pair(false, 0U);
}
};
}

View file

@ -28,7 +28,7 @@ namespace spot
{
index = i;
is_accepting = false;
condition = bddfalse;
condition = 0U;
}
scc_stack_ta::connected_component&

View file

@ -76,8 +76,15 @@ namespace spot
class SPOT_API ta
{
protected:
acc_cond acc_;
public:
ta(const bdd_dict_ptr& d)
: acc_(d)
{
}
virtual
~ta()
{
@ -128,8 +135,11 @@ namespace spot
/// This is useful when dealing with several automata (which
/// may use the same BDD variable for different formula),
/// or simply when printing.
virtual bdd_dict_ptr
get_dict() const = 0;
bdd_dict_ptr
get_dict() const
{
return acc_.get_dict();
}
/// \brief Format the state as a string for printing.
///
@ -160,17 +170,16 @@ namespace spot
virtual void
free_state(const spot::state* s) const = 0;
/// \brief Return the set of all acceptance conditions used
/// by this automaton
/// (for Generalized form: Transition-based Generalized Testing Automata).
///
/// The goal of the emptiness check is to ensure that
/// a strongly connected component walks through each
/// of these acceptiong conditions. I.e., the union
/// of the acceptiong conditions of all transition in
/// the SCC should be equal to the result of this function.
virtual bdd
all_acceptance_conditions() const = 0;
const acc_cond& acc() const
{
return acc_;
}
acc_cond& acc()
{
return acc_;
}
};
@ -206,7 +215,7 @@ namespace spot
virtual bdd
current_condition() const = 0;
bdd
acc_cond::mark_t
current_acceptance_conditions() const = 0;
};
@ -228,7 +237,7 @@ namespace spot
/// The bdd condition is the union of all acceptance conditions of
/// transitions which connect the states of the connected component.
bdd condition;
acc_cond::mark_t condition;
std::list<state*> rem;
};

View file

@ -97,7 +97,7 @@ namespace spot
return (*i_)->condition;
}
bdd
acc_cond::mark_t
ta_explicit_succ_iterator::current_acceptance_conditions() const
{
assert(!done());
@ -352,13 +352,14 @@ namespace spot
ta_explicit::ta_explicit(const const_tgba_ptr& tgba,
bdd all_acceptance_conditions,
unsigned n_acc,
state_ta_explicit* artificial_initial_state):
ta(tgba->get_dict()),
tgba_(tgba),
all_acceptance_conditions_(all_acceptance_conditions),
artificial_initial_state_(artificial_initial_state)
{
get_dict()->register_all_variables_of(&tgba_, this);
acc().add_sets(n_acc);
if (artificial_initial_state != 0)
{
state_ta_explicit* is = add_state(artificial_initial_state);
@ -403,7 +404,7 @@ namespace spot
{
state_ta_explicit* i =
down_cast<state_ta_explicit*>(get_artificial_initial_state());
create_transition(i, condition, bddfalse, s);
create_transition(i, condition, 0U, s);
}
}
@ -420,7 +421,7 @@ namespace spot
void
ta_explicit::create_transition(state_ta_explicit* source, bdd condition,
bdd acceptance_conditions,
acc_cond::mark_t acceptance_conditions,
state_ta_explicit* dest, bool add_at_beginning)
{
state_ta_explicit::transition* t = new state_ta_explicit::transition;

View file

@ -41,7 +41,8 @@ namespace spot
class SPOT_API ta_explicit : public ta
{
public:
ta_explicit(const const_tgba_ptr& tgba, bdd all_acceptance_conditions,
ta_explicit(const const_tgba_ptr& tgba,
unsigned n_acc,
state_ta_explicit* artificial_initial_state = 0);
const_tgba_ptr
@ -55,8 +56,9 @@ namespace spot
void
create_transition(state_ta_explicit* source, bdd condition,
bdd acceptance_conditions, state_ta_explicit* dest,
bool add_at_beginning = false);
acc_cond::mark_t acceptance_conditions,
state_ta_explicit* dest,
bool add_at_beginning = false);
void
delete_stuttering_transitions();
@ -115,27 +117,12 @@ namespace spot
return states_set_;
}
/// \brief Return the set of all acceptance conditions used
/// by this automaton.
///
/// The goal of the emptiness check is to ensure that
/// a strongly connected component walks through each
/// of these acceptiong conditions. I.e., the union
/// of the acceptiong conditions of all transition in
/// the SCC should be equal to the result of this function.
bdd
all_acceptance_conditions() const
{
return all_acceptance_conditions_;
}
private:
// Disallow copy.
ta_explicit(const ta_explicit& other) SPOT_DELETED;
ta_explicit& operator=(const ta_explicit& other) SPOT_DELETED;
const_tgba_ptr tgba_;
bdd all_acceptance_conditions_;
state_ta_explicit* artificial_initial_state_;
ta::states_set_t states_set_;
ta::states_set_t initial_states_set_;
@ -152,7 +139,7 @@ namespace spot
struct transition
{
bdd condition;
bdd acceptance_conditions;
acc_cond::mark_t acceptance_conditions;
state_ta_explicit* dest;
};
@ -255,7 +242,7 @@ namespace spot
virtual bdd
current_condition() const;
virtual bdd
virtual acc_cond::mark_t
current_acceptance_conditions() const;
private:
@ -267,13 +254,11 @@ namespace spot
typedef std::shared_ptr<const ta_explicit> const_ta_explicit_ptr;
inline ta_explicit_ptr make_ta_explicit(const const_tgba_ptr& tgba,
bdd all_acceptance_conditions,
unsigned n_acc,
state_ta_explicit*
artificial_initial_state = 0)
{
return std::make_shared<ta_explicit>(tgba,
all_acceptance_conditions,
artificial_initial_state);
return std::make_shared<ta_explicit>(tgba, n_acc, artificial_initial_state);
}
}

View file

@ -190,7 +190,7 @@ namespace spot
//if stuttering transition, the TA automata stays in the same state
current_state_ = new state_ta_product(source_->get_ta_state(),
kripke_current_dest_state->clone());
current_acceptance_conditions_ = bddfalse;
current_acceptance_conditions_ = 0U;
return true;
}
@ -232,7 +232,7 @@ namespace spot
return current_condition_;
}
bdd
acc_cond::mark_t
ta_succ_iterator_product::current_acceptance_conditions() const
{
return current_acceptance_conditions_;
@ -244,6 +244,7 @@ namespace spot
ta_product::ta_product(const const_ta_ptr& testing_automata,
const const_kripke_ptr& kripke_structure):
ta(testing_automata->get_dict()),
dict_(testing_automata->get_dict()),
ta_(testing_automata),
kripke_(kripke_structure)
@ -387,12 +388,6 @@ namespace spot
return is_hole_state;
}
bdd
ta_product::all_acceptance_conditions() const
{
return get_ta()->all_acceptance_conditions();
}
bdd
ta_product::get_state_condition(const spot::state* s) const
{

View file

@ -93,7 +93,7 @@ namespace spot
bdd
current_condition() const;
bdd
acc_cond::mark_t
current_acceptance_conditions() const;
/// \brief Return true if the changeset of the current transition is empty
@ -120,7 +120,7 @@ namespace spot
tgba_succ_iterator* kripke_succ_it_;
state_ta_product* current_state_;
bdd current_condition_;
bdd current_acceptance_conditions_;
acc_cond::mark_t current_acceptance_conditions_;
bool is_stuttering_transition_;
bdd kripke_source_condition;
state * kripke_current_dest_state;
@ -174,9 +174,6 @@ namespace spot
virtual bdd
get_state_condition(const spot::state* s) const;
virtual bdd
all_acceptance_conditions() const;
virtual void
free_state(const spot::state* s) const;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Développement
// Copyright (C) 2012, 2013, 2014 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
@ -22,11 +22,9 @@
namespace spot
{
tgta::tgta()
{};
tgta::~tgta()
{};
tgta::tgta(const bdd_dict_ptr& d)
: tgba(d)
{};
tgta::~tgta()
{};
}

View file

@ -62,9 +62,9 @@ namespace spot
{
protected:
tgta();
public:
tgta(const bdd_dict_ptr& d);
public:
virtual
~tgta();

View file

@ -30,10 +30,10 @@ namespace spot
{
tgta_explicit::tgta_explicit(const const_tgba_ptr& tgba,
bdd all_acceptance_conditions,
unsigned n_acc,
state_ta_explicit* artificial_initial_state) :
ta_(make_ta_explicit(tgba, all_acceptance_conditions,
artificial_initial_state))
tgta(tgba->get_dict()),
ta_(make_ta_explicit(tgba, n_acc, artificial_initial_state))
{
}
@ -63,18 +63,6 @@ namespace spot
return ta_->get_dict();
}
bdd
tgta_explicit::all_acceptance_conditions() const
{
return ta_->all_acceptance_conditions();
}
bdd
tgta_explicit::neg_acceptance_conditions() const
{
return ta_->get_tgba()->neg_acceptance_conditions();
}
std::string
tgta_explicit::format_state(const spot::state* s) const
{

View file

@ -39,7 +39,7 @@ namespace spot
{
public:
tgta_explicit(const const_tgba_ptr& tgba,
bdd all_acceptance_conditions,
unsigned n_acc,
state_ta_explicit* artificial_initial_state);
// tgba interface
@ -54,9 +54,6 @@ namespace spot
const_ta_explicit_ptr get_ta() const { return ta_; }
ta_explicit_ptr get_ta() { return ta_; }
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
virtual std::string format_state(const spot::state* s) const;
virtual tgba_succ_iterator*
@ -71,12 +68,11 @@ namespace spot
typedef std::shared_ptr<const tgta_explicit> const_tgta_explicit_ptr;
inline tgta_explicit_ptr make_tgta_explicit(const const_tgba_ptr& tgba,
bdd all_acceptance_conditions,
unsigned n_acc,
state_ta_explicit*
artificial_initial_state = 0)
{
return std::make_shared<tgta_explicit>(tgba,
all_acceptance_conditions,
return std::make_shared<tgta_explicit>(tgba, n_acc,
artificial_initial_state);
}
}

View file

@ -207,7 +207,7 @@ namespace spot
kripke_current_dest_state->clone(),
tgta_succ_it_->current_state(), pool_);
current_acceptance_conditions_
= tgta_succ_it_->current_acceptance_conditions();
= tgta_succ_it_->current_acceptance_conditions();
return true;
}
@ -244,7 +244,7 @@ namespace spot
return current_condition_;
}
bdd
acc_cond::mark_t
tgta_succ_iterator_product::current_acceptance_conditions() const
{
return current_acceptance_conditions_;

View file

@ -72,7 +72,7 @@ namespace spot
bdd
current_condition() const;
bdd
acc_cond::mark_t
current_acceptance_conditions() const;
private:
@ -96,7 +96,7 @@ namespace spot
tgba_succ_iterator* kripke_succ_it_;
state_product* current_state_;
bdd current_condition_;
bdd current_acceptance_conditions_;
acc_cond::mark_t current_acceptance_conditions_;
bdd kripke_source_condition;
state* kripke_current_dest_state;
};

View file

@ -106,9 +106,8 @@ namespace spot
if (label.empty())
label = "{}";
label += ("\n" +
bdd_format_accset(d, si->current_acceptance_conditions()));
label += "\n";
label += t_automata_->acc().format(si->current_acceptance_conditions());
os_ << " " << in << " -> " << out << " [label=\"";
escape_str(os_, label);

View file

@ -54,7 +54,7 @@ namespace spot
// * scc: (attribute) a stack of strongly connected components (SCC)
// * arc, a stack of acceptance conditions between each of these SCC,
std::stack<bdd> arc;
std::stack<acc_cond::mark_t> arc;
// * h: a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
@ -113,7 +113,7 @@ namespace spot
}
scc.push(++num);
arc.push(bddfalse);
arc.push(0U);
ta_succ_iterator_product* iter = a_->succ_iter(init);
iter->first();
@ -194,7 +194,7 @@ namespace spot
// Fetch the values destination state we are interested in...
state* dest = succ->current_state();
bdd acc_cond = succ->current_acceptance_conditions();
auto acc_cond = succ->current_acceptance_conditions();
bool curr_is_livelock_hole_state_in_ta_component =
(a_->is_hole_state_in_ta_component(curr))
@ -284,8 +284,8 @@ namespace spot
scc.top().condition |= acc_cond;
scc.rem().splice(scc.rem().end(), rem);
bool is_accepting_sscc = (scc.top().is_accepting)
|| (scc.top().condition == a_->all_acceptance_conditions());
bool is_accepting_sscc = scc.top().is_accepting
|| a_->acc().accepting(scc.top().condition);
if (is_accepting_sscc)
{
@ -294,25 +294,14 @@ namespace spot
<< a_->is_livelock_accepting_state(curr) << '\n';
trace
<< "PASS 1: scc.top().condition : "
<< bdd_format_accset(a_->get_dict(), scc.top().condition)
<< '\n';
<< scc.top().condition << '\n';
trace
<< "PASS 1: a_->all_acceptance_conditions() : "
<< (a_->all_acceptance_conditions()) << '\n';
<< "PASS 1: a_->acc().all_sets() : "
<< (a_->acc().all_sets()) << '\n';
trace
<< ("PASS 1 CYCLE and (scc.top().condition == "
"a_->all_acceptance_conditions()) : ")
<< (scc.top().condition
== a_->all_acceptance_conditions()) << std::endl;
trace
<< "PASS 1: bddtrue: " << (a_->all_acceptance_conditions()
== bddtrue) << '\n';
trace
<< "PASS 1: bddfalse: " << (a_->all_acceptance_conditions()
== bddfalse) << '\n';
<< ("PASS 1 CYCLE and accepting? ")
<< a_->acc().accepting(scc.top().condition)
<< std::endl;
clear(h, todo, ta_init_it_);
return true;
}

View file

@ -64,127 +64,149 @@ namespace spot
return out;
}
static std::string
format_hash_set(const hash_set* hs, const const_ta_ptr& aut)
{
std::ostringstream s;
dump_hash_set(hs, aut, s);
return s.str();
}
static std::string
format_hash_set(const hash_set* hs, const const_ta_ptr& aut)
{
std::ostringstream s;
dump_hash_set(hs, aut, s);
return s.str();
}
// From the base automaton and the list of sets, build the minimal
// automaton
static void
build_result(const const_ta_ptr& a, std::list<hash_set*>& sets,
tgba_digraph_ptr result_tgba, const ta_explicit_ptr& result)
{
// For each set, create a state in the tgbaulting automaton.
// For a state s, state_num[s] is the number of the state in the minimal
// automaton.
hash_map state_num;
std::list<hash_set*>::iterator sit;
unsigned num = 0;
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set::iterator hit;
hash_set* h = *sit;
for (hit = h->begin(); hit != h->end(); ++hit)
state_num[*hit] = num;
result_tgba->new_state();
++num;
}
// From the base automaton and the list of sets, build the minimal
// automaton
static void
build_result(const const_ta_ptr& a, std::list<hash_set*>& sets,
tgba_digraph_ptr result_tgba, const ta_explicit_ptr& result)
{
// For each set, create a state in the tgbaulting automaton.
// For a state s, state_num[s] is the number of the state in the minimal
// automaton.
hash_map state_num;
std::list<hash_set*>::iterator sit;
unsigned num = 0;
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set::iterator hit;
hash_set* h = *sit;
for (hit = h->begin(); hit != h->end(); ++hit)
state_num[*hit] = num;
result_tgba->new_state();
++num;
}
// For each transition in the initial automaton, add the corresponding
// transition in ta.
// For each transition in the initial automaton, add the corresponding
// transition in ta.
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set::iterator hit;
hash_set* h = *sit;
hit = h->begin();
const state* src = *hit;
unsigned src_num = state_num[src];
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set::iterator hit;
hash_set* h = *sit;
hit = h->begin();
const state* src = *hit;
unsigned src_num = state_num[src];
bdd tgba_condition = bddtrue;
bool is_initial_state = a->is_initial_state(src);
if ((a->get_artificial_initial_state() == 0) && is_initial_state)
tgba_condition = a->get_state_condition(src);
bool is_accepting_state = a->is_accepting_state(src);
bool is_livelock_accepting_state =
a->is_livelock_accepting_state(src);
bdd tgba_condition = bddtrue;
bool is_initial_state = a->is_initial_state(src);
if ((a->get_artificial_initial_state() == 0) && is_initial_state)
tgba_condition = a->get_state_condition(src);
bool is_accepting_state = a->is_accepting_state(src);
bool is_livelock_accepting_state =
a->is_livelock_accepting_state(src);
state_ta_explicit* new_src =
new state_ta_explicit(result_tgba->state_from_number(src_num),
tgba_condition, is_initial_state,
is_accepting_state,
is_livelock_accepting_state);
state_ta_explicit* new_src =
new state_ta_explicit(result_tgba->state_from_number(src_num),
tgba_condition, is_initial_state,
is_accepting_state,
is_livelock_accepting_state);
state_ta_explicit* ta_src = result->add_state(new_src);
state_ta_explicit* ta_src = result->add_state(new_src);
if (ta_src != new_src)
{
delete new_src;
}
else if (a->get_artificial_initial_state() != 0)
{
if (a->get_artificial_initial_state() == src)
result->set_artificial_initial_state(new_src);
}
else if (is_initial_state)
{
result->add_to_initial_states_set(new_src);
}
if (ta_src != new_src)
{
delete new_src;
}
else if (a->get_artificial_initial_state() != 0)
{
if (a->get_artificial_initial_state() == src)
result->set_artificial_initial_state(new_src);
}
else if (is_initial_state)
{
result->add_to_initial_states_set(new_src);
}
ta_succ_iterator* succit = a->succ_iter(src);
ta_succ_iterator* succit = a->succ_iter(src);
for (succit->first(); !succit->done(); succit->next())
{
const state* dst = succit->current_state();
hash_map::const_iterator i = state_num.find(dst);
for (succit->first(); !succit->done(); succit->next())
{
const state* dst = succit->current_state();
hash_map::const_iterator i = state_num.find(dst);
if (i == state_num.end()) // Ignore useless destinations.
continue;
if (i == state_num.end()) // Ignore useless destinations.
continue;
bdd tgba_condition = bddtrue;
is_initial_state = a->is_initial_state(dst);
if ((a->get_artificial_initial_state() == 0) && is_initial_state)
tgba_condition = a->get_state_condition(dst);
bool is_accepting_state = a->is_accepting_state(dst);
bool is_livelock_accepting_state =
a->is_livelock_accepting_state(dst);
bdd tgba_condition = bddtrue;
is_initial_state = a->is_initial_state(dst);
if ((a->get_artificial_initial_state() == 0) && is_initial_state)
tgba_condition = a->get_state_condition(dst);
bool is_accepting_state = a->is_accepting_state(dst);
bool is_livelock_accepting_state =
a->is_livelock_accepting_state(dst);
state_ta_explicit* new_dst =
new state_ta_explicit(result_tgba->state_from_number(i->second),
tgba_condition, is_initial_state,
is_accepting_state,
is_livelock_accepting_state);
state_ta_explicit* new_dst =
new state_ta_explicit
(result_tgba->state_from_number(i->second),
tgba_condition, is_initial_state,
is_accepting_state,
is_livelock_accepting_state);
state_ta_explicit* ta_dst = result->add_state(new_dst);
state_ta_explicit* ta_dst = result->add_state(new_dst);
if (ta_dst != new_dst)
{
delete new_dst;
}
else if (a->get_artificial_initial_state() != 0)
{
if (a->get_artificial_initial_state() == dst)
result->set_artificial_initial_state(new_dst);
}
if (ta_dst != new_dst)
{
delete new_dst;
}
else if (a->get_artificial_initial_state() != 0)
{
if (a->get_artificial_initial_state() == dst)
result->set_artificial_initial_state(new_dst);
}
else if (is_initial_state)
result->add_to_initial_states_set(new_dst);
else if (is_initial_state)
result->add_to_initial_states_set(new_dst);
result->create_transition(ta_src, succit->current_condition(),
succit->current_acceptance_conditions(),
ta_dst);
}
delete succit;
}
}
result->create_transition
(ta_src, succit->current_condition(),
succit->current_acceptance_conditions(),
ta_dst);
}
delete succit;
}
}
static partition_t
build_partition(const const_ta_ptr& ta_)
{
unsigned num_sets = ta_->acc().num_sets();
std::map<acc_cond::mark_t, bdd> m2b;
int acc_vars = ta_->get_dict()->register_anonymous_variables(num_sets,
&m2b);
auto mark_to_bdd = [&](acc_cond::mark_t m) -> bdd
{
auto i = m2b.find(m);
if (i != m2b.end())
return i->second;
bdd res = bddtrue;
for (unsigned n = 0; n < num_sets; ++n)
if (m.has(n))
res &= bdd_ithvar(acc_vars + n);
else
res &= bdd_nithvar(acc_vars + n);
m2b.emplace_hint(i, m, res);
return res;
};
partition_t cur_run;
partition_t next_run;
@ -237,7 +259,7 @@ namespace spot
// Use bdd variables to number sets. set_num is the first variable
// available.
unsigned set_num =
ta_->get_dict()->register_anonymous_variables(size, ta_);
ta_->get_dict()->register_anonymous_variables(size, &m2b);
std::set<int> free_var;
for (unsigned i = set_num; i < set_num + size; ++i)
@ -335,6 +357,7 @@ namespace spot
delete S;
}
// A bdd_states_map is a list of formulae (in a BDD form)
// associated with a destination set of states.
typedef std::map<bdd, hash_set*, bdd_less_than> bdd_states_map;
@ -372,13 +395,10 @@ namespace spot
hash_map::const_iterator i = state_set_map.find(dst);
assert(i != state_set_map.end());
bdd current_acceptance_conditions =
si->current_acceptance_conditions();
if (current_acceptance_conditions == bddfalse)
current_acceptance_conditions
= bdd_false_acceptance_condition;
f |= (bdd_ithvar(i->second) & si->current_condition()
& current_acceptance_conditions);
auto curacc =
mark_to_bdd(si->current_acceptance_conditions());
f |= (bdd_ithvar(i->second)
& si->current_condition() & curacc);
trace
<< "+f: " << bdd_format_accset(ta_->get_dict(), f)
<< "\n -bdd_ithvar(i->second): "
@ -388,9 +408,8 @@ namespace spot
<< bdd_format_accset(ta_->get_dict(),
si->current_condition())
<< "\n -current_acceptance_conditions: "
<< bdd_format_accset(ta_->get_dict(),
current_acceptance_conditions)
<< std::endl;
<< si->current_acceptance_conditions()
<< std::endl;
}
delete si;
@ -480,6 +499,7 @@ namespace spot
trace << std::endl;
#endif
ta_->get_dict()->unregister_all_my_variables(&m2b);
return done;
}
}
@ -489,7 +509,7 @@ namespace spot
{
auto tgba = make_tgba_digraph(ta_->get_dict());
auto res = make_ta_explicit(tgba, ta_->all_acceptance_conditions(), 0);
auto res = make_ta_explicit(tgba, ta_->acc().num_sets(), 0);
partition_t partition = build_partition(ta_);
@ -509,7 +529,7 @@ namespace spot
{
auto tgba = make_tgba_digraph(tgta_->get_dict());
auto res = make_tgta_explicit(tgba, tgta_->all_acceptance_conditions(), 0);
auto res = make_tgta_explicit(tgba, tgta_->acc().num_sets(), 0);
auto ta = tgta_->get_ta();

View file

@ -148,7 +148,7 @@ namespace spot
}
static void
compute_livelock_acceptance_states(const ta_explicit_ptr& testing_automata,
compute_livelock_acceptance_states(const ta_explicit_ptr& testing_aut,
bool single_pass_emptiness_check,
state_ta_explicit*
artificial_livelock_acc_state)
@ -158,7 +158,7 @@ namespace spot
scc_stack_ta sscc;
// * arc, a stack of acceptance conditions between each of these SCC,
std::stack<bdd> arc;
std::stack<acc_cond::mark_t> arc;
// * h: a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
@ -180,7 +180,7 @@ namespace spot
// * init: the set of the depth-first search initial states
std::stack<state*> init_set;
for (state* s: testing_automata->get_initial_states_set())
for (state* s: testing_aut->get_initial_states_set())
init_set.push(s);
while (!init_set.empty())
@ -199,10 +199,10 @@ namespace spot
}
sscc.push(++num);
arc.push(bddfalse);
arc.push(0U);
sscc.top().is_accepting
= testing_automata->is_accepting_state(init);
tgba_succ_iterator* iter = testing_automata->succ_iter(init);
= testing_aut->is_accepting_state(init);
tgba_succ_iterator* iter = testing_aut->succ_iter(init);
iter->first();
todo.emplace(init, iter);
}
@ -243,10 +243,9 @@ namespace spot
// removing states
std::list<state*>::iterator i;
bool is_livelock_accepting_sscc = (sscc.rem().size() > 1)
&& ((sscc.top().is_accepting)
|| (sscc.top().condition ==
testing_automata->all_acceptance_conditions()));
&& ((sscc.top().is_accepting) ||
(testing_aut->acc().
accepting(sscc.top().condition)));
trace << "*** sscc.size() = ***" << sscc.size() << '\n';
for (auto j: sscc.rem())
{
@ -257,7 +256,7 @@ namespace spot
// if it is an accepting sscc add the state to
// G (=the livelock-accepting states set)
trace << "*** sscc.size() > 1: states: ***"
<< testing_automata->format_state(j)
<< testing_aut->format_state(j)
<< '\n';
state_ta_explicit* livelock_accepting_state =
down_cast<state_ta_explicit*>(j);
@ -283,7 +282,7 @@ namespace spot
}
// automata reduction
testing_automata->delete_stuttering_and_hole_successors(curr);
testing_aut->delete_stuttering_and_hole_successors(curr);
delete succ;
// Do not delete CURR: it is a key in H.
@ -293,7 +292,7 @@ namespace spot
// Fetch the values destination state we are interested in...
state* dest = succ->current_state();
bdd acc_cond = succ->current_acceptance_conditions();
auto acc_cond = succ->current_acceptance_conditions();
// ... and point the iterator to the next successor, for
// the next iteration.
succ->next();
@ -301,8 +300,8 @@ namespace spot
// Are we going to a new state through a stuttering transition?
bool is_stuttering_transition =
testing_automata->get_state_condition(curr)
== testing_automata->get_state_condition(dest);
testing_aut->get_state_condition(curr)
== testing_aut->get_state_condition(dest);
auto id = h.find(dest);
// Is this a new state?
@ -321,9 +320,9 @@ namespace spot
sscc.push(num);
arc.push(acc_cond);
sscc.top().is_accepting =
testing_automata->is_accepting_state(dest);
testing_aut->is_accepting_state(dest);
tgba_succ_iterator* iter = testing_automata->succ_iter(dest);
tgba_succ_iterator* iter = testing_aut->succ_iter(dest);
iter->first();
todo.emplace(dest, iter);
continue;
@ -342,9 +341,8 @@ namespace spot
down_cast<state_ta_explicit*> (curr);
assert(self_loop_state);
if (testing_automata->is_accepting_state(self_loop_state)
|| (acc_cond
== testing_automata->all_acceptance_conditions()))
if (testing_aut->is_accepting_state(self_loop_state)
|| (testing_aut->acc().accepting(acc_cond)))
{
self_loop_state->set_livelock_accepting_state(true);
if (single_pass_emptiness_check)
@ -404,7 +402,7 @@ namespace spot
if ((artificial_livelock_acc_state != 0)
|| single_pass_emptiness_check)
transform_to_single_pass_automaton(testing_automata,
transform_to_single_pass_automaton(testing_aut,
artificial_livelock_acc_state);
}
@ -429,7 +427,7 @@ namespace spot
tgba_succ_iterator* it = tgba_->succ_iter(tgba_init_state);
it->first();
if (!it->done())
is_acc = it->current_acceptance_conditions() != bddfalse;
is_acc = it->current_acceptance_conditions() != 0U;
delete it;
}
@ -462,7 +460,7 @@ namespace spot
{
const state* tgba_state = tgba_succ_it->current_state();
bdd tgba_condition = tgba_succ_it->current_condition();
bdd tgba_acceptance_conditions =
acc_cond::mark_t tgba_acceptance_conditions =
tgba_succ_it->current_acceptance_conditions();
bdd satone_tgba_condition;
while ((satone_tgba_condition =
@ -481,7 +479,7 @@ namespace spot
tgba_succ_iterator* it = tgba_->succ_iter(tgba_state);
it->first();
if (!it->done())
is_acc = it->current_acceptance_conditions() != bddfalse;
is_acc = it->current_acceptance_conditions() != 0U;
delete it;
}
@ -554,12 +552,12 @@ namespace spot
state_ta_explicit* artificial_init_state =
new state_ta_explicit(tgba_init_state->clone(), bddfalse, true);
ta = make_ta_explicit(tgba_, tgba_->all_acceptance_conditions(),
ta = make_ta_explicit(tgba_, tgba_->acc().num_sets(),
artificial_init_state);
}
else
{
ta = make_ta_explicit(tgba_, tgba_->all_acceptance_conditions());
ta = make_ta_explicit(tgba_, tgba_->acc().num_sets());
}
tgba_init_state->destroy();
@ -586,10 +584,7 @@ namespace spot
for (it_trans = trans->begin(); it_trans != trans->end();
++it_trans)
{
(*it_trans)->acceptance_conditions
= ta->all_acceptance_conditions();
}
(*it_trans)->acceptance_conditions = ta->acc().all_sets();
state->set_accepting_state(false);
}
@ -606,7 +601,7 @@ namespace spot
bddfalse, true);
tgba_init_state->destroy();
auto tgta = make_tgta_explicit(tgba_, tgba_->all_acceptance_conditions(),
auto tgta = make_tgta_explicit(tgba_, tgba_->acc().num_sets(),
artificial_init_state);
// build a Generalized TA automaton involving a single_pass_emptiness_check
@ -644,13 +639,13 @@ namespace spot
if (trans_empty || state->is_accepting_state())
{
ta->create_transition(state, bdd_stutering_transition,
ta->all_acceptance_conditions(), state);
ta->acc().all_sets(), state);
}
}
if (state->compare(ta->get_artificial_initial_state()))
ta->create_transition(state, bdd_stutering_transition,
bddfalse, state);
0U, state);
state->set_livelock_accepting_state(false);
state->set_accepting_state(false);

View file

@ -26,6 +26,7 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS)
tgbadir = $(pkgincludedir)/tgba
tgba_HEADERS = \
acc.hh \
bdddict.hh \
bddprint.hh \
formula2bdd.hh \
@ -33,11 +34,9 @@ tgba_HEADERS = \
taatgba.hh \
tgba.hh \
tgbagraph.hh \
tgbakvcomplement.hh \
tgbamask.hh \
tgbaproxy.hh \
tgbaproduct.hh \
tgbasgba.hh \
tgbasafracomplement.hh
noinst_LTLIBRARIES = libtgba.la
@ -48,9 +47,7 @@ libtgba_la_SOURCES = \
taatgba.cc \
tgba.cc \
tgbagraph.cc \
tgbakvcomplement.cc \
tgbaproduct.cc \
tgbamask.cc \
tgbaproxy.cc \
tgbasafracomplement.cc \
tgbasgba.cc
tgbasafracomplement.cc

433
src/tgba/acc.hh Normal file
View file

@ -0,0 +1,433 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2014 Laboratoire de Recherche et Développement de
// l'Epita.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SPOT_TGBA_ACC_HH
# define SPOT_TGBA_ACC_HH
# include <functional>
# include <unordered_map>
# include <sstream>
# include "bdddict.hh"
# include "ltlenv/defaultenv.hh"
namespace spot
{
class acc_cond
{
public:
struct mark_t
{
typedef unsigned value_t;
value_t id;
mark_t() = default;
mark_t(value_t id)
: id(id)
{
}
bool operator==(unsigned o) const
{
assert(o == 0U);
return id == o;
}
bool operator!=(unsigned o) const
{
assert(o == 0U);
return id != o;
}
bool operator==(mark_t o) const
{
return id == o.id;
}
bool operator!=(mark_t o) const
{
return id != o.id;
}
bool operator<(mark_t o) const
{
return id < o.id;
}
bool operator<=(mark_t o) const
{
return id <= o.id;
}
bool operator>(mark_t o) const
{
return id > o.id;
}
bool operator>=(mark_t o) const
{
return id >= o.id;
}
operator bool() const
{
return id != 0;
}
bool has(unsigned u) const
{
return id & (1U << u);
}
mark_t& operator&=(mark_t r)
{
id &= r.id;
return *this;
}
mark_t& operator|=(mark_t r)
{
id |= r.id;
return *this;
}
mark_t& operator-=(mark_t r)
{
id &= ~r.id;
return *this;
}
mark_t operator&(mark_t r) const
{
return id & r.id;
}
mark_t operator|(mark_t r) const
{
return id | r.id;
}
mark_t operator-(mark_t r) const
{
return id & ~r.id;
}
// Number of bits sets.
unsigned count() const
{
#ifdef __GNUC__
return __builtin_popcount(id);
#else
unsigned c = 0U;
auto v = id;
while (v)
{
++c;
v &= v - 1;
}
return c;
#endif
}
// Remove n bits that where set
mark_t& remove_some(unsigned n)
{
while (n--)
id &= id - 1;
return *this;
}
friend std::ostream& operator<<(std::ostream& os, mark_t m)
{
auto a = m.id;
os << '{';
unsigned level = 0;
const char* comma = "";
while (a)
{
if (a & 1)
{
os << comma << level;
comma = ",";
}
a >>= 1;
++level;
}
os << '}';
return os;
}
};
acc_cond(const bdd_dict_ptr& dict, unsigned n_sets = 0)
: d_(dict), num_(0U), all_(0U)
{
add_sets(n_sets);
}
acc_cond(const acc_cond& o)
: num_(o.num_), all_(o.all_)
{
}
~acc_cond()
{
}
const bdd_dict_ptr& get_dict() const
{
return d_;
}
unsigned add_sets(unsigned num)
{
if (num == 0)
return -1U;
unsigned j = num_;
num_ += num;
if (num_ > 8 * sizeof(mark_t::id))
throw std::runtime_error("Too many acceptance sets used.");
all_ = all_sets_();
return j;
}
unsigned add_set()
{
return add_sets(1);
}
mark_t mark(unsigned u) const
{
return out(mark_(u));
}
template<class iterator>
mark_t marks(const iterator& begin, const iterator& end) const
{
mark_t::value_t res = 0U;
for (iterator i = begin; i != end; ++i)
res |= mark_(*i);
return out(res);
}
mark_t marks(std::initializer_list<unsigned> vals) const
{
return marks(vals.begin(), vals.end());
}
template<class iterator>
void fill_from(mark_t m, iterator here) const
{
auto a = in(m);
unsigned level = 0;
while (a)
{
if (a & 1)
*here++ = level;
++level;
a >>= 1;
}
assert(level <= num_sets());
}
// FIXME: Return some iterable object without building a vector.
std::vector<unsigned> sets(mark_t m) const
{
std::vector<unsigned> res;
fill_from(m, std::back_inserter(res));
return res;
}
// whether m contains u
bool has(mark_t m, unsigned u) const
{
return m.has(u);
}
mark_t cup(mark_t l, mark_t r) const
{
return l | r;
}
mark_t cap(mark_t l, mark_t r) const
{
return l & r;
}
mark_t set_minus(mark_t l, mark_t r) const
{
return l - r;
}
mark_t join(const acc_cond& la, mark_t lm,
const acc_cond& ra, mark_t rm) const
{
assert(la.num_sets() + ra.num_sets() == num_sets());
return la.in(lm) | (ra.in(rm) << la.num_sets());
}
mark_t comp(mark_t l) const
{
return out(all_ ^ in(l));
}
mark_t all_sets() const
{
return out(all_);
}
bool accepting(mark_t inf) const
{
return in(inf) == all_;
}
std::ostream& format_quoted(std::ostream& os, mark_t m) const
{
auto a = in(m);
if (a == 0U)
return os;
unsigned level = 0;
const char* space = "";
while (a)
{
if (a & 1)
{
os << space << '"' << level << '"';
space = " ";
}
a >>= 1;
++level;
}
return os;
}
std::ostream& format(std::ostream& os, mark_t m) const
{
auto a = in(m);
if (a == 0U)
return os;
return os << m;
}
std::string format(mark_t m) const
{
std::ostringstream os;
format(os, m);
return os.str();
}
unsigned num_sets() const
{
return num_;
}
template<class iterator>
mark_t useless(iterator begin, iterator end) const
{
mark_t::value_t u = 0U; // The set of useless marks.
for (unsigned x = 0; x < num_; ++x)
{
// Skip marks that are already known to be useless.
if (u & (1 << x))
continue;
unsigned all = all_ ^ (u | (1 << x));
for (iterator y = begin; y != end; ++y)
{
auto v = in(*y);
if (v & (1 << x))
{
all &= v;
if (!all)
break;
}
}
u |= all;
}
return out(u);
}
mark_t strip(mark_t x, mark_t y) const
{
// strip every bit of x that is marked in y
// strip(100101110100,
// 001011001000)
// == 10 1 11 100
// == 10111100
auto xv = in(x); // 100101110100
auto yv = in(y); // 001011001000
while (yv && xv)
{
// Mask for everything after the last 1 in y
auto rm = (~yv) & (yv - 1); // 000000000111
// Mask for everything before the last 1 in y
auto lm = ~(yv ^ (yv - 1)); // 111111110000
xv = ((xv & lm) >> 1) | (xv & rm);
yv = (yv & lm) >> 1;
}
return out(xv);
}
protected:
mark_t::value_t mark_(unsigned u) const
{
assert(u < num_sets());
return 1U << u;
}
mark_t::value_t all_sets_() const
{
if (num_ == 0)
return 0;
return -1U >> (8 * sizeof(mark_t::value_t) - num_);
}
mark_t::value_t in(mark_t m) const
{
return m.id;
}
mark_t out(mark_t::value_t r) const
{
return r;
}
bdd_dict_ptr d_;
unsigned num_;
mark_t::value_t all_;
};
}
namespace std
{
template<>
struct hash<spot::acc_cond::mark_t>
{
size_t operator()(spot::acc_cond::mark_t m) const
{
std::hash<decltype(m.id)> h;
return h(m.id);
}
};
}
#endif // SPOT_TGBA_ACC_HH

View file

@ -35,10 +35,6 @@ namespace spot
class tgba_product;
typedef std::shared_ptr<const tgba_product> const_tgba_product_ptr;
typedef std::shared_ptr<tgba_product> tgba_product_ptr;
class tgba_sgba_proxy;
typedef std::shared_ptr<const tgba_sgba_proxy> const_tgba_sgba_proxy_ptr;
typedef std::shared_ptr<tgba_sgba_proxy> tgba_sgba_proxy_ptr;
}
#endif // SPOT_TGBA_FWD_HH

View file

@ -34,10 +34,7 @@ namespace spot
`--------*/
taa_tgba::taa_tgba(const bdd_dict_ptr& dict)
: dict_(dict),
all_acceptance_conditions_(bddfalse),
all_acceptance_conditions_computed_(false),
neg_acceptance_conditions_(bddtrue),
: tgba(dict),
init_(0), state_set_vec_()
{
}
@ -47,13 +44,13 @@ namespace spot
ss_vec::iterator j;
for (j = state_set_vec_.begin(); j != state_set_vec_.end(); ++j)
delete *j;
dict_->unregister_all_my_variables(this);
get_dict()->unregister_all_my_variables(this);
}
void
taa_tgba::add_condition(transition* t, const ltl::formula* f)
{
t->condition &= formula_to_bdd(f, dict_, this);
t->condition &= formula_to_bdd(f, get_dict(), this);
f->destroy();
}
@ -69,31 +66,7 @@ namespace spot
{
const spot::set_state* s = down_cast<const spot::set_state*>(state);
assert(s);
return new taa_succ_iterator(s->get_state(), all_acceptance_conditions());
}
bdd_dict_ptr
taa_tgba::get_dict() const
{
return dict_;
}
bdd
taa_tgba::all_acceptance_conditions() const
{
if (!all_acceptance_conditions_computed_)
{
all_acceptance_conditions_ =
compute_all_acceptance_conditions(neg_acceptance_conditions_);
all_acceptance_conditions_computed_ = true;
}
return all_acceptance_conditions_;
}
bdd
taa_tgba::neg_acceptance_conditions() const
{
return neg_acceptance_conditions_;
return new taa_succ_iterator(s->get_state(), acc_);
}
bdd
@ -172,14 +145,14 @@ namespace spot
`--------------*/
taa_succ_iterator::taa_succ_iterator(const taa_tgba::state_set* s,
bdd all_acc)
: all_acceptance_conditions_(all_acc), seen_()
const acc_cond& acc)
: seen_(), acc_(acc)
{
if (s->empty())
{
taa_tgba::transition* t = new taa_tgba::transition;
t->condition = bddtrue;
t->acceptance_conditions = bddfalse;
t->acceptance_conditions = 0U;
t->dst = new taa_tgba::state_set;
succ_.push_back(t);
return;
@ -202,7 +175,7 @@ namespace spot
{
taa_tgba::transition* t = new taa_tgba::transition;
t->condition = bddtrue;
t->acceptance_conditions = bddfalse;
t->acceptance_conditions = 0U;
taa_tgba::state_set* ss = new taa_tgba::state_set;
unsigned p;
@ -330,12 +303,11 @@ namespace spot
return (*i_)->condition;
}
bdd
acc_cond::mark_t
taa_succ_iterator::current_acceptance_conditions() const
{
assert(!done());
return all_acceptance_conditions_ -
((*i_)->acceptance_conditions & all_acceptance_conditions_);
return acc_.comp((*i_)->acceptance_conditions);
}
/*----------------.

View file

@ -27,6 +27,7 @@
#include "ltlast/formula.hh"
#include "bdddict.hh"
#include "tgba.hh"
#include "ltlvisit/tostring.hh"
namespace spot
{
@ -45,7 +46,7 @@ namespace spot
struct transition
{
bdd condition;
bdd acceptance_conditions;
acc_cond::mark_t acceptance_conditions;
const state_set* dst;
};
@ -55,23 +56,19 @@ namespace spot
virtual ~taa_tgba();
virtual spot::state* get_init_state() const;
virtual tgba_succ_iterator* succ_iter(const spot::state* state) const;
virtual bdd_dict_ptr get_dict() const;
virtual std::string format_state(const spot::state* state) const = 0;
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
protected:
virtual bdd compute_support_conditions(const spot::state* state) const;
typedef std::vector<taa_tgba::state_set*> ss_vec;
bdd_dict_ptr dict_;
mutable bdd all_acceptance_conditions_;
mutable bool all_acceptance_conditions_computed_;
bdd neg_acceptance_conditions_;
taa_tgba::state_set* init_;
ss_vec state_set_vec_;
std::map<const ltl::formula*, acc_cond::mark_t,
ltl::formula_ptr_less_than> acc_map_;
private:
// Disallow copy.
taa_tgba(const taa_tgba& other) SPOT_DELETED;
@ -106,7 +103,7 @@ namespace spot
class SPOT_API taa_succ_iterator : public tgba_succ_iterator
{
public:
taa_succ_iterator(const taa_tgba::state_set* s, bdd all_acc);
taa_succ_iterator(const taa_tgba::state_set* s, const acc_cond& acc);
virtual ~taa_succ_iterator();
virtual bool first();
@ -115,7 +112,7 @@ namespace spot
virtual set_state* current_state() const;
virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const;
virtual acc_cond::mark_t current_acceptance_conditions() const;
private:
/// Those typedefs are used to generate all possible successors in
@ -141,8 +138,8 @@ namespace spot
std::vector<taa_tgba::transition*>::const_iterator i_;
std::vector<taa_tgba::transition*> succ_;
bdd all_acceptance_conditions_;
seen_map seen_;
const acc_cond& acc_;
};
/// A taa_tgba instance with states labeled by a given type.
@ -153,6 +150,13 @@ namespace spot
public:
taa_tgba_labelled(const bdd_dict_ptr& dict) : taa_tgba(dict) {};
~taa_tgba_labelled()
{
auto i = acc_map_.begin();
while (i != acc_map_.end())
(i++)->first->destroy();
}
void set_init_state(const label& s)
{
std::vector<label> v(1);
@ -173,10 +177,11 @@ namespace spot
transition* t = new transition;
t->dst = dst;
t->condition = bddtrue;
t->acceptance_conditions = bddfalse;
t->acceptance_conditions = 0U;
src->push_back(t);
return t;
}
transition*
create_transition(const label& s, const label& d)
{
@ -187,29 +192,12 @@ namespace spot
void add_acceptance_condition(transition* t, const ltl::formula* f)
{
if (dict_->acc_map.find(f) == dict_->acc_map.end())
{
int v = dict_->register_acceptance_variable(f, this);
bdd neg = bdd_nithvar(v);
neg_acceptance_conditions_ &= neg;
// Append neg to all acceptance conditions.
typename ns_map::iterator i;
for (i = name_state_map_.begin(); i != name_state_map_.end(); ++i)
{
taa_tgba::state::iterator i2;
for (i2 = i->second->begin(); i2 != i->second->end(); ++i2)
(*i2)->acceptance_conditions &= neg;
}
all_acceptance_conditions_computed_ = false;
}
bdd_dict::fv_map::iterator i = dict_->acc_map.find(f);
assert(i != dict_->acc_map.end());
f->destroy();
bdd v = bdd_ithvar(i->second);
t->acceptance_conditions |= v & bdd_exist(neg_acceptance_conditions_, v);
auto p = acc_map_.emplace(f, 0);
if (p.second)
p.first->second = acc_.marks({acc_.add_set()});
else
f->destroy();
t->acceptance_conditions |= p.first->second;
}
/// \brief Format the state as a string for printing.

View file

@ -25,10 +25,10 @@
namespace spot
{
tgba::tgba()
tgba::tgba(const bdd_dict_ptr& d)
: iter_cache_(nullptr),
last_support_conditions_input_(0),
num_acc_(-1)
acc_(d),
last_support_conditions_input_(0)
{
props = 0U;
}
@ -69,23 +69,6 @@ namespace spot
return "";
}
unsigned int
tgba::number_of_acceptance_conditions() const
{
if (num_acc_ < 0)
{
bdd all = all_acceptance_conditions();
unsigned int n = 0;
while (all != bddfalse)
{
++n;
all -= bdd_satone(all);
}
num_acc_ = n;
}
return num_acc_;
}
bool
tgba::is_empty() const
{

View file

@ -23,8 +23,8 @@
#ifndef SPOT_TGBA_TGBA_HH
# define SPOT_TGBA_TGBA_HH
#include "bdddict.hh"
#include "fwd.hh"
#include "acc.hh"
#include <cassert>
#include <memory>
#include "misc/casts.hh"
@ -387,7 +387,7 @@ namespace spot
virtual bdd current_condition() const = 0;
/// \brief Get the acceptance conditions on the transition leading
/// to this successor.
virtual bdd current_acceptance_conditions() const = 0;
virtual acc_cond::mark_t current_acceptance_conditions() const = 0;
//@}
};
@ -467,7 +467,7 @@ namespace spot
class SPOT_API tgba: public std::enable_shared_from_this<tgba>
{
protected:
tgba();
tgba(const bdd_dict_ptr& d);
// Any iterator returned via release_iter.
mutable tgba_succ_iterator* iter_cache_;
@ -572,7 +572,10 @@ namespace spot
/// formulae, and vice versa. This is useful when dealing with
/// several automata (which may use the same BDD variable for
/// different formula), or simply when printing.
virtual bdd_dict_ptr get_dict() const = 0;
bdd_dict_ptr get_dict() const
{
return acc_.get_dict();
}
/// \brief Format the state as a string for printing.
///
@ -615,40 +618,27 @@ namespace spot
virtual state* project_state(const state* s,
const const_tgba_ptr& t) const;
/// \brief Return the set of all acceptance conditions used
/// by this automaton.
///
/// The goal of the emptiness check is to ensure that
/// a strongly connected component walks through each
/// of these acceptiong conditions. I.e., the union
/// of the acceptiong conditions of all transition in
/// the SCC should be equal to the result of this function.
virtual bdd all_acceptance_conditions() const = 0;
/// The number of acceptance conditions.
virtual unsigned int number_of_acceptance_conditions() const;
const acc_cond& acc() const
{
return acc_;
}
/// \brief Return the conjuction of all negated acceptance
/// variables.
///
/// For instance if the automaton uses variables <tt>Acc[a]</tt>,
/// <tt>Acc[b]</tt> and <tt>Acc[c]</tt> to describe acceptance sets,
/// this function should return <tt>!Acc[a]\&!Acc[b]\&!Acc[c]</tt>.
///
/// This is useful when making products: each operand's condition
/// set should be augmented with the neg_acceptance_conditions() of
/// the other operand.
virtual bdd neg_acceptance_conditions() const = 0;
acc_cond& acc()
{
return acc_;
}
virtual bool is_empty() const;
protected:
acc_cond acc_;
/// Do the actual computation of tgba::support_conditions().
virtual bdd compute_support_conditions(const state* state) const = 0;
mutable const state* last_support_conditions_input_;
private:
mutable bdd last_support_conditions_output_;
mutable int num_acc_;
protected:

View file

@ -23,41 +23,6 @@
namespace spot
{
void tgba_digraph::set_acceptance_conditions(bdd all)
{
if (all_acceptance_conditions_ != bddfalse)
dict_->unregister_all_typed_variables(bdd_dict::acc, this);
bdd sup = bdd_support(all);
dict_->register_acceptance_variables(sup, this);
neg_acceptance_conditions_ = bddtrue;
while (sup != bddtrue)
{
neg_acceptance_conditions_ &= bdd_nithvar(bdd_var(sup));
sup = bdd_high(sup);
}
all_acceptance_conditions_ =
compute_all_acceptance_conditions(neg_acceptance_conditions_);
prop_single_acc_set(number_of_acceptance_conditions() == 1);
}
bdd tgba_digraph::set_single_acceptance_set()
{
if (all_acceptance_conditions_ != bddfalse)
dict_->unregister_all_typed_variables(bdd_dict::acc, this);
prop_single_acc_set();
int accvar =
dict_->register_acceptance_variable(ltl::constant::true_instance(),
this);
bdd degen_acc = bdd_ithvar(accvar);
all_acceptance_conditions_ = degen_acc;
neg_acceptance_conditions_ = bdd_nithvar(accvar);
return degen_acc;
}
void tgba_digraph::merge_transitions()
{
for (auto& s: g_.states())
@ -65,7 +30,7 @@ namespace spot
// Map a pair (dest state, acc) to the first transition seen
// with such characteristic.
typedef std::pair<graph_t::state, int> key_t;
typedef std::pair<graph_t::state, acc_cond::mark_t> key_t;
std::unordered_map<key_t, graph_t::transition, pair_hash> trmap;
auto t = g_.out_iteraser(s);
@ -78,7 +43,7 @@ namespace spot
continue;
}
key_t k(t->dst, t->acc.id());
key_t k(t->dst, t->acc);
auto p = trmap.emplace(k, t.trans());
if (!p.second)
{

View file

@ -76,14 +76,14 @@ namespace spot
struct SPOT_API tgba_graph_trans_data
{
bdd cond;
bdd acc;
acc_cond::mark_t acc;
explicit tgba_graph_trans_data()
: cond(bddfalse), acc(bddfalse)
: cond(bddfalse), acc(0)
{
}
tgba_graph_trans_data(bdd cond, bdd acc = bddfalse)
tgba_graph_trans_data(bdd cond, acc_cond::mark_t acc = 0U)
: cond(cond), acc(acc)
{
}
@ -141,7 +141,7 @@ namespace spot
return g_->trans_data(p_).cond;
}
virtual bdd current_acceptance_conditions() const
virtual acc_cond::mark_t current_acceptance_conditions() const
{
assert(!done());
return g_->trans_data(p_).acc;
@ -161,23 +161,18 @@ namespace spot
protected:
graph_t g_;
bdd_dict_ptr dict_;
bdd all_acceptance_conditions_;
bdd neg_acceptance_conditions_;
mutable unsigned init_number_;
public:
tgba_digraph(const bdd_dict_ptr& dict)
: dict_(dict),
all_acceptance_conditions_(bddfalse),
neg_acceptance_conditions_(bddtrue),
: tgba(dict),
init_number_(0)
{
}
virtual ~tgba_digraph()
{
dict_->unregister_all_my_variables(this);
get_dict()->unregister_all_my_variables(this);
// Prevent this state from being destroyed by ~tgba(),
// as the state will be destroyed when g_ is destroyed.
last_support_conditions_input_ = 0;
@ -212,11 +207,6 @@ namespace spot
return g_;
}
virtual bdd_dict_ptr get_dict() const
{
return this->dict_;
}
unsigned num_states() const
{
return g_.num_states();
@ -314,8 +304,22 @@ namespace spot
return g_.trans_data(t);
}
void set_acceptance_conditions(bdd all);
bdd set_single_acceptance_set();
void set_acceptance_conditions(unsigned num)
{
if (num < acc_.num_sets())
{
acc_.~acc_cond();
new (&acc_) acc_cond(get_dict());
}
acc_.add_sets(num - acc_.num_sets());
prop_single_acc_set(num == 1);
}
acc_cond::mark_t set_single_acceptance_set()
{
set_acceptance_conditions(1);
return acc_.mark(0);
}
unsigned new_state()
{
@ -328,7 +332,7 @@ namespace spot
}
unsigned new_transition(unsigned src, unsigned dst,
bdd cond, bdd acc = bddfalse)
bdd cond, acc_cond::mark_t acc = 0U)
{
return g_.new_transition(src, dst, cond, acc);
}
@ -337,7 +341,7 @@ namespace spot
bdd cond, bool acc = true)
{
if (acc)
return g_.new_transition(src, dst, cond, all_acceptance_conditions_);
return g_.new_transition(src, dst, cond, acc_.all_sets());
else
return g_.new_transition(src, dst, cond);
}
@ -364,22 +368,13 @@ namespace spot
/// \brief Copy the acceptance conditions of another tgba.
void copy_acceptance_conditions_of(const const_tgba_ptr& a)
{
set_acceptance_conditions(a->neg_acceptance_conditions());
assert(acc_.num_sets() == 0);
acc_.add_sets(a->acc().num_sets());
}
void copy_ap_of(const const_tgba_ptr& a)
{
dict_->register_all_propositions_of(a, this);
}
virtual bdd all_acceptance_conditions() const
{
return all_acceptance_conditions_;
}
virtual bdd neg_acceptance_conditions() const
{
return neg_acceptance_conditions_;
get_dict()->register_all_propositions_of(a, this);
}
virtual bdd compute_support_conditions(const state* s) const
@ -400,7 +395,7 @@ namespace spot
for (auto& t: g_.out(s))
// Stop at the first transition, since the remaining should be
// labeled identically.
return t.acc == all_acceptance_conditions_;
return acc_.accepting(t.acc);
return false;
}

View file

@ -1,685 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 2011, 2013, 2014 Laboratoire de Recherche
// et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <vector>
#include <cassert>
#include <sstream>
#include "bdd.h"
#include "bddprint.hh"
#include "tgba.hh"
#include "tgbakvcomplement.hh"
#include "misc/hash.hh"
#include "tgbaalgos/bfssteps.hh"
#include "misc/hashfunc.hh"
#include "ltlast/formula.hh"
#include "ltlast/constant.hh"
#include "priv/countstates.hh"
namespace spot
{
namespace
{
////////////////////////////////////////
// rank
/// \brief A rank structure, one of the main structure of the algorithm.
///
/// A rank has a number (\a rank) that refers to the depth in the DAG of
/// the current word. When the rank is odd, a \a condition is associated
/// to this rank.
struct rank_t
{
mutable unsigned rank;
mutable bdd_ordered condition;
bool operator<(const rank_t& other) const
{
return rank < other.rank ||
condition.order() < other.condition.order();
}
unsigned get_rank() const
{
return rank;
}
bdd_ordered get_condition() const
{
return condition;
}
size_t hash() const
{
size_t hash = wang32_hash(rank);
if (rank & 1)
hash ^= wang32_hash(condition.order());
return hash;
}
std::string format(const bdd_dict_ptr& d) const
{
std::ostringstream ss;
ss << "{rank: " << rank;
if (rank & 1)
{
ss << ", bdd: {" << condition.order() << ", "
<< bdd_format_accset(d, condition.get_bdd())
<< "} ";
}
ss << '}';
return ss.str();
}
};
// typedefs.
typedef std::unordered_map<shared_state, rank_t,
state_shared_ptr_hash,
state_shared_ptr_equal> state_rank_map;
////////////////////////////////////////
// state_kv_complement
/// States used by spot::tgba_kv_complement.
/// A state has a map of states associated to ranks, and a set
/// of filtered states.
/// \ingroup tgba_representation
class state_kv_complement : public state
{
public:
state_kv_complement();
state_kv_complement(state_rank_map state_map,
shared_state_set state_filter);
virtual ~state_kv_complement() {}
virtual int compare(const state* other) const;
virtual size_t hash() const;
virtual state_kv_complement* clone() const;
void add(shared_state state, const rank_t& rank);
const state_rank_map& get_state_map() const;
const shared_state_set& get_filter_set() const;
bool accepting() const;
private:
state_rank_map state_map_;
shared_state_set state_filter_;
};
state_kv_complement::state_kv_complement()
{
}
state_kv_complement::state_kv_complement(state_rank_map state_map,
shared_state_set state_filter)
: state_map_(state_map), state_filter_(state_filter)
{
}
int
state_kv_complement::compare(const state* o) const
{
const state_kv_complement* other =
down_cast<const state_kv_complement*>(o);
if (other == 0)
return 1;
if (state_map_.size() < other->state_map_.size())
return -1;
else if (state_map_.size() > other->state_map_.size())
return 1;
if (state_filter_.size() < other->state_filter_.size())
return -1;
else if (state_filter_.size() > other->state_filter_.size())
return 1;
{
state_rank_map::const_iterator i = state_map_.begin();
state_rank_map::const_iterator j = other->state_map_.begin();
while (i != state_map_.end() && j != other->state_map_.end())
{
int result = i->first->compare(j->first.get());
if (result != 0)
return result;
if (i->second < j->second)
return -1;
if (j->second < i->second)
return 1;
++i;
++j;
}
}
{
shared_state_set::const_iterator i = state_filter_.begin();
shared_state_set::const_iterator j = other->state_filter_.begin();
while (i != state_filter_.end() && j != other->state_filter_.end())
{
int result = (*i)->compare(j->get());
if (result != 0)
return result;
++i;
++j;
}
}
return 0;
}
size_t
state_kv_complement::hash() const
{
size_t hash = 0;
{
state_rank_map::const_iterator i = state_map_.begin();
while (i != state_map_.end())
{
hash ^= i->first->hash();
hash ^= i->second.hash();
++i;
}
}
{
shared_state_set::const_iterator i = state_filter_.begin();
while (i != state_filter_.end())
{
hash ^= (*i)->hash();
++i;
}
}
return hash;
}
state_kv_complement*
state_kv_complement::clone() const
{
return new state_kv_complement(*this);
}
void
state_kv_complement::add(shared_state state,
const rank_t& rank)
{
state_map_[state] = rank;
}
const state_rank_map&
state_kv_complement::get_state_map() const
{
return state_map_;
}
const shared_state_set&
state_kv_complement::get_filter_set() const
{
return state_filter_;
}
bool
state_kv_complement::accepting() const
{
return state_filter_.empty();
}
/// Successor iterators used by spot::tgba_kv_complement.
/// \ingroup tgba_representation
///
/// Since the algorithm works on-the-fly, the key components of the
/// algorithm are implemented in this class.
///
///
class tgba_kv_complement_succ_iterator: public tgba_succ_iterator
{
public:
typedef std::list<bdd> bdd_list_t;
tgba_kv_complement_succ_iterator(const tgba_sgba_proxy* automaton,
bdd the_acceptance_cond,
const acc_list_t& acc_list,
const state_kv_complement* origin);
virtual ~tgba_kv_complement_succ_iterator() {};
virtual bool first();
virtual bool next();
virtual bool done() const;
virtual state_kv_complement* current_state() const;
virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const;
private:
/// \brief Create the highest rank of \a origin_ as origin and
/// \a condition as successor condition.
void successor_highest_rank(bdd condition);
void get_atomics(std::set<int>& list, bdd c);
void get_conj_list();
bool is_valid_rank() const;
bool next_valid_rank();
const tgba_sgba_proxy* automaton_;
bdd the_acceptance_cond_;
const acc_list_t& acc_list_;
const state_kv_complement* origin_;
bdd_list_t condition_list_;
bdd_list_t::const_iterator current_condition_;
state_rank_map highest_current_ranks_;
state_rank_map current_ranks_;
shared_state_set highest_state_set_;
};
tgba_kv_complement_succ_iterator::
tgba_kv_complement_succ_iterator(const tgba_sgba_proxy* automaton,
bdd the_acceptance_cond,
const acc_list_t& acc_list,
const state_kv_complement* origin)
: automaton_(automaton), the_acceptance_cond_(the_acceptance_cond),
acc_list_(acc_list), origin_(origin)
{
get_conj_list();
}
/// Insert in \a list atomic properties of the formula \a c.
void
tgba_kv_complement_succ_iterator::get_atomics(std::set<int>& list, bdd c)
{
bdd current = bdd_satone(c);
while (current != bddtrue && current != bddfalse)
{
list.insert(bdd_var(current));
bdd high = bdd_high(current);
if (high == bddfalse)
current = bdd_low(current);
else
current = high;
}
}
/// Create the conjunction of all the atomic properties from
/// the successors of the current state.
void
tgba_kv_complement_succ_iterator::get_conj_list()
{
std::set<int> atomics;
condition_list_.clear();
state_rank_map sr_map = origin_->get_state_map();
// Retrieve all the atomics in acceptance conditions.
for (state_rank_map::const_iterator i = sr_map.begin();
i != sr_map.end();
++i)
{
for (auto iterator: automaton_->succ(i->first.get()))
{
bdd c = iterator->current_condition();
get_atomics(atomics, c);
}
}
// Compute the conjunction of all those atomic properties.
unsigned atomics_size = atomics.size();
assert(atomics_size < 32);
for (unsigned i = 1; i <= static_cast<unsigned>(1 << atomics_size); ++i)
{
bdd result = bddtrue;
unsigned position = 1;
for (std::set<int>::const_iterator a_it = atomics.begin();
a_it != atomics.end();
++a_it, position <<= 1)
{
bdd this_atomic;
if (position & i)
this_atomic = bdd_ithvar(*a_it);
else
this_atomic = bdd_nithvar(*a_it);
result = bdd_apply(result, this_atomic, bddop_and);
}
condition_list_.push_back(result);
}
}
/// Check whether \a current_ranks_ is a valid rank.
/// For each odd rank, its condition associated must not
/// be present in its tracked state.
bool
tgba_kv_complement_succ_iterator::is_valid_rank() const
{
for (state_rank_map::const_iterator i = current_ranks_.begin();
i != current_ranks_.end();
++i)
{
if (i->second.rank & 1)
{
if ((automaton_->state_acceptance_conditions(i->first.get()) &
i->second.condition.get_bdd()) != bddfalse)
return false;
}
}
return true;
}
/// \brief Decrease \a current_ranks_ and produces a valid rank.
/// \a current_ranks_ is a map of states to a rank.
/// A rank for a state is valid if it is inferior than the rank of its
/// predecessor.
/// When the rank is odd, its has an acceptance condition associated that
/// must not be in its associated state.
/// \return false if there is not valid rank as successor.
bool tgba_kv_complement_succ_iterator::next_valid_rank()
{
state_rank_map::const_iterator i;
do
{
for (i = current_ranks_.begin(); i != current_ranks_.end(); ++i)
{
if (i->second.rank != 0)
{
if (i->second.rank & 1)
{
if (i->second.condition.order() == 0)
--i->second.rank;
else
i->second.condition =
acc_list_[i->second.condition.order() - 1];
}
else
{
--i->second.rank;
i->second.condition = acc_list_[acc_list_.size() - 1];
}
break;
}
else
{
current_ranks_[i->first] = highest_current_ranks_[i->first];
}
}
}
while ((i != current_ranks_.end()) && !is_valid_rank());
return i != current_ranks_.end();
}
/// \brief Create the highest rank of \a origin_ as origin and
/// \a condition as successor condition.
void
tgba_kv_complement_succ_iterator::successor_highest_rank(bdd condition)
{
// Highest rank for bdd.
state_rank_map sr_map = origin_->get_state_map();
highest_current_ranks_.clear();
for (state_rank_map::const_iterator i = sr_map.begin();
i != sr_map.end();
++i)
{
for (auto iterator: automaton_->succ(i->first.get()))
{
bdd c = iterator->current_condition();
if ((c & condition) != bddfalse)
{
shared_state s(iterator->current_state(), shared_state_deleter);
if (highest_current_ranks_.find(s) != highest_current_ranks_.end())
{
if (i->second < highest_current_ranks_[s])
highest_current_ranks_[s] = i->second;
}
else
highest_current_ranks_[s] = i->second;
}
}
}
// Highest $O$ set of the algorithm.
shared_state_set s_set = origin_->get_filter_set();
highest_state_set_.clear();
for (shared_state_set::const_iterator i = s_set.begin();
i != s_set.end();
++i)
{
for (auto iterator: automaton_->succ(i->get()))
{
bdd c = iterator->current_condition();
if ((c & condition) != bddfalse)
{
shared_state s(iterator->current_state(), shared_state_deleter);
highest_state_set_.insert(s);
}
}
}
current_ranks_ = highest_current_ranks_;
}
bool
tgba_kv_complement_succ_iterator::first()
{
current_condition_ = condition_list_.begin();
if (current_condition_ == condition_list_.end())
return false;
successor_highest_rank(*current_condition_);
if (!is_valid_rank())
next_valid_rank();
return current_condition_ != condition_list_.end();
}
bool
tgba_kv_complement_succ_iterator::next()
{
if (current_condition_ == condition_list_.end())
return false;
if (!next_valid_rank())
{
++current_condition_;
if (!done())
{
successor_highest_rank(*current_condition_);
if (!is_valid_rank())
next_valid_rank();
}
}
return current_condition_ != condition_list_.end();
}
bool
tgba_kv_complement_succ_iterator::done() const
{
return current_condition_ == condition_list_.end();
}
state_kv_complement*
tgba_kv_complement_succ_iterator::current_state() const
{
if (done())
return 0;
// If the filter set is empty, all the states of the map
// that are associated to an even rank create the new filter set.
shared_state_set filter;
if (origin_->get_filter_set().empty())
{
for (state_rank_map::const_iterator i = current_ranks_.begin();
i != current_ranks_.end();
++i)
if (!(i->second.rank & 1))
filter.insert(i->first);
}
else
{
// It the filter set is non-empty, we delete from this set states
// that are now associated to an odd rank.
for (shared_state_set::const_iterator i = highest_state_set_.begin();
i != highest_state_set_.end();
++i)
{
state_rank_map::const_iterator s(current_ranks_.find(*i));
assert(s != current_ranks_.end());
if (!(s->second.get_rank() & 1))
filter.insert(*i);
}
}
return new state_kv_complement(current_ranks_, filter);
}
bdd
tgba_kv_complement_succ_iterator::current_condition() const
{
if (done())
return bddfalse;
return *current_condition_;
}
bdd
tgba_kv_complement_succ_iterator::current_acceptance_conditions() const
{
if (done())
return bddfalse;
// This algorithm doesn't generalized acceptance conditions.
if (origin_->accepting())
return the_acceptance_cond_;
else
return bddfalse;
}
} // end namespace anonymous.
/// Retrieve all the atomic acceptance conditions of the automaton.
/// They are inserted into \a acc_list_.
void
tgba_kv_complement::get_acc_list()
{
bdd c = automaton_->all_acceptance_conditions();
bdd current = bdd_satone(c);
unsigned i = 0;
while (current != bddtrue && current != bddfalse)
{
acc_list_.push_back(bdd_ordered(bdd_var(current), i));
++i;
bdd high = bdd_high(current);
if (high == bddfalse)
current = bdd_low(current);
else
current = high;
}
}
tgba_kv_complement::tgba_kv_complement(const const_tgba_ptr& a)
: automaton_(make_sgba(a))
{
get_dict()->register_all_variables_of(automaton_, this);
int v = get_dict()
->register_acceptance_variable(ltl::constant::true_instance(), this);
the_acceptance_cond_ = bdd_ithvar(v);
nb_states_ = count_states(automaton_);
get_acc_list();
}
tgba_kv_complement::~tgba_kv_complement()
{
get_dict()->unregister_all_my_variables(this);
}
state*
tgba_kv_complement::get_init_state() const
{
state_kv_complement* init = new state_kv_complement();
rank_t r = {2 * nb_states_, bdd_ordered()};
init->add(shared_state(automaton_->get_init_state(), shared_state_deleter),
r);
return init;
}
tgba_succ_iterator*
tgba_kv_complement::succ_iter(const state* state) const
{
const state_kv_complement* s =
down_cast<const state_kv_complement*>(state);
assert(s);
return new tgba_kv_complement_succ_iterator(automaton_.get(),
the_acceptance_cond_,
acc_list_, s);
}
bdd_dict_ptr
tgba_kv_complement::get_dict() const
{
return automaton_->get_dict();
}
std::string
tgba_kv_complement::format_state(const state* state) const
{
const state_kv_complement* s =
down_cast<const state_kv_complement*>(state);
assert(s);
std::ostringstream ss;
ss << "{ set: {" << std::endl;
const state_rank_map& state_map = s->get_state_map();
const shared_state_set& state_filter = s->get_filter_set();
for (state_rank_map::const_iterator i = state_map.begin();
i != state_map.end();
++i)
{
ss << " {" << automaton_->format_state(i->first.get())
<< ", " << i->second.format(get_dict()) << "}\n";
}
ss << "} odd-less: {";
for (shared_state_set::const_iterator i = state_filter.begin();
i != state_filter.end();
++i)
ss << " " << automaton_->format_state(i->get()) << '\n';
ss << "} }";
return ss.str();
}
bdd
tgba_kv_complement::all_acceptance_conditions() const
{
return the_acceptance_cond_;
}
bdd
tgba_kv_complement::neg_acceptance_conditions() const
{
return !the_acceptance_cond_;
}
bdd
tgba_kv_complement::compute_support_conditions(const state* state) const
{
bdd result = bddfalse;
for (auto i: succ(state))
result |= i->current_condition();
return result;
}
} // end namespace spot.

View file

@ -1,124 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche
// et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SPOT_TGBA_TGBAKVCOMPLEMENT_HH
#define SPOT_TGBA_TGBAKVCOMPLEMENT_HH
#include <vector>
#include "bdd.h"
#include "tgba.hh"
#include "tgba/tgbasgba.hh"
namespace spot
{
class SPOT_API bdd_ordered
{
public:
bdd_ordered()
: bdd_(0), order_(0)
{};
bdd_ordered(int bdd_, unsigned order_)
: bdd_(bdd_), order_(order_)
{
}
unsigned order() const
{
return order_;
}
unsigned& order()
{
return order_;
}
bdd get_bdd() const
{
return bdd_ithvar(bdd_);
}
private:
int bdd_;
unsigned order_;
};
typedef std::vector<bdd_ordered> acc_list_t;
/// \ingroup tgba_on_the_fly_algorithms
/// \brief Build a complemented automaton.
///
/// The construction comes from:
/** \verbatim
@Article{ kupferman.05.tcs,
title = {From complementation to certification},
author = {Kupferman, O. and Vardi, M.Y.},
journal = {Theoretical Computer Science},
volume = {345},
number = {1},
pages = {83--100},
year = {2005},
publisher = {Elsevier}
}
\endverbatim */
///
/// The original automaton is used as a States-based Generalized
/// Büchi Automaton.
///
/// The construction is done on-the-fly, by the
/// \c tgba_kv_complement_succ_iterator class.
/// \see tgba_kv_complement_succ_iterator
class SPOT_API tgba_kv_complement : public tgba
{
public:
tgba_kv_complement(const const_tgba_ptr& a);
virtual ~tgba_kv_complement();
// tgba interface
virtual state* get_init_state() const;
virtual tgba_succ_iterator* succ_iter(const state* state) const;
virtual bdd_dict_ptr get_dict() const;
virtual std::string format_state(const state* state) const;
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
protected:
virtual bdd compute_support_conditions(const state* state) const;
private:
/// Retrieve all the atomic acceptance conditions of the automaton.
/// They are inserted into \a acc_list_.
void get_acc_list();
private:
const_tgba_sgba_proxy_ptr automaton_;
bdd the_acceptance_cond_;
unsigned nb_states_;
acc_list_t acc_list_;
}; // end class tgba_kv_complement.
typedef std::shared_ptr<tgba_kv_complement> tgba_kv_complement_ptr;
typedef std::shared_ptr<const tgba_kv_complement>
const_tgba_kv_complement_ptr;
inline tgba_kv_complement_ptr
make_kv_complement(const const_tgba_ptr& a)
{
return std::make_shared<tgba_kv_complement>(a);
}
} // end namespace spot.
#endif // !SPOT_TGBA_TGBAKVCOMPLEMENT_HH

View file

@ -28,7 +28,7 @@ namespace spot
{
const state* dest;
bdd cond;
bdd acc;
acc_cond::mark_t acc;
};
typedef std::vector<transition> transitions;
@ -67,7 +67,7 @@ namespace spot
return it_->cond;
}
bdd current_acceptance_conditions() const
acc_cond::mark_t current_acceptance_conditions() const
{
return it_->acc;
}
@ -128,19 +128,19 @@ namespace spot
for (auto it: original_->succ(local_state))
{
const spot::state* s = it->current_state();
bdd acc = it->current_acceptance_conditions();
auto acc = it->current_acceptance_conditions();
if (!wanted(s, acc))
{
s->destroy();
continue;
}
res->trans_.emplace_back(transition {s, it->current_condition(),
acc});
res->trans_.emplace_back
(transition {s, it->current_condition(), acc});
}
return res;
}
virtual bool wanted(const state* s, const bdd& acc) const = 0;
virtual bool wanted(const state* s, acc_cond::mark_t acc) const = 0;
protected:
const state* init_;
@ -158,7 +158,7 @@ namespace spot
{
}
bool wanted(const state* s, const bdd&) const
bool wanted(const state* s, const acc_cond::mark_t) const
{
state_set::const_iterator i = mask_.find(s);
return i != mask_.end();
@ -177,7 +177,7 @@ namespace spot
{
}
bool wanted(const state* s, const bdd&) const
bool wanted(const state* s, const acc_cond::mark_t) const
{
state_set::const_iterator i = mask_.find(s);
return i == mask_.end();
@ -186,19 +186,19 @@ namespace spot
class tgba_mask_acc_ignore: public tgba_mask
{
const bdd& mask_;
unsigned mask_;
public:
tgba_mask_acc_ignore(const const_tgba_ptr& masked,
const bdd& mask,
unsigned mask,
const state* init)
: tgba_mask(masked, init),
mask_(mask)
{
}
bool wanted(const state*, const bdd& acc) const
bool wanted(const state*, const acc_cond::mark_t acc) const
{
return (acc & mask_) == bddfalse;
return !acc.has(mask_);
}
};
@ -222,7 +222,7 @@ namespace spot
const_tgba_ptr
build_tgba_mask_acc_ignore(const const_tgba_ptr& to_mask,
const bdd to_ignore,
unsigned to_ignore,
const state* init)
{
return std::make_shared<tgba_mask_acc_ignore>(to_mask, to_ignore, init);

View file

@ -52,9 +52,9 @@ namespace spot
/// \ingroup tgba_on_the_fly_algorithms
/// \brief Mask a TGBA, rejecting some acceptance set of transitions.
///
/// This will ignore all transitions labeled by the acceptance ACC
/// such that ACC & TO_IGNORE != bddfalse. The initial state can
/// optionally be reset to \a init.
/// This will ignore all transitions that have the TO_IGNORE
/// acceptance mark. The initial state can optionally be reset to
/// \a init.
///
/// Note that the acceptance condition of the automaton (i.e. the
/// set of all acceptance set) is not changed, because so far this
@ -62,7 +62,7 @@ namespace spot
/// all_acceptance_conditions().
SPOT_API const_tgba_ptr
build_tgba_mask_acc_ignore(const const_tgba_ptr& to_mask,
const bdd to_ignore,
unsigned to_ignore,
const state* init = 0);
}

View file

@ -84,8 +84,9 @@ namespace spot
public:
tgba_succ_iterator_product_common(tgba_succ_iterator* left,
tgba_succ_iterator* right,
const tgba_product* prod,
fixed_size_pool* pool)
: left_(left), right_(right), pool_(pool)
: left_(left), right_(right), prod_(prod), pool_(pool)
{
}
@ -139,6 +140,7 @@ namespace spot
protected:
tgba_succ_iterator* left_;
tgba_succ_iterator* right_;
const tgba_product* prod_;
fixed_size_pool* pool_;
friend class spot::tgba_product;
};
@ -150,13 +152,9 @@ namespace spot
public:
tgba_succ_iterator_product(tgba_succ_iterator* left,
tgba_succ_iterator* right,
bdd left_neg, bdd right_neg,
bddPair* right_common_acc,
const tgba_product* prod,
fixed_size_pool* pool)
: tgba_succ_iterator_product_common(left, right, pool),
left_neg_(left_neg),
right_neg_(right_neg),
right_common_acc_(right_common_acc)
: tgba_succ_iterator_product_common(left, right, prod, pool)
{
}
@ -203,18 +201,17 @@ namespace spot
return current_cond_;
}
bdd current_acceptance_conditions() const
acc_cond::mark_t current_acceptance_conditions() const
{
return ((left_->current_acceptance_conditions() & right_neg_)
| (bdd_replace(right_->current_acceptance_conditions(),
right_common_acc_) & left_neg_));
}
return
prod_->acc().join(prod_->left_acc(),
left_->current_acceptance_conditions(),
prod_->right_acc(),
right_->current_acceptance_conditions());
}
protected:
bdd current_cond_;
bdd left_neg_;
bdd right_neg_;
bddPair* right_common_acc_;
};
/// Iterate over the successors of a product computed on the fly.
@ -225,8 +222,9 @@ namespace spot
public:
tgba_succ_iterator_product_kripke(tgba_succ_iterator* left,
tgba_succ_iterator* right,
const tgba_product* prod,
fixed_size_pool* pool)
: tgba_succ_iterator_product_common(left, right, pool)
: tgba_succ_iterator_product_common(left, right, prod, pool)
{
}
@ -270,7 +268,7 @@ namespace spot
return current_cond_;
}
bdd current_acceptance_conditions() const
acc_cond::mark_t current_acceptance_conditions() const
{
return right_->current_acceptance_conditions();
}
@ -286,10 +284,10 @@ namespace spot
tgba_product::tgba_product(const const_tgba_ptr& left,
const const_tgba_ptr& right)
: dict_(left->get_dict()), left_(left), right_(right),
: tgba(left->get_dict()), left_(left), right_(right),
pool_(sizeof(state_product))
{
assert(dict_ == right_->get_dict());
assert(get_dict() == right_->get_dict());
// If one of the side is a Kripke structure, it is easier to deal
// with (we don't have to fix the acceptance conditions, and
@ -308,55 +306,17 @@ namespace spot
left_kripke_ = false;
}
dict_->register_all_variables_of(&left_, this);
dict_->register_all_variables_of(&right_, this);
auto d = get_dict();
d->register_all_propositions_of(&left_, this);
d->register_all_propositions_of(&right_, this);
if (left_kripke_)
{
all_acceptance_conditions_ = right_->all_acceptance_conditions();
neg_acceptance_conditions_ = right_->neg_acceptance_conditions();
return;
}
bdd lna = left_->neg_acceptance_conditions();
bdd rna = right_->neg_acceptance_conditions();
right_common_acc_ = bdd_newpair();
bdd tmp = lna;
while (tmp != bddtrue)
{
assert(bdd_high(tmp) == bddfalse);
int var = bdd_var(tmp);
if (bdd_implies(rna, bdd_nithvar(var)))
{
int varclone = dict_->register_clone_acc(var, this);
bdd_setpair(right_common_acc_, var, varclone);
}
tmp = bdd_low(tmp);
}
bdd lac = left_->all_acceptance_conditions();
bdd rac = right_->all_acceptance_conditions();
rna = bdd_replace(rna, right_common_acc_);
rac = bdd_replace(rac, right_common_acc_);
left_acc_complement_ = lna;
assert(bdd_exist(lna, rna) == lna);
right_acc_complement_ = rna;
assert(bdd_exist(rna, lna) == rna);
all_acceptance_conditions_ = ((lac & right_acc_complement_)
| (rac & left_acc_complement_));
neg_acceptance_conditions_ = lna & rna;
assert(acc_.num_sets() == 0);
acc_.add_sets(left->acc().num_sets() + right->acc().num_sets());
}
tgba_product::~tgba_product()
{
if (!left_kripke_)
bdd_freepair(right_common_acc_);
dict_->unregister_all_my_variables(this);
get_dict()->unregister_all_my_variables(this);
// Prevent these states from being destroyed by ~tgba(): they
// will be destroyed before when the pool is destructed.
if (last_support_conditions_input_)
@ -393,13 +353,9 @@ namespace spot
fixed_size_pool* p = const_cast<fixed_size_pool*>(&pool_);
if (left_kripke_)
return new tgba_succ_iterator_product_kripke(li, ri, p);
return new tgba_succ_iterator_product_kripke(li, ri, this, p);
else
return new tgba_succ_iterator_product(li, ri,
left_acc_complement_,
right_acc_complement_,
right_common_acc_,
p);
return new tgba_succ_iterator_product(li, ri, this, p);
}
bdd
@ -412,10 +368,14 @@ namespace spot
return lsc & rsc;
}
bdd_dict_ptr
tgba_product::get_dict() const
const acc_cond& tgba_product::left_acc() const
{
return dict_;
return left_->acc();
}
const acc_cond& tgba_product::right_acc() const
{
return right_->acc();
}
std::string
@ -441,18 +401,6 @@ namespace spot
return right_->project_state(s2->right(), t);
}
bdd
tgba_product::all_acceptance_conditions() const
{
return all_acceptance_conditions_;
}
bdd
tgba_product::neg_acceptance_conditions() const
{
return neg_acceptance_conditions_;
}
std::string
tgba_product::transition_annotation(const tgba_succ_iterator* t) const
{

View file

@ -94,8 +94,6 @@ namespace spot
virtual tgba_succ_iterator*
succ_iter(const state* state) const;
virtual bdd_dict_ptr get_dict() const;
virtual std::string format_state(const state* state) const;
virtual std::string
@ -103,22 +101,16 @@ namespace spot
virtual state* project_state(const state* s, const const_tgba_ptr& t) const;
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
const acc_cond& left_acc() const;
const acc_cond& right_acc() const;
protected:
virtual bdd compute_support_conditions(const state* state) const;
protected:
bdd_dict_ptr dict_;
const_tgba_ptr left_;
const_tgba_ptr right_;
bool left_kripke_;
bdd left_acc_complement_;
bdd right_acc_complement_;
bdd all_acceptance_conditions_;
bdd neg_acceptance_conditions_;
bddPair* right_common_acc_;
fixed_size_pool pool_;
private:

View file

@ -22,9 +22,10 @@
namespace spot
{
tgba_proxy::tgba_proxy(const const_tgba_ptr& original)
: original_(original)
: tgba(original->get_dict()), original_(original)
{
get_dict()->register_all_variables_of(original, this);
acc_.add_sets(original->acc().num_sets());
}
tgba_proxy::~tgba_proxy()
@ -48,12 +49,6 @@ namespace spot
return original_->succ_iter(state);
}
bdd_dict_ptr
tgba_proxy::get_dict() const
{
return original_->get_dict();
}
std::string
tgba_proxy::format_state(const state* state) const
{
@ -72,18 +67,6 @@ namespace spot
return original_->project_state(s, t);
}
bdd
tgba_proxy::all_acceptance_conditions() const
{
return original_->all_acceptance_conditions();
}
bdd
tgba_proxy::neg_acceptance_conditions() const
{
return original_->neg_acceptance_conditions();
}
bdd
tgba_proxy::compute_support_conditions(const state* state) const
{

View file

@ -46,8 +46,6 @@ namespace spot
virtual tgba_succ_iterator*
succ_iter(const state* state) const;
virtual bdd_dict_ptr get_dict() const;
virtual std::string format_state(const state* state) const;
virtual std::string
@ -55,10 +53,6 @@ namespace spot
virtual state* project_state(const state* s, const const_tgba_ptr& t) const;
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
protected:
virtual bdd compute_support_conditions(const state* state) const;
const_tgba_ptr original_;

View file

@ -962,7 +962,7 @@ namespace spot
typedef std::multimap<bdd, state_complement*, bdd_less_than> succ_list_t;
tgba_safra_complement_succ_iterator(const succ_list_t& list,
bdd the_acceptance_cond)
acc_cond::mark_t the_acceptance_cond)
: list_(list), the_acceptance_cond_(the_acceptance_cond)
{
}
@ -979,10 +979,10 @@ namespace spot
virtual bool done() const;
virtual state_complement* current_state() const;
virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const;
virtual acc_cond::mark_t current_acceptance_conditions() const;
private:
succ_list_t list_;
bdd the_acceptance_cond_;
acc_cond::mark_t the_acceptance_cond_;
succ_list_t::const_iterator it_;
};
@ -1020,7 +1020,7 @@ namespace spot
return it_->first;
}
bdd
acc_cond::mark_t
tgba_safra_complement_succ_iterator::current_acceptance_conditions() const
{
assert(!done());
@ -1075,38 +1075,22 @@ namespace spot
//////////////////////////
tgba_safra_complement::tgba_safra_complement(const const_tgba_ptr& a)
: automaton_(a), safra_(safra_determinisation::create_safra_automaton(a))
: tgba(a->get_dict()), automaton_(a),
safra_(safra_determinisation::create_safra_automaton(a))
{
assert(safra_ || !"safra construction fails");
// We will use one acceptance condition for this automata.
// Let's call it Acc[True].
int v = get_dict()
->register_acceptance_variable(ltl::constant::true_instance(), safra_);
#if TRANSFORM_TO_TBA
the_acceptance_cond_ = bdd_ithvar(v);
the_acceptance_cond_ = acc_.mark(acc_.add_set());
#endif
#if TRANSFORM_TO_TGBA
unsigned nb_acc =
static_cast<safra_tree_automaton*>(safra_)->get_nb_acceptance_pairs();
all_acceptance_cond_ = bddfalse;
neg_acceptance_cond_ = bddtrue;
acceptance_cond_vec_.reserve(nb_acc);
for (unsigned i = 0; i < nb_acc; ++i)
{
int r = get_dict()->register_clone_acc(v, safra_);
all_acceptance_cond_ &= bdd_nithvar(r);
all_acceptance_cond_ |= bdd_ithvar(r) & neg_acceptance_cond_;
neg_acceptance_cond_ &= bdd_nithvar(r);
acceptance_cond_vec_.push_back(bdd_ithvar(r));
}
for (unsigned i = 0; i < nb_acc; ++i)
{
bdd c = acceptance_cond_vec_[i];
acceptance_cond_vec_[i] = bdd_exist(neg_acceptance_cond_, c) & c;
}
acceptance_cond_vec_.push_back(acc_.mark(acc_.add_set()));
#endif
}
@ -1171,7 +1155,7 @@ namespace spot
assert(tr != a->automaton.end());
bdd condition = bddfalse;
acc_cond::mark_t condition = 0U;
tgba_safra_complement_succ_iterator::succ_list_t succ_list;
int nb_acceptance_pairs = a->get_nb_acceptance_pairs();
bitvect* e = make_bitvect(nb_acceptance_pairs);
@ -1249,12 +1233,6 @@ namespace spot
return new tgba_safra_complement_succ_iterator(succ_list, condition);
}
bdd_dict_ptr
tgba_safra_complement::get_dict() const
{
return automaton_->get_dict();
}
std::string
tgba_safra_complement::format_state(const state* state) const
{
@ -1264,26 +1242,6 @@ namespace spot
return s->to_string();
}
bdd
tgba_safra_complement::all_acceptance_conditions() const
{
#if TRANSFORM_TO_TBA
return the_acceptance_cond_;
#else
return all_acceptance_cond_;
#endif
}
bdd
tgba_safra_complement::neg_acceptance_conditions() const
{
#if TRANSFORM_TO_TBA
return !the_acceptance_cond_;
#else
return neg_acceptance_cond_;
#endif
}
bdd
tgba_safra_complement::compute_support_conditions(const state* state) const
{

View file

@ -57,10 +57,7 @@ namespace spot
virtual state* get_init_state() const;
virtual tgba_succ_iterator* succ_iter(const state* state) const;
virtual bdd_dict_ptr get_dict() const;
virtual std::string format_state(const state* state) const;
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
void* get_safra() const
{
@ -73,13 +70,11 @@ namespace spot
const_tgba_ptr automaton_;
void* safra_;
#if TRANSFORM_TO_TBA
bdd the_acceptance_cond_;
acc_cond::mark_t the_acceptance_cond_;
#endif
#if TRANSFORM_TO_TGBA
bdd all_acceptance_cond_;
bdd neg_acceptance_cond_;
// Map to i the i-th acceptance condition of the final automaton.
std::vector<bdd> acceptance_cond_vec_;
std::vector<acc_cond::mark_t> acceptance_cond_vec_;
#endif
};

View file

@ -1,262 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2011, 2012, 2014 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <cassert>
#include "tgbasgba.hh"
#include "bddprint.hh"
#include "ltlast/constant.hh"
#include "misc/hashfunc.hh"
namespace spot
{
namespace
{
/// \brief A state for spot::tgba_sgba_proxy.
class state_sgba_proxy: public state
{
public:
state_sgba_proxy(state* s, bdd acc)
: s_(s), acc_(acc)
{
}
/// Copy constructor
state_sgba_proxy(const state_sgba_proxy& o)
: state(),
s_(o.real_state()->clone()),
acc_(o.acc_)
{
}
virtual
~state_sgba_proxy()
{
s_->destroy();
}
state*
real_state() const
{
return s_;
}
bdd
acceptance_cond() const
{
return acc_;
}
virtual int
compare(const state* other) const
{
const state_sgba_proxy* o =
down_cast<const state_sgba_proxy*>(other);
assert(o);
int res = s_->compare(o->real_state());
if (res != 0)
return res;
return acc_.id() - o->acc_.id();
}
virtual size_t
hash() const
{
return wang32_hash(s_->hash()) ^ wang32_hash(acc_.id());
}
virtual
state_sgba_proxy* clone() const
{
return new state_sgba_proxy(*this);
}
private:
state* s_;
bdd acc_;
};
/// \brief Iterate over the successors of tgba_sgba_proxy computed
/// on the fly.
class tgba_sgba_proxy_succ_iterator: public tgba_succ_iterator
{
public:
tgba_sgba_proxy_succ_iterator(tgba_succ_iterator* it)
: it_(it), emulate_acc_cond_(false)
{
}
tgba_sgba_proxy_succ_iterator(tgba_succ_iterator* it, bdd acc)
: it_(it), emulate_acc_cond_(true), acceptance_condition_(acc)
{
}
virtual
~tgba_sgba_proxy_succ_iterator()
{
delete it_;
}
// iteration
bool
first()
{
return it_->first();
}
bool
next()
{
return it_->next();
}
bool
done() const
{
return it_->done();
}
// inspection
state_sgba_proxy*
current_state() const
{
return new state_sgba_proxy(it_->current_state(),
it_->current_acceptance_conditions());
}
bdd
current_condition() const
{
return it_->current_condition();
}
bdd
current_acceptance_conditions() const
{
if (emulate_acc_cond_)
return acceptance_condition_;
return it_->current_acceptance_conditions();
}
protected:
tgba_succ_iterator* it_;
// If the automaton has no acceptance condition,
// every state is accepting.
bool emulate_acc_cond_;
bdd acceptance_condition_;
};
} // anonymous
tgba_sgba_proxy::tgba_sgba_proxy(const const_tgba_ptr& a,
bool no_zero_acc)
: a_(a), emulate_acc_cond_(false)
{
if (no_zero_acc && a_->number_of_acceptance_conditions() == 0)
{
emulate_acc_cond_ = true;
int v = get_dict()
->register_acceptance_variable(ltl::constant::true_instance(), this);
acceptance_condition_ = bdd_ithvar(v);
}
get_dict()->register_all_variables_of(a, this);
}
tgba_sgba_proxy::~tgba_sgba_proxy()
{
get_dict()->unregister_all_my_variables(this);
}
state*
tgba_sgba_proxy::get_init_state() const
{
return new state_sgba_proxy(a_->get_init_state(), bddfalse);
}
tgba_succ_iterator*
tgba_sgba_proxy::succ_iter(const state* state) const
{
const state_sgba_proxy* s = down_cast<const state_sgba_proxy*>(state);
assert(s);
tgba_succ_iterator* it = a_->succ_iter(s->real_state());
return new tgba_sgba_proxy_succ_iterator(it);
}
bdd_dict_ptr
tgba_sgba_proxy::get_dict() const
{
return a_->get_dict();
}
std::string
tgba_sgba_proxy::format_state(const state* state) const
{
const state_sgba_proxy* s = down_cast<const state_sgba_proxy*>(state);
assert(s);
std::string a;
if (!emulate_acc_cond_)
a = bdd_format_accset(get_dict(), s->acceptance_cond());
else
a = bdd_format_accset(get_dict(), acceptance_condition_);
if (a != "")
a = " " + a;
return a_->format_state(s->real_state()) + a;
}
bdd
tgba_sgba_proxy::all_acceptance_conditions() const
{
if (emulate_acc_cond_)
return acceptance_condition_;
return a_->all_acceptance_conditions();
}
bdd
tgba_sgba_proxy::neg_acceptance_conditions() const
{
if (emulate_acc_cond_)
return bdd_nithvar(bdd_var(acceptance_condition_));
return a_->neg_acceptance_conditions();
}
bdd
tgba_sgba_proxy::state_acceptance_conditions(const state* state) const
{
const state_sgba_proxy* s =
down_cast<const state_sgba_proxy*>(state);
assert(s);
if (emulate_acc_cond_)
return acceptance_condition_;
return s->acceptance_cond();
}
bdd
tgba_sgba_proxy::compute_support_conditions(const state* state) const
{
const state_sgba_proxy* s =
down_cast<const state_sgba_proxy*>(state);
assert(s);
if (emulate_acc_cond_)
return acceptance_condition_;
return a_->support_conditions(s->real_state());
}
}

View file

@ -1,76 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2013, 2014 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SPOT_TGBA_TGBASGBA_HH
# define SPOT_TGBA_TGBASGBA_HH
#include "tgba.hh"
#include "misc/bddlt.hh"
namespace spot
{
/// \ingroup tgba_on_the_fly_algorithms
/// \brief Change the labeling-mode of spot::tgba on the fly, producing a
/// state-based generalized Büchi automaton.
///
/// This class acts as a proxy in front of a spot::tgba, that should
/// label on states on-the-fly. The result is still a spot::tgba,
/// but acceptances conditions are also on states.
class SPOT_API tgba_sgba_proxy : public tgba
{
public:
tgba_sgba_proxy(const const_tgba_ptr& a, bool no_zero_acc = true);
virtual ~tgba_sgba_proxy();
virtual state* get_init_state() const;
virtual tgba_succ_iterator* succ_iter(const state* state) const;
virtual bdd_dict_ptr get_dict() const;
virtual std::string format_state(const state* state) const;
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
/// \brief Retrieve the acceptance condition of a state.
bdd state_acceptance_conditions(const state* state) const;
protected:
virtual bdd compute_support_conditions(const state* state) const;
private:
const_tgba_ptr a_;
// If the automaton has no acceptance condition,
// every state is accepting.
bool emulate_acc_cond_;
bdd acceptance_condition_;
// Disallow copy.
tgba_sgba_proxy(const tgba_sgba_proxy&) SPOT_DELETED;
tgba_sgba_proxy& operator=(const tgba_sgba_proxy&) SPOT_DELETED;
};
inline tgba_sgba_proxy_ptr make_sgba(const const_tgba_ptr& a,
bool no_zero_acc = true)
{
return std::make_shared<tgba_sgba_proxy>(a, no_zero_acc);
}
}
#endif // SPOT_TGBA_TGBASGBA_HH

View file

@ -80,7 +80,7 @@ namespace spot
continue;
bdd cond = i->current_condition();
bdd acc = i->current_acceptance_conditions();
acc_cond::mark_t acc = i->current_acceptance_conditions();
tgba_run::step s = { src, cond, acc };
if (match(s, dest))

View file

@ -26,8 +26,8 @@ namespace spot
{
unsigned n = aut->num_states();
unsigned sink = -1U;
bdd allacc = aut->all_acceptance_conditions();
if (allacc == bddfalse)
acc_cond::mark_t allacc = aut->acc().all_sets();
if (allacc == 0U)
{
// We cannot safely complete an automaton if it has no
// acceptance set as the added sink would become accepting.
@ -44,7 +44,7 @@ namespace spot
for (unsigned i = 0; i < n; ++i)
{
bool selfloop = true;
bdd accsum = bddfalse;
acc_cond::mark_t accsum = 0U;
for (auto& t: aut->out(i))
{
if (t.dst != i) // Not a self-loop
@ -66,7 +66,7 @@ namespace spot
for (unsigned i = 0; i < n; ++i)
{
bdd missingcond = bddtrue;
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (auto& t: aut->out(i))
{
missingcond -= t.cond;

View file

@ -225,35 +225,11 @@ namespace spot
dict->register_all_variables_of(right, res);
dict->unregister_variable(bdd_var(v), res);
// The left and right automata might have acceptance marker in
// common.
// For the example, assume left has acceptance conditions A,B,C,D
// while right has acceptance condition C,D,E,F.
const acc_cond& la = left->acc();
const acc_cond& ra = right->acc();
res->set_acceptance_conditions(la.num_sets() + ra.num_sets());
// Negative acceptance variables...
// !A&!B&!C&!D
bdd lna = left->neg_acceptance_conditions();
// !C&!D&!E&!F
bdd rna = right->neg_acceptance_conditions();
// Missing acceptance variables...
// !E&!F
bdd lma = bdd_exist(rna, bdd_support(lna));
// !A&!B
bdd rma = bdd_exist(lna, bdd_support(rna));
// (A&!B&!C&!D + ... + !A&!B&!C&D) & !E&!F
bdd lac = left->all_acceptance_conditions() & lma;
// (C&!D&!E&!F + ... + !C&!D&!E&F) & !A&!B
bdd rac = right->all_acceptance_conditions() & rma;
bdd allacc = lac | rac;
res->set_acceptance_conditions(allacc);
// Acceptance condition to add to all transitions
// of the left automaton.
// !A&!B&!C&!D&E&!F | !A&!B&!C&!D&!E&F
bdd ladd = rac - lma;
bdd radd = lac - rma;
acc_cond::mark_t radd = ra.all_sets();
pair_map seen;
pair_queue todo;
@ -300,7 +276,7 @@ namespace spot
while (!ri || !ri->done())
{
bdd cond = lc;
bdd ra = allacc;
acc_cond::mark_t racc = radd;
if (ri)
{
cond = lc & ri->current_condition();
@ -311,7 +287,7 @@ namespace spot
continue;
}
d.second = ri->current_state();
ra = (ri->current_acceptance_conditions() & rma) | radd;
racc = ri->current_acceptance_conditions();
}
int dest;
@ -327,8 +303,10 @@ namespace spot
todo.push_back(d);
}
bdd la = (li->current_acceptance_conditions() & lma) | ladd;
res->new_transition(src, dest, bdd_exist(cond, v), ra & la);
acc_cond::mark_t a =
res->acc().join(la, li->current_acceptance_conditions(),
ra, racc);
res->new_transition(src, dest, bdd_exist(cond, v), a);
if (ri)
ri->next();

View file

@ -25,6 +25,7 @@
#include <deque>
#include <vector>
#include <algorithm>
#include <iterator>
#include "tgbaalgos/scc.hh"
#include "tgba/bddprint.hh"
@ -72,7 +73,7 @@ namespace spot
class outgoing_acc
{
const_tgba_ptr a_;
typedef std::pair<bdd, bdd> cache_entry;
typedef std::pair<acc_cond::mark_t, acc_cond::mark_t> cache_entry;
typedef std::unordered_map<const state*, cache_entry,
state_ptr_hash, state_ptr_equal> cache_t;
cache_t cache_;
@ -86,8 +87,8 @@ namespace spot
cache_t::const_iterator fill_cache(const state* s)
{
unsigned s1 = sm_ ? sm_->scc_of_state(s) : 0;
bdd common = a_->all_acceptance_conditions();
bdd union_ = bddfalse;
acc_cond::mark_t common = a_->acc().all_sets();
acc_cond::mark_t union_ = 0U;
for (auto it: a_->succ(s))
{
// Ignore transitions that leave the SCC of s.
@ -97,7 +98,7 @@ namespace spot
if (s2 != s1)
continue;
bdd set = it->current_acceptance_conditions();
acc_cond::mark_t set = it->current_acceptance_conditions();
common &= set;
union_ |= set;
}
@ -106,7 +107,7 @@ namespace spot
}
// Intersection of all outgoing acceptance sets
bdd common_acc(const state* s)
acc_cond::mark_t common_acc(const state* s)
{
cache_t::const_iterator i = cache_.find(s);
if (i == cache_.end())
@ -115,7 +116,7 @@ namespace spot
}
// Union of all outgoing acceptance sets
bdd union_acc(const state* s)
acc_cond::mark_t union_acc(const state* s)
{
cache_t::const_iterator i = cache_.find(s);
if (i == cache_.end())
@ -146,11 +147,10 @@ namespace spot
auto p = cache_.emplace(s, false);
if (p.second)
{
bdd all = a_->all_acceptance_conditions();
for (auto it: a_->succ(s))
{
// Look only for transitions that are accepting.
if (all != it->current_acceptance_conditions())
if (!a_->acc().accepting(it->current_acceptance_conditions()))
continue;
// Look only for self-loops.
const state* dest = uniq_(it->current_state());
@ -168,37 +168,23 @@ namespace spot
// Order of accepting sets (for one SCC)
class acc_order
{
std::vector<bdd> order_;
bdd found_;
std::vector<unsigned> order_;
acc_cond::mark_t found_;
public:
unsigned
next_level(bdd all, int slevel, bdd acc, bool skip_levels)
next_level(const acc_cond& acc, int slevel,
acc_cond::mark_t set, bool skip_levels)
{
bdd temp = acc;
if (all != found_)
{
// Check for new conditions in acc
if ((acc & found_) != acc)
{
bdd acc_t = acc;
while (acc_t != bddfalse)
{
bdd next = bdd_satone(acc_t);
acc_t -= next;
// Add new condition
if ((next & found_) != next)
{
order_.push_back(next);
found_ |= next;
}
}
}
}
// Update the order with any new set we discover
if (auto newsets = set - found_)
{
acc.fill_from(newsets, std::back_inserter(order_));
found_ |= newsets;
}
acc = temp;
unsigned next = slevel;
while (next < order_.size() && bdd_implies(order_[next], acc))
while (next < order_.size() && set.has(order_[next]))
{
++next;
if (!skip_levels)
@ -208,44 +194,41 @@ namespace spot
}
void
print(int scc, const bdd_dict_ptr dict)
print(int scc)
{
std::vector<bdd>::iterator i;
std::cout << "Order_" << scc << ":\t";
for (i = order_.begin(); i != order_.end(); i++)
{
bdd_print_acc(std::cout, dict, *i);
std::cout << ", ";
}
std::cout << std::endl;
for (auto i: order_)
std::cout << i << ", ";
std::cout << '\n';
}
};
// Accepting order for each SCC
class scc_orders
{
bdd all_;
const acc_cond& acc_;
std::map<int, acc_order> orders_;
bool skip_levels_;
public:
scc_orders(bdd all, bool skip_levels):
all_(all), skip_levels_(skip_levels)
scc_orders(const acc_cond& acc, bool skip_levels):
acc_(acc), skip_levels_(skip_levels)
{
}
unsigned
next_level(int scc, int slevel, bdd acc)
next_level(int scc, int slevel, acc_cond::mark_t set)
{
return orders_[scc].next_level(all_, slevel, acc, skip_levels_);
return orders_[scc].next_level(acc_, slevel, set, skip_levels_);
}
void
print(const bdd_dict_ptr dict)
print()
{
std::map<int, acc_order>::iterator i;
for (i = orders_.begin(); i != orders_.end(); i++)
i->second.print(i->first, dict);
i->second.print(i->first);
}
};
@ -273,26 +256,23 @@ namespace spot
// be used as a level in degen_state to indicate the next expected
// acceptance set. Level order.size() is a special level used to
// denote accepting states.
std::vector<bdd> order;
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.)
bdd all = a->all_acceptance_conditions();
while (all != bddfalse)
{
bdd next = bdd_satone(all);
all -= next;
order.push_back(next);
}
unsigned n = a->acc().num_sets();
for (unsigned i = n; i > 0; --i)
order.push_back(i - 1);
}
// Initialize scc_orders
bdd allacc = a->all_acceptance_conditions();
scc_orders orders(a->all_acceptance_conditions(), skip_levels);
scc_orders orders(a->acc(), skip_levels);
// Make sure we always use the same pointer for identical states
// from the input automaton.
@ -340,11 +320,12 @@ namespace spot
// start on the associated level.
if (s.second == 0)
{
bdd acc = outgoing.common_acc(s.first);
auto set = outgoing.common_acc(s.first);
if (use_cust_acc_orders)
s.second = orders.next_level(m.initial(), s.second, acc);
s.second = orders.next_level(m.initial(), s.second, set);
else
while (s.second < order.size() && bdd_implies(order[s.second], acc))
while (s.second < order.size()
&& set.has(order[s.second]))
{
++s.second;
if (!skip_levels)
@ -405,13 +386,13 @@ namespace spot
}
// The old level is slevel. What should be the new one?
bdd acc = i->current_acceptance_conditions();
bdd otheracc = outgoing.common_acc(d.first);
auto acc = i->current_acceptance_conditions();
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
// prev below) if it is common to all other outgoing
// transitions (of the current state) AND if it is not
// used by any outgoing transition of the destination
// state.
@ -447,12 +428,12 @@ namespace spot
if (!order.empty())
{
unsigned prev = order.size() - 1;
bdd common = outgoing.common_acc(s.first);
if (bdd_implies(order[prev], common))
auto common = outgoing.common_acc(s.first);
if (common.has(order[prev]))
{
bdd u = outgoing.union_acc(d.first);
if (!bdd_implies(order[prev], u))
acc -= order[prev];
auto u = outgoing.union_acc(d.first);
if (!u.has(order[prev]))
acc -= a->acc().mark(order[prev]);
}
}
}
@ -523,7 +504,7 @@ namespace spot
// are not skipping levels.
if (skip_levels || !is_acc)
while (next < order.size()
&& bdd_implies(order[next], acc))
&& acc.has(order[next]))
{
++next;
if (!skip_levels)
@ -545,7 +526,7 @@ namespace spot
{
d.second = 0; // Make it go to the first level.
// Skip levels as much as possible.
if (acc != allacc && !skip_levels)
if (!a->acc().accepting(acc) && !skip_levels)
{
if (use_cust_acc_orders)
{
@ -554,7 +535,7 @@ namespace spot
else
{
while (d.second < order.size() &&
bdd_implies(order[d.second], acc))
acc.has(order[d.second]))
++d.second;
}
}

View file

@ -73,9 +73,8 @@ namespace spot
else
{
si->first();
accepting = ((!si->done())
&& (si->current_acceptance_conditions() ==
aut_->all_acceptance_conditions()));
auto a = si->current_acceptance_conditions();
accepting = !si->done() && aut_->acc().accepting(a);
}
}
else
@ -96,10 +95,13 @@ namespace spot
{
std::string label =
bdd_format_formula(aut_->get_dict(),
si->current_condition())
+ "\n"
+ bdd_format_accset(aut_->get_dict(),
si->current_acceptance_conditions());
si->current_condition());
auto a = si->current_acceptance_conditions();
if (a)
{
label += "\n";
label += aut_->acc().format(a);
}
std::string s = aut_->transition_annotation(si);
if (!s.empty())

View file

@ -436,7 +436,7 @@ namespace spot
}
}
bdd all_acc = ref->all_acceptance_conditions();
const acc_cond& ra = ref->acc();
// construction of contraints (4,5) : all loops in the product
// where no accepting run is detected in the ref. automaton,
@ -477,7 +477,7 @@ namespace spot
if (sm.scc_of(dp) != q1p_scc)
continue;
if (tr.acc == all_acc)
if (ra.accepting(tr.acc))
continue;
for (unsigned q3 = 0; q3 < d.cand_size; ++q3)
{
@ -574,7 +574,7 @@ namespace spot
{
// We only care about the looping case if
// it is accepting in the reference.
if (tr.acc != all_acc)
if (!ra.accepting(tr.acc))
continue;
bdd all = tr.cond;
while (all != bddfalse)
@ -636,7 +636,7 @@ namespace spot
auto autdict = aut->get_dict();
auto a = make_tgba_digraph(autdict);
a->copy_ap_of(aut);
bdd acc = a->set_single_acceptance_set();
acc_cond::mark_t acc = a->set_single_acceptance_set();
a->new_states(satdict.cand_size);
unsigned last_aut_trans = -1U;

View file

@ -28,18 +28,20 @@ namespace spot
// Clone the original automaton.
tgba_digraph_ptr res = tgba_dupexp_dfs(aut);
bdd oldaccs = aut->all_acceptance_conditions();
bdd oldnegs = aut->neg_acceptance_conditions();
// Copy the old acceptance condition before we replace it.
acc_cond oldacc = aut->acc(); // Copy it!
// We will modify res in place, and the resulting
// automaton will only have one acceptance set.
// This changes aut->acc();
res->set_single_acceptance_set();
unsigned num_acc = aut->number_of_acceptance_conditions();
unsigned num_sets = oldacc.num_sets();
unsigned n = res->num_states();
// We will duplicate the automaton as many times as we have
// acceptance sets, and we need one extra sink state.
res->new_states(num_acc * n + 1);
res->new_states(num_sets * n + 1);
unsigned sink = res->num_states() - 1;
// The sink state has an accepting self-loop.
res->new_acc_transition(sink, sink, bddtrue);
@ -54,29 +56,26 @@ namespace spot
if (t.dst >= n) // Ignore transitions we added.
break;
missingcond -= t.cond;
bdd curacc = t.acc;
acc_cond::mark_t curacc = t.acc;
// The original transition must not accept anymore.
t.acc = bddfalse;
t.acc = 0U;
// Transition that were fully accepting are never cloned.
if (curacc == oldaccs)
if (oldacc.accepting(curacc))
continue;
// Save t.cond and t.dst as the reference to t
// is invalided by calls to new_transition().
unsigned dst = t.dst;
bdd cond = t.cond;
// We want all acceptance bdd variable to appear in curacc.
if (curacc == bddfalse)
curacc = oldnegs;
// Iterate over all the acceptance conditions in 'curacc',
// an duplicate it each each clone for which it does not
// an duplicate it for each clone for which it does not
// belong to the acceptance set.
unsigned add = 0;
while (curacc != bddtrue)
for (unsigned set = 0; set < num_sets; ++set)
{
add += n;
bdd h = bdd_high(curacc);
if (h == bddfalse)
if (!oldacc.has(curacc, set))
{
// Clone the transition
res->new_acc_transition(src + add, dst + add, cond);
@ -93,26 +92,9 @@ namespace spot
// arc set would be better.
if (dst <= src)
res->new_transition(src, dst + add, cond);
curacc = bdd_low(curacc);
}
else
{
// We know that only one variable can be positive
// on any branch, so since we have just seen such
// a variable, we want to go to explore its LOW
// branch for more positive variables. The only
// case where we will not do that is if the LOW
// branch is false. In that case we take the HIGH
// branch to enumerate all the remaining negated
// variables.
bdd tmp = bdd_low(curacc);
if (tmp != bddfalse)
curacc = tmp;
else
curacc = h;
}
}
assert(add == num_acc * n);
assert(add == num_sets * n);
}
// Complete the original automaton.
if (missingcond != bddfalse)
@ -134,21 +116,18 @@ namespace spot
true, // inherently_weak
true); // deterministic
bdd oldaccs = aut->all_acceptance_conditions();
bdd oldnegs = aut->neg_acceptance_conditions();
scc_info si(res);
// We will modify res in place, and the resulting
// automaton will only have one acceptance set.
bdd all_acc = res->set_single_acceptance_set();
acc_cond::mark_t all_acc = res->set_single_acceptance_set();
res->prop_state_based_acc();
unsigned sink = res->num_states();
for (unsigned src = 0; src < sink; ++src)
{
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
unsigned scc = si.scc_of(src);
if (!si.is_accepting_scc(scc) && !si.is_trivial(scc))
acc = all_acc;

View file

@ -57,6 +57,8 @@ namespace spot
namespace
{
static bdd_dict_ptr debug_dict = 0;
static const acc_cond* debug_ref_acc = 0;
static const acc_cond* debug_cand_acc = 0;
struct transition
{
@ -120,10 +122,10 @@ namespace spot
{
unsigned src;
bdd cond;
bdd acc;
acc_cond::mark_t acc;
unsigned dst;
transition_acc(int src, bdd cond, bdd acc, int dst)
transition_acc(int src, bdd cond, acc_cond::mark_t acc, int dst)
: src(src), cond(cond), acc(acc), dst(dst)
{
}
@ -142,7 +144,7 @@ namespace spot
return true;
if (this->cond.id() > other.cond.id())
return false;
return this->acc.id() < other.acc.id();
return this->acc < other.acc;
}
bool operator==(const transition_acc& other) const
@ -150,7 +152,7 @@ namespace spot
return (this->src == other.src
&& this->dst == other.dst
&& this->cond.id() == other.cond.id()
&& this->acc.id() == other.acc.id());
&& this->acc == other.acc);
}
};
@ -160,19 +162,19 @@ namespace spot
unsigned src_ref;
unsigned dst_cand;
unsigned dst_ref;
bdd acc_cand;
bdd acc_ref;
acc_cond::mark_t acc_cand;
acc_cond::mark_t acc_ref;
path(unsigned src_cand, unsigned src_ref)
: src_cand(src_cand), src_ref(src_ref),
dst_cand(src_cand), dst_ref(src_ref),
acc_cand(bddfalse), acc_ref(bddfalse)
acc_cand(0U), acc_ref(0U)
{
}
path(unsigned src_cand, unsigned src_ref,
unsigned dst_cand, unsigned dst_ref,
bdd acc_cand, bdd acc_ref)
acc_cond::mark_t acc_cand, acc_cond::mark_t acc_ref)
: src_cand(src_cand), src_ref(src_ref),
dst_cand(dst_cand), dst_ref(dst_ref),
acc_cand(acc_cand), acc_ref(acc_ref)
@ -197,13 +199,13 @@ namespace spot
return true;
if (this->dst_ref > other.dst_ref)
return false;
if (this->acc_ref.id() < other.acc_ref.id())
if (this->acc_ref < other.acc_ref)
return true;
if (this->acc_ref.id() > other.acc_ref.id())
if (this->acc_ref > other.acc_ref)
return false;
if (this->acc_cand.id() < other.acc_cand.id())
if (this->acc_cand < other.acc_cand)
return true;
if (this->acc_cand.id() > other.acc_cand.id())
if (this->acc_cand > other.acc_cand)
return false;
return false;
@ -224,7 +226,7 @@ namespace spot
{
os << '<' << t.src << ','
<< bdd_format_formula(debug_dict, t.cond) << ','
<< bdd_format_accset(debug_dict, t.acc)
<< debug_cand_acc->format(t.acc)
<< ',' << t.dst << '>';
return os;
}
@ -236,15 +238,15 @@ namespace spot
<< p.src_ref << ','
<< p.dst_cand << ','
<< p.dst_ref << ", "
<< bdd_format_accset(debug_dict, p.acc_cand) << ", "
<< bdd_format_accset(debug_dict, p.acc_ref) << '>';
<< debug_cand_acc->format(p.acc_cand) << ", "
<< debug_ref_acc->format(p.acc_ref) << '>';
return os;
}
struct dict
{
dict(const const_tgba_ptr& a)
: aut(a)
: aut(a), cacc(a->get_dict())
{
}
@ -267,16 +269,15 @@ namespace spot
// int_map int_to_state;
unsigned cand_size;
unsigned int cand_nacc;
std::vector<bdd> cand_acc; // size cand_nacc
std::vector<acc_cond::mark_t> cand_acc; // size cand_nacc
std::vector<bdd> all_cand_acc;
std::vector<bdd> all_ref_acc;
bdd cand_all_acc;
bdd ref_all_acc;
std::vector<acc_cond::mark_t> all_cand_acc;
std::vector<acc_cond::mark_t> all_ref_acc;
std::vector<bool> is_weak_scc;
acc_cond cacc;
~dict()
{
aut->get_dict()->unregister_all_my_variables(this);
@ -288,48 +289,27 @@ namespace spot
dict& d, bdd ap, bool state_based, scc_info& sm)
{
bdd_dict_ptr bd = aut->get_dict();
ltl::default_environment& env = ltl::default_environment::instance();
d.cand_acc.resize(d.cand_nacc);
d.all_cand_acc.push_back(bddfalse);
bdd allneg = bddtrue;
d.cacc.add_sets(d.cand_nacc);
d.all_cand_acc.push_back(0U);
for (unsigned n = 0; n < d.cand_nacc; ++n)
{
std::ostringstream s;
s << n;
const ltl::formula* af = env.require(s.str());
int v = bd->register_acceptance_variable(af, &d);
af->destroy();
d.cand_acc[n] = bdd_ithvar(v);
allneg &= bdd_nithvar(v);
}
for (unsigned n = 0; n < d.cand_nacc; ++n)
{
bdd c = bdd_exist(allneg, d.cand_acc[n]) & d.cand_acc[n];
auto c = d.cacc.mark(n);
d.cand_acc[n] = c;
size_t s = d.all_cand_acc.size();
for (size_t i = 0; i < s; ++i)
d.all_cand_acc.push_back(d.all_cand_acc[i] | c);
}
d.cand_all_acc = bdd_support(allneg);
d.ref_all_acc = bdd_support(aut->all_acceptance_conditions());
bdd refall = d.ref_all_acc;
bdd refnegall = aut->neg_acceptance_conditions();
d.all_ref_acc.push_back(bddfalse);
while (refall != bddtrue)
d.all_ref_acc.push_back(0U);
unsigned ref_nacc = aut->acc().num_sets();
for (unsigned n = 0; n < ref_nacc; ++n)
{
bdd v = bdd_ithvar(bdd_var(refall));
bdd c = bdd_exist(refnegall, v) & v;
auto c = aut->acc().mark(n);
size_t s = d.all_ref_acc.size();
for (size_t i = 0; i < s; ++i)
d.all_ref_acc.push_back(d.all_ref_acc[i] | c);
refall = bdd_high(refall);
}
unsigned ref_size = aut->num_states();
@ -485,9 +465,12 @@ namespace spot
#if DEBUG
debug_dict = ref->get_dict();
debug_ref_acc = &ref->acc();
debug_cand_acc = &d.cacc;
dout << "ref_size: " << ref_size << '\n';
dout << "cand_size: " << d.cand_size << '\n';
#endif
auto& racc = ref->acc();
dout << "symmetry-breaking clauses\n";
int j = 0;
@ -586,8 +569,6 @@ namespace spot
}
}
bdd all_acc = ref->all_acceptance_conditions();
// construction of constraints (11,12,13)
for (unsigned q1p = 0; q1p < ref_size; ++q1p)
{
@ -630,7 +611,7 @@ namespace spot
for (unsigned q3 = 0; q3 < d.cand_size; ++q3)
{
bdd all = tr.cond;
bdd curacc = tr.acc;
acc_cond::mark_t curacc = tr.acc;
while (all != bddfalse)
{
bdd l = bdd_satoneset(all, ap, bddfalse);
@ -643,23 +624,22 @@ namespace spot
{
if ((!is_acc) ||
(!is_weak &&
(curacc |
d.all_ref_acc[fp]) != all_acc))
!racc.accepting
(curacc | d.all_ref_acc[fp])))
{
#if DEBUG
dout << "(11) " << p << ""
<< t << "δ → ¬(";
bdd all_ = d.all_cand_acc.back();
all_ -= d.all_cand_acc[f];
bool notfirst = false;
while (all_ != bddfalse)
acc_cond::mark_t all_ =
d.all_cand_acc.back() -
d.all_cand_acc[f];
for (auto m: d.cacc.sets(all_))
{
bdd one = bdd_satone(all_);
all_ -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
if (notfirst)
out << "";
else
@ -671,15 +651,14 @@ namespace spot
out << -pid << ' ' << -ti;
// 11
bdd all_f = d.all_cand_acc.back();
all_f -= d.all_cand_acc[f];
while (all_f != bddfalse)
acc_cond::mark_t all_f =
d.all_cand_acc.back() -
d.all_cand_acc[f];
for (auto m: d.cacc.sets(all_f))
{
bdd one = bdd_satone(all_f);
all_f -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
int tai = d.transaccid[ta];
assert(tai != 0);
out << ' ' << -tai;
@ -692,17 +671,15 @@ namespace spot
#if DEBUG
dout << "(12) " << p << ""
<< t << "δ → (";
bdd all_ = d.all_cand_acc.back();
all_ -= d.all_cand_acc[f];
bool notfirst = false;
while (all_ != bddfalse)
// 11
acc_cond::mark_t all_ =
d.cacc.comp(d.all_cand_acc[f]);
for (auto m: d.cacc.sets(all_))
{
bdd one = bdd_satone(all_);
all_ -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
if (notfirst)
out << "";
else
@ -712,15 +689,13 @@ namespace spot
out << ")\n";
#endif // DEBUG
// 12
bdd all_f = d.all_cand_acc.back();
all_f -= d.all_cand_acc[f];
while (all_f != bddfalse)
acc_cond::mark_t all_f =
d.cacc.comp(d.all_cand_acc[f]);
for (auto m: d.cacc.sets(all_f))
{
bdd one = bdd_satone(all_f);
all_f -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
int tai = d.transaccid[ta];
assert(tai != 0);
@ -735,10 +710,9 @@ namespace spot
size_t sf = d.all_cand_acc.size();
for (size_t f = 0; f < sf; ++f)
{
bdd f2 = p.acc_cand |
d.all_cand_acc[f];
bdd f2p = bddfalse;
acc_cond::mark_t f2 =
p.acc_cand | d.all_cand_acc[f];
acc_cond::mark_t f2p = 0U;
if (!is_weak)
f2p = p.acc_ref | curacc;
@ -751,47 +725,34 @@ namespace spot
dout << "(13) " << p << ""
<< t << "δ ";
bdd biga_ = d.all_cand_acc[f];
while (biga_ != bddfalse)
auto biga_ = d.all_cand_acc[f];
for (unsigned m = 0;
m < d.cand_nacc; ++m)
{
bdd a = bdd_satone(biga_);
biga_ -= a;
transition_acc ta(q2, l, a, q3);
out << "" << ta << "FC";
}
biga_ = d.all_cand_acc.back()
- d.all_cand_acc[f];
while (biga_ != bddfalse)
{
bdd a = bdd_satone(biga_);
biga_ -= a;
transition_acc ta(q2, l, a, q3);
out << " ∧ ¬" << ta << "FC";
transition_acc
ta(q2, l,
d.cacc.mark(m), q3);
int tai = d.transaccid[ta];
const char* not_ = "¬";
if (d.cacc.has(biga_, m))
not_ = "";
out << tai << ' ';
out << "" << not_
<< ta << "FC";
}
out << "" << p2 << '\n';
#endif
out << -pid << ' ' << -ti << ' ';
bdd biga = d.all_cand_acc[f];
while (biga != bddfalse)
auto biga = d.all_cand_acc[f];
for (unsigned m = 0;
m < d.cand_nacc; ++m)
{
bdd a = bdd_satone(biga);
biga -= a;
transition_acc ta(q2, l, a, q3);
int tai = d.transaccid[ta];
out << -tai << ' ';
}
biga = d.all_cand_acc.back()
- d.all_cand_acc[f];
while (biga != bddfalse)
{
bdd a = bdd_satone(biga);
biga -= a;
transition_acc ta(q2, l, a, q3);
transition_acc
ta(q2, l,
d.cacc.mark(m), q3);
int tai = d.transaccid[ta];
if (d.cacc.has(biga, m))
tai = -tai;
out << tai << ' ';
}
@ -818,7 +779,7 @@ namespace spot
auto autdict = aut->get_dict();
auto a = make_tgba_digraph(autdict);
a->copy_ap_of(aut);
a->set_acceptance_conditions(satdict.all_cand_acc.back());
a->set_acceptance_conditions(satdict.cand_nacc);
a->new_states(satdict.cand_size);
@ -835,7 +796,7 @@ namespace spot
#endif
dout << "--- transition variables ---\n";
std::map<int, bdd> state_acc;
std::map<int, acc_cond::mark_t> state_acc;
std::set<src_cond> seen_trans;
for (int v: solution)
{
@ -854,7 +815,7 @@ namespace spot
if (seen_trans.insert(src_cond(t->second.src,
t->second.cond)).second)
{
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
if (state_based)
{
auto i = state_acc.find(t->second.src);
@ -887,11 +848,13 @@ namespace spot
ta->second.dst == last_sat_trans->dst)
{
assert(!state_based);
a->trans_data(last_aut_trans).acc |= ta->second.acc;
auto& v = a->trans_data(last_aut_trans).acc;
v |= ta->second.acc;
}
else if (state_based)
{
state_acc[ta->second.src] |= ta->second.acc;
auto& v = state_acc[ta->second.src];
v |= ta->second.acc;
}
}
}

View file

@ -60,9 +60,9 @@ namespace spot
const state*, int out,
const tgba_succ_iterator* si)
{
out_->new_transition(in - 1, out - 1,
si->current_condition(),
si->current_acceptance_conditions());
out_->new_transition
(in - 1, out - 1, si->current_condition(),
si->current_acceptance_conditions());
}
protected:

View file

@ -89,7 +89,7 @@ namespace spot
os << " | ";
bdd_print_formula(os, d, i->label);
os << '\t';
bdd_print_accset(os, d, i->acc);
os << a->acc().format(i->acc);
os << std::endl;
}
os << "Cycle:" << std::endl;
@ -100,7 +100,7 @@ namespace spot
os << " | ";
bdd_print_formula(os, d, i->label);
os << '\t';
bdd_print_accset(os, d, i->acc);
os << a->acc().format(i->acc);
os << '\n';
}
return os;
@ -302,7 +302,7 @@ namespace spot
unsigned src;
unsigned dst;
const tgba_run::steps* l;
bdd seen_acc = bddfalse;
acc_cond::mark_t seen_acc = 0U;
typedef std::unordered_map<const state*, unsigned,
state_ptr_hash, state_ptr_equal> state_map;
@ -323,7 +323,7 @@ namespace spot
{
// expected outgoing transition
bdd label = i->label;
bdd acc = i->acc;
acc_cond::mark_t acc = i->acc;
// compute the next expected state
const state* next;
@ -379,7 +379,7 @@ namespace spot
s->destroy();
assert(seen_acc == a->all_acceptance_conditions());
assert(a->acc().accepting(seen_acc));
return res;
}

View file

@ -269,7 +269,7 @@ namespace spot
struct step {
const state* s;
bdd label;
bdd acc;
acc_cond::mark_t acc;
};
typedef std::list<step> steps;

View file

@ -149,7 +149,7 @@ namespace spot
void
couvreur99_check_result::accepting_cycle()
{
bdd acc_to_traverse = ecs_->aut->all_acceptance_conditions();
acc_cond::mark_t acc_to_traverse = ecs_->aut->acc().all_sets();
// Compute an accepting cycle using successive BFS that are
// restarted from the point reached after we have discovered a
// transition with a new acceptance conditions.
@ -173,11 +173,11 @@ namespace spot
{
const couvreur99_check_status* ecs;
couvreur99_check_result* r;
bdd& acc_to_traverse;
acc_cond::mark_t& acc_to_traverse;
int scc_root;
scc_bfs(const couvreur99_check_status* ecs,
couvreur99_check_result* r, bdd& acc_to_traverse)
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)
@ -202,9 +202,10 @@ namespace spot
virtual bool
match(tgba_run::step& st, const state* s)
{
bdd less_acc = acc_to_traverse - st.acc;
acc_cond::mark_t less_acc =
acc_to_traverse - st.acc;
if (less_acc != acc_to_traverse
|| (acc_to_traverse == bddfalse
|| (acc_to_traverse == 0U
&& s == ecs->cycle_seed))
{
acc_to_traverse = less_acc;
@ -218,7 +219,7 @@ namespace spot
substart = b.search(substart, run_->cycle);
assert(substart);
}
while (acc_to_traverse != bddfalse || substart != ecs_->cycle_seed);
while (acc_to_traverse != 0U || substart != ecs_->cycle_seed);
}
void

View file

@ -136,7 +136,7 @@ namespace spot
// * couvreur99_check::h, a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
// * arc, a stack of acceptance conditions between each of these SCC,
std::stack<bdd> arc;
std::stack<acc_cond::mark_t> arc;
// * num, the number of visited nodes. Used to set the order of each
// visited node,
int num = 1;
@ -152,7 +152,7 @@ namespace spot
state* init = ecs_->aut->get_init_state();
ecs_->h[init] = 1;
ecs_->root.push(1);
arc.push(bddfalse);
arc.push(0U);
tgba_succ_iterator* iter = ecs_->aut->succ_iter(init);
iter->first();
todo.emplace(init, iter);
@ -207,7 +207,7 @@ namespace spot
// Fetch the values (destination state, acceptance conditions
// of the arc) we are interested in...
const state* dest = succ->current_state();
bdd acc = succ->current_acceptance_conditions();
acc_cond::mark_t acc = succ->current_acceptance_conditions();
// ... and point the iterator to the next successor, for
// the next iteration.
succ->next();
@ -265,8 +265,7 @@ namespace spot
ecs_->root.top().condition |= acc;
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
if (ecs_->root.top().condition
== ecs_->aut->all_acceptance_conditions())
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// We have found an accepting SCC.
// Release all iterators in TODO.
@ -521,7 +520,7 @@ namespace spot
// (called the "threshold").
int threshold = i->second;
std::list<const state*> rem;
bdd acc = succ.acc;
acc_cond::mark_t acc = succ.acc;
while (threshold < ecs_->root.top().index)
{
assert(!ecs_->root.empty());
@ -543,8 +542,7 @@ namespace spot
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
// Have we found all acceptance conditions?
if (ecs_->root.top().condition
== ecs_->aut->all_acceptance_conditions())
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// Use this state to start the computation of an accepting
// cycle.

View file

@ -195,9 +195,9 @@ namespace spot
protected:
struct successor {
bdd acc;
acc_cond::mark_t acc;
const spot::state* s;
successor(bdd acc, const spot::state* s): acc(acc), s(s) {}
successor(acc_cond::mark_t acc, const spot::state* s): acc(acc), s(s) {}
};
// We use five main data in this algorithm:
@ -205,7 +205,7 @@ namespace spot
// * couvreur99_check::h, a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
// * arc, a stack of acceptance conditions between each of these SCC,
std::stack<bdd> arc;
std::stack<acc_cond::mark_t> arc;
// * num, the number of visited nodes. Used to set the order of each
// visited node,
int num;

View file

@ -27,7 +27,7 @@ namespace spot
scc_stack::connected_component::connected_component(int i)
{
index = i;
condition = bddfalse;
condition = 0U;
}
scc_stack::connected_component&

View file

@ -41,9 +41,9 @@ namespace spot
/// Index of the SCC.
int index;
/// The bdd condition is the union of all acceptance conditions of
/// transitions which connect the states of the connected component.
bdd condition;
/// The union of all acceptance marks of transitions the
/// connected component.
acc_cond::mark_t condition;
std::list<const state*> rem;
};

View file

@ -54,10 +54,6 @@ namespace spot
struct gv04: public emptiness_check, public ec_statistics
{
// The unique acceptance condition of the automaton \a a,
// or bddfalse if there is no.
bdd accepting;
// Map of visited states.
typedef std::unordered_map<const state*, size_t,
state_ptr_hash, state_ptr_equal> hash_type;
@ -72,9 +68,9 @@ namespace spot
bool violation; // Whether an accepting run was found.
gv04(const const_tgba_ptr& a, option_map o)
: emptiness_check(a, o), accepting(a->all_acceptance_conditions())
: emptiness_check(a, o)
{
assert(a->number_of_acceptance_conditions() <= 1);
assert(a->acc().num_sets() <= 1);
}
~gv04()
@ -125,7 +121,8 @@ namespace spot
else
{
const state* s_prime = iter->current_state();
bool acc = iter->current_acceptance_conditions() == accepting;
bool acc =
a_->acc().accepting(iter->current_acceptance_conditions());
inc_transitions();
trace << " Next successor: s_prime = "
@ -365,7 +362,7 @@ namespace spot
virtual bool
match(tgba_run::step& step, const state*)
{
return step.acc != bddfalse;
return step.acc != 0U;
}
};
@ -386,7 +383,7 @@ namespace spot
const state* bfs_start = data.stack[scc_root].s;
const state* bfs_end = bfs_start;
if (data.accepting != bddfalse)
if (a_->acc().num_sets() > 0)
{
first_bfs b1(this, scc_root);
bfs_start = b1.search(bfs_start, res->cycle);

View file

@ -44,10 +44,6 @@ namespace spot
typedef std::vector<int> vap_t;
vap_t vap;
// Assign a number to each acceptance condition.
typedef std::map<bdd, unsigned, bdd_less_than> acc_map;
acc_map acc;
// Map each state to a number.
typedef std::unordered_map<const state*, unsigned,
state_ptr_hash, state_ptr_equal> state_map;
@ -69,40 +65,27 @@ namespace spot
metadata(const const_tgba_ptr& aut)
: state_acc(true), is_complete(true), is_deterministic(true)
{
number_all_acc(aut);
number_all_states_and_fill_sup(aut);
number_all_ap();
}
void number_all_acc(const const_tgba_ptr& aut)
{
bdd all_acc = aut->all_acceptance_conditions();
unsigned count = 0;
while (all_acc != bddfalse)
{
bdd one = bdd_satone(all_acc);
all_acc -= one;
acc[one] = count++;
}
}
std::ostream&
emit_acc(std::ostream& os, bdd b)
emit_acc(std::ostream& os,
const const_tgba_ptr& aut,
acc_cond::mark_t b)
{
// FIXME: We could use a cache for this.
if (b == bddfalse)
if (b == 0U)
return os;
os << " {";
bool notfirst = false;
while (b != bddfalse)
for (auto v: aut->acc().sets(b))
{
bdd one = bdd_satone(b);
b -= one;
if (notfirst)
os << ' ';
else
notfirst = true;
os << acc[one];
os << v;
}
os << '}';
return os;
@ -124,7 +107,7 @@ namespace spot
{
auto src = todo.front();
todo.pop_front();
bdd prev = bddtrue;
acc_cond::mark_t prev = -1U;
bool st_acc = true;
bdd sum = bddfalse;
bdd available = bddtrue;
@ -153,8 +136,8 @@ namespace spot
}
if (st_acc)
{
bdd acc = i->current_acceptance_conditions();
if (prev != bddtrue && prev != acc)
acc_cond::mark_t acc = i->current_acceptance_conditions();
if (prev != -1U && prev != acc)
st_acc = false;
else
prev = acc;
@ -265,7 +248,7 @@ namespace spot
i != md.vap.end(); ++i)
escape_str(os << " \"", to_string(d->bdd_map[*i].f)) << '"';
os << nl;
unsigned num_acc = md.acc.size();
unsigned num_acc = aut->acc().num_sets();
if (num_acc == 0)
os << "acc-name: all";
else if (num_acc == 1)
@ -309,7 +292,7 @@ namespace spot
os << "State: " << i;
if (this_acc == Hoaf_Acceptance_States && !j->done())
md.emit_acc(os, j->current_acceptance_conditions());
md.emit_acc(os, aut, j->current_acceptance_conditions());
os << nl;
for (; !j->done(); j->next())
@ -317,7 +300,7 @@ namespace spot
const state* dst = j->current_state();
os << '[' << md.sup[j->current_condition()] << "] " << md.sm[dst];
if (this_acc == Hoaf_Acceptance_Transitions)
md.emit_acc(os, j->current_acceptance_conditions());
md.emit_acc(os, aut, j->current_acceptance_conditions());
os << nl;
dst->destroy();
}

View file

@ -40,7 +40,7 @@ namespace spot
cycle_found(const state* start)
{
dfs_stack::const_reverse_iterator i = dfs_.rbegin();
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (;;)
{
acc |= i->succ->current_acceptance_conditions();
@ -51,7 +51,7 @@ namespace spot
// At least version 4.0 needs it.
assert(i != const_cast<const dfs_stack&>(dfs_).rend());
}
if (acc != aut_->all_acceptance_conditions())
if (!aut_->acc().accepting(acc))
{
// We have found an non-accepting cycle, so the SCC is not
// weak.
@ -83,9 +83,8 @@ namespace spot
// If no cycle is accepting, the SCC is weak.
if (!map.accepting(scc))
return true;
// If all transitions use all acceptance conditions, the SCC is weak.
return (map.useful_acc_of(scc)
== bdd_support(map.get_aut()->neg_acceptance_conditions()));
// If all transitions use the same acceptance set, the SCC is weak.
return map.useful_acc_of(scc).size() == 1;
}
bool
@ -128,8 +127,8 @@ namespace spot
is_terminal_scc(scc_map& map, unsigned scc)
{
// If all transitions use all acceptance conditions, the SCC is weak.
return ((map.useful_acc_of(scc) ==
bdd_support(map.get_aut()->neg_acceptance_conditions()))
return (map.accepting(scc)
&& map.useful_acc_of(scc).size() == 1
&& is_complete_scc(map, scc));
}
}

View file

@ -35,49 +35,12 @@ namespace spot
{
namespace
{
// At some point we'll need to print an acceptance set into LBTT's
// format. LBTT expects numbered acceptance sets, so first we'll
// number each acceptance condition, and later when we have to print
// them we'll just have to look up each of them.
class acceptance_cond_splitter
{
public:
acceptance_cond_splitter(bdd all_acc)
{
unsigned count = 0;
while (all_acc != bddfalse)
{
bdd acc = bdd_satone(all_acc);
all_acc -= acc;
sm[acc] = count++;
}
}
std::ostream&
split(std::ostream& os, bdd b)
{
while (b != bddfalse)
{
bdd acc = bdd_satone(b);
b -= acc;
os << sm[acc] << ' ';
}
return os;
}
private:
typedef std::map<bdd, unsigned, bdd_less_than> split_map;
split_map sm;
};
class lbtt_bfs : public tgba_reachable_iterator_breadth_first
{
public:
lbtt_bfs(const const_tgba_ptr& a, std::ostream& os, bool sba_format)
: tgba_reachable_iterator_breadth_first(a),
os_(os),
all_acc_conds_(a->all_acceptance_conditions()),
acs_(all_acc_conds_),
sba_format_(sba_format),
sba_(nullptr)
{
@ -104,7 +67,7 @@ namespace spot
// iterator.
tgba_succ_iterator* it = aut_->succ_iter(s);
bool accepting = it->first()
&& it->current_acceptance_conditions() == all_acc_conds_;
&& aut_->acc().accepting(it->current_acceptance_conditions());
aut_->release_iter(it);
return accepting;
}
@ -138,7 +101,8 @@ namespace spot
body_ << out - 1 << ' ';
if (!sba_format_)
{
acs_.split(body_, si->current_acceptance_conditions());
for (auto s: aut_->acc().sets(si->current_acceptance_conditions()))
body_ << s << ' ';
body_ << "-1 ";
}
const ltl::formula* f = bdd_to_formula(si->current_condition(),
@ -155,7 +119,7 @@ namespace spot
if (sba_format_)
os_ << '1';
else
os_ << aut_->number_of_acceptance_conditions() << 't';
os_ << aut_->acc().num_sets() << 't';
os_ << '\n' << body_.str() << "-1" << std::endl;
}
@ -163,7 +127,6 @@ namespace spot
std::ostream& os_;
std::ostringstream body_;
bdd all_acc_conds_;
acceptance_cond_splitter acs_;
bool sba_format_;
const_tgba_digraph_ptr sba_;
};
@ -196,7 +159,7 @@ namespace spot
break;
// Read the acceptance conditions.
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (;;)
{
int acc_n = 0;
@ -254,7 +217,7 @@ namespace spot
aut->set_init_state(src_state);
// Read the acceptance conditions.
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (;;)
{
int acc_n = 0;

View file

@ -141,7 +141,9 @@ namespace spot
{
public:
translate_dict(const bdd_dict_ptr& dict, ltl_simplifier* ls, bool exprop,
translate_dict(const bdd_dict_ptr& dict,
acc_cond& acc,
ltl_simplifier* ls, bool exprop,
bool single_acc)
: dict(dict),
ls(ls),
@ -150,7 +152,8 @@ namespace spot
next_set(bddtrue),
transdfa(*this),
exprop(exprop),
single_acc(single_acc)
single_acc(single_acc),
acc(acc)
{
}
@ -184,6 +187,9 @@ namespace spot
ratexp_to_dfa transdfa;
bool exprop;
bool single_acc;
acc_cond& acc;
// Map BDD variables to acceptance marks.
std::map<int, unsigned> bm;
enum translate_flags
{
@ -231,6 +237,7 @@ namespace spot
public:
int
register_proposition(const formula* f)
{
@ -239,6 +246,30 @@ namespace spot
return num;
}
acc_cond::mark_t
bdd_to_mark(bdd a)
{
bdd o = a;
if (a == bddtrue)
return 0U;
assert(a != bddfalse);
std::vector<unsigned> t;
do
{
int v = bdd_var(a);
bdd h = bdd_high(a);
a = bdd_low(a);
if (h != bddfalse)
{
t.push_back(bm[v]);
if (a == bddfalse)
a = h;
}
}
while (a != bddtrue);
return acc.marks(t.begin(), t.end());
}
int
register_a_variable(const formula* f)
{
@ -247,6 +278,10 @@ namespace spot
int num = dict->register_acceptance_variable
(ltl::constant::true_instance(), this);
a_set &= bdd_ithvar(num);
auto p = bm.emplace(num, 0U);
if (p.second)
p.first->second = acc.add_set();
return num;
}
// A promise of 'x', noted P(x) is pretty much like the F(x)
@ -297,6 +332,11 @@ namespace spot
int num = dict->register_acceptance_variable(g, this);
a_set &= bdd_ithvar(num);
g->destroy();
auto p = bm.emplace(num, 0U);
if (p.second)
p.first->second = acc.add_set();
return num;
}
else
@ -316,6 +356,11 @@ namespace spot
}
int num = dict->register_acceptance_variable(f, this);
a_set &= bdd_ithvar(num);
auto p = bm.emplace(num, 0U);
if (p.second)
p.first->second = acc.add_set();
return num;
}
@ -2105,7 +2150,10 @@ namespace spot
assert(dict == s->get_dict());
translate_dict d(dict, s, exprop, f->is_syntactic_persistence());
tgba_digraph_ptr a = make_tgba_digraph(dict);
auto namer = a->create_namer<const formula*, formula_ptr_hash>();
translate_dict d(dict, a->acc(), s, exprop, f->is_syntactic_persistence());
// Compute the set of all promises that can possibly occur
// inside the formula.
@ -2154,8 +2202,6 @@ namespace spot
bdd all_events = observable_events | unobservable_events;
tgba_digraph_ptr a = make_tgba_digraph(dict);
auto namer = a->create_namer<const formula*, formula_ptr_hash>();
// This is in case the initial state is equivalent to true...
if (symb_merge)
@ -2341,7 +2387,7 @@ namespace spot
formulae_to_translate.insert(truef);
namer->new_state(truef);
}
namer->new_transition(now, truef, cond_for_true, bddtrue);
namer->new_transition(now, truef, cond_for_true, 0U);
}
// Register other transitions.
for (i = dests.begin(); i != dests.end(); ++i)
@ -2365,7 +2411,7 @@ namespace spot
if (!reachable && !seen)
namer->new_state(dest);
reachable = true;
namer->new_transition(now, dest, cond, j.first);
namer->new_transition(now, dest, cond, d.bdd_to_mark(j.first));
}
if (reachable && !seen)
@ -2380,21 +2426,15 @@ namespace spot
delete namer;
dict->register_propositions(fc.used_vars(), a);
a->set_acceptance_conditions(d.a_set);
// Turn all promises into real acceptance conditions.
acc_compl ac(a->all_acceptance_conditions(),
a->neg_acceptance_conditions());
unsigned ns = a->num_states();
for (unsigned s = 0; s < ns; ++s)
for (auto& t: a->out(s))
t.acc = ac.reverse_complement(t.acc);
t.acc = a->acc().comp(t.acc);
if (!simplifier)
// This should not be deleted before we have registered all propositions.
delete s;
return a;
}

View file

@ -57,10 +57,9 @@ namespace spot
magic_search_(const const_tgba_ptr& a, size_t size,
option_map o = option_map())
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
h(size)
{
assert(a->number_of_acceptance_conditions() <= 1);
assert(a->acc().num_sets() <= 1);
}
virtual ~magic_search_()
@ -98,7 +97,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, BLUE);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
if (dfs_blue())
return std::make_shared<magic_search_result>(t, options());
}
@ -151,7 +150,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -179,9 +178,6 @@ namespace spot
/// State targeted by the red dfs.
const state* target;
/// The unique acceptance condition of the automaton \a a.
bdd all_cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -194,7 +190,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -208,7 +204,7 @@ namespace spot
}
else
{
if (acc == all_cond && c.get_color() != RED)
if (a_->acc().accepting(acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -239,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() &&
f_dest.acc == all_cond && 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
@ -281,7 +277,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();

View file

@ -46,7 +46,7 @@ namespace spot
{
struct stack_item
{
stack_item(const state* n, tgba_succ_iterator* i, bdd l, bdd a)
stack_item(const state* n, tgba_succ_iterator* i, bdd l, acc_cond::mark_t a)
: s(n), it(i), label(l), acc(a) {};
/// The visited state.
const state* s;
@ -57,7 +57,7 @@ namespace spot
bdd label;
/// The acceptance set of the transition traversed to reach \a s
/// (false for the first one).
bdd acc;
acc_cond::mark_t acc;
};
typedef std::list<stack_item> stack_type;
@ -112,7 +112,7 @@ namespace spot
assert(!stb.empty());
bdd covered_acc = bddfalse;
acc_cond::mark_t covered_acc = 0U;
accepting_transitions_list acc_trans;
const state* start;
@ -120,7 +120,7 @@ namespace spot
start = stb.front().s->clone();
if (!str.empty())
{
if (a_->number_of_acceptance_conditions() == 0)
if (a_->acc().num_sets() == 0)
{
// take arbitrarily the last transition on the red stack
stack_type::const_iterator i, j;
@ -164,7 +164,7 @@ namespace spot
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;
@ -184,7 +184,7 @@ namespace spot
}
}
if (a_->all_acceptance_conditions() != covered_acc)
if (!a_->acc().accepting(covered_acc))
{
bool b = dfs(start, acc_trans, covered_acc);
assert(b);
@ -222,7 +222,7 @@ namespace spot
struct transition {
const state* source;
bdd label;
bdd acc;
acc_cond::mark_t acc;
const state* dest;
};
typedef std::list<transition> accepting_transitions_list;
@ -253,7 +253,7 @@ namespace spot
}
bool dfs(const state* target, accepting_transitions_list& acc_trans,
bdd& covered_acc)
acc_cond::mark_t& covered_acc)
{
assert(h_.has_been_visited(target));
stack_type st1;
@ -264,7 +264,7 @@ namespace spot
seen.insert(start);
tgba_succ_iterator* i = a_->succ_iter(start);
i->first();
st1.emplace_front(start, i, bddfalse, bddfalse);
st1.emplace_front(start, i, bddfalse, 0U);
while (!st1.empty())
{
@ -277,7 +277,7 @@ namespace spot
ndfsr_trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
f.it->next();
if (h_.has_been_visited(s_prime))
{
@ -308,7 +308,7 @@ namespace spot
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
covered_acc |= acc;
if (covered_acc == a_->all_acceptance_conditions())
if (a_->acc().accepting(covered_acc))
{
clean(a_, st1, seen, dead);
s_prime->destroy();
@ -337,7 +337,7 @@ namespace spot
stack_item f_dest(f);
a_->release_iter(st1.front().it);
st1.pop_front();
if (!st1.empty() && (f_dest.acc & covered_acc) != f_dest.acc)
if (!st1.empty() && ((f_dest.acc & covered_acc) != f_dest.acc))
{
ndfsr_trace << " a propagation is needed, start a search"
<< std::endl;
@ -349,8 +349,8 @@ namespace spot
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
covered_acc |= f_dest.acc;
if (covered_acc == a_->all_acceptance_conditions())
covered_acc |= f_dest.acc;
if (a_->acc().accepting(covered_acc))
{
clean(a_, st1, seen, dead);
return true;
@ -607,6 +607,7 @@ namespace spot
<< a_->format_state(begin) << std::endl;
transition tmp;
tmp.source = tmp.dest = 0; // Initialize to please GCC 4.0.1 (Darwin).
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);
@ -621,6 +622,7 @@ namespace spot
m_source_trans target;
transition tmp;
tmp.source = tmp.dest = 0; // Initialize to please GCC 4.0.
tmp.acc = 0U;
// Register all states from the cycle as target of the BFS.
for (tgba_run::steps::const_iterator i = run->cycle.begin();

View file

@ -41,7 +41,7 @@ namespace spot
const ltl::formula* f, bool comments)
: tgba_reachable_iterator_breadth_first(a),
os_(os), f_(f), accept_all_(-1), fi_needed_(false),
comments_(comments), all_acc_conds_(a->all_acceptance_conditions()),
comments_(comments),
sba_(std::dynamic_pointer_cast<const tgba_digraph>(a))
{
assert(!sba_ || sba_->has_state_based_acc());
@ -87,8 +87,8 @@ namespace spot
// is not terribly efficient since we have to create the
// iterator.
tgba_succ_iterator* it = aut_->succ_iter(s);
bool accepting =
it->first() && it->current_acceptance_conditions() == all_acc_conds_;
bool accepting = it->first()
&& aut_->acc().accepting(it->current_acceptance_conditions());
aut_->release_iter(it);
return accepting;
}
@ -193,7 +193,6 @@ namespace spot
bool fi_needed_;
state* init_;
bool comments_;
bdd all_acc_conds_;
const_tgba_digraph_ptr sba_;
};
} // anonymous
@ -202,7 +201,7 @@ namespace spot
never_claim_reachable(std::ostream& os, const const_tgba_ptr& g,
const ltl::formula* f, bool comments)
{
assert(g->number_of_acceptance_conditions() <= 1);
assert(g->acc().num_sets() <= 1);
never_claim_bfs n(g, os, f, comments);
n.run();
return os;

View file

@ -142,7 +142,7 @@ namespace spot
if (type_ == BA)
state_based_ = true;
int original_acc = a->number_of_acceptance_conditions();
int original_acc = a->acc().num_sets();
// Remove useless SCCs.
if (type_ == Monitor)
@ -237,7 +237,7 @@ namespace spot
if (PREF_ == Deterministic
&& f
&& f->is_syntactic_recurrence()
&& sim->number_of_acceptance_conditions() > 1)
&& sim->acc().num_sets() > 1)
tmpd = degeneralize_tba(sim);
auto in = tmpd ? tmpd : sim;
@ -306,7 +306,7 @@ namespace spot
// because the input TBA might be smaller.
if (state_based_)
in = degeneralize(dba);
else if (dba->number_of_acceptance_conditions() != 1)
else if (dba->acc().num_sets() != 1)
in = degeneralize_tba(dba);
else
in = dba;
@ -354,8 +354,7 @@ namespace spot
// 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->number_of_acceptance_conditions() == 1))
&& !(dba_is_minimal && state_based_ && dba->acc().num_sets() == 1))
dba = degeneralize(dba);
if (dba && sim)

View file

@ -165,7 +165,7 @@ namespace spot
// print_set(std::cerr, *j) << '\n';
// }
bdd acc = aut_->all_acceptance_conditions();
auto acc = aut_->acc().all_sets();
for (auto i: all_)
i->acc = acc;
return threshold_ != 0 && cycles_left_ == 0;
@ -316,7 +316,7 @@ namespace spot
{
if (f == 0 && neg_aut == 0)
return 0;
if (aut->number_of_acceptance_conditions() > 1)
if (aut->acc().num_sets() > 1)
return 0;
auto det = tba_determinize(aut, threshold_states, threshold_cycles);

View file

@ -35,20 +35,12 @@ namespace spot
namespace
{
std::string
acc(int n)
{
std::stringstream s;
s << n;
return "a" + s.str();
}
void
random_labels(tgba_digraph_ptr aut,
unsigned src,
unsigned dest,
int* props, int props_n, float t,
const std::list<bdd>& accs, float a)
unsigned n_accs, float a)
{
int val = 0;
int size = 0;
@ -70,21 +62,18 @@ namespace spot
if (size > 0)
p &= bdd_ibuildcube(val, size, props);
bdd ac = bddfalse;
for (std::list<bdd>::const_iterator i = accs.begin();
i != accs.end(); ++i)
acc_cond::mark_t m = 0U;
for (unsigned i = 0U; i < n_accs; ++i)
if (drand() < a)
ac |= *i;
aut->new_transition(src, dest, p, ac);
m |= aut->acc().mark(i);
aut->new_transition(src, dest, p, m);
}
}
tgba_digraph_ptr
random_graph(int n, float d,
const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict,
int n_acc, float a, float t,
ltl::environment* env)
unsigned n_accs, float a, float t)
{
assert(n > 0);
auto res = make_tgba_digraph(dict);
@ -96,20 +85,7 @@ namespace spot
for (auto i: *ap)
props[pi++] = dict->register_proposition(i, res);
std::list<bdd> accs;
bdd allneg = bddtrue;
for (int i = 0; i < n_acc; ++i)
{
const ltl::formula* f = env->require(acc(i));
int v = dict->register_acceptance_variable(f, res);
f->destroy();
bdd b = bdd_nithvar(v);
allneg &= b;
accs.push_back(b);
}
res->set_acceptance_conditions(allneg);
for (auto& i: accs)
i = bdd_compose(allneg, i, bdd_var(i));
res->set_acceptance_conditions(n_accs);
// Using std::unordered_set instead of std::set for these sets is 3
// times slower (tested on a 50000 nodes example).
@ -162,7 +138,7 @@ namespace spot
std::advance(i, index);
// Link it from src.
random_labels(res, src, *i, props, props_n, t, accs, a);
random_labels(res, src, *i, props, props_n, t, n_accs, a);
nodes_to_process.insert(*i);
unreachable_nodes.erase(i);
break;
@ -178,7 +154,7 @@ namespace spot
state_randomizer[index] = state_randomizer[possibilities];
state_randomizer[possibilities] = x;
random_labels(res, src, x, props, props_n, t, accs, a);
random_labels(res, src, x, props, props_n, t, n_accs, a);
auto j = unreachable_nodes.find(x);
if (j != unreachable_nodes.end())

View file

@ -41,7 +41,7 @@ namespace spot
/// A density of 1 means all states will be connected to each other.
/// \param ap The list of atomic property that should label the transition.
/// \param dict The bdd_dict to used for this automata.
/// \param n_acc The number of acceptance sets to use.
/// \param n_accs The number of acceptance sets to use.
/// If this number is non null, then there is no guarantee
/// that the generated graph contains an accepting cycle (raise
/// the value of \a a to improve the chances).
@ -49,7 +49,6 @@ namespace spot
/// to an acceptance set.
/// \param t The probability (between 0.0 and 1.0) that an atomic proposition
/// is true.
/// \param env The environment in which to declare the acceptance conditions.
///
/// This algorithms is adapted from the one in Fig 6.2 page 48 of
/** \verbatim
@ -79,8 +78,7 @@ namespace spot
SPOT_API tgba_digraph_ptr
random_graph(int n, float d,
const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict,
int n_acc = 0, float a = 0.1, float t = 0.5,
ltl::environment* env = &ltl::default_environment::instance());
unsigned n_accs = 0, float a = 0.1, float t = 0.5);
}
#endif // SPOT_TGBAALGOS_RANDOMGRAPH_HH

View file

@ -102,9 +102,8 @@ namespace spot
const state* segment_next; // The state immediately after the segment.
// Start from the end of the original cycle, and rewind until all
// acceptance conditions have been seen.
bdd seen_acc = bddfalse;
bdd all_acc = a->all_acceptance_conditions();
// acceptance sets have been seen.
acc_cond::mark_t seen_acc = 0U;
tgba_run::steps::const_iterator seg = org->cycle.end();
do
{
@ -112,12 +111,12 @@ namespace spot
--seg;
seen_acc |= seg->acc;
}
while (seen_acc != all_acc);
while (!a->acc().accepting(seen_acc));
segment_start = seg->s;
// Now go forward and ends the segment as soon as we have seen all
// acceptance conditions, cloning it in our result along the way.
seen_acc = bddfalse;
// acceptance sets, cloning it in our result along the way.
seen_acc = 0U;
do
{
assert(seg != org->cycle.end());
@ -128,7 +127,7 @@ namespace spot
++seg;
}
while (seen_acc != all_acc);
while (!a->acc().accepting(seen_acc));
segment_next = seg == org->cycle.end() ? org->cycle.front().s : seg->s;
// Close this cycle if needed, that is, compute a cycle going

View file

@ -51,8 +51,7 @@ namespace spot
int serial = 1;
const tgba_run::steps* l;
std::string in;
bdd all_acc = bddfalse;
bdd expected_all_acc = a->all_acceptance_conditions();
acc_cond::mark_t all_acc = 0U;
bool all_acc_seen = false;
typedef std::unordered_map<const state*, std::set<int>,
state_ptr_hash, state_ptr_equal> state_map;
@ -116,7 +115,7 @@ namespace spot
// expected outgoing transition
bdd label = i->label;
bdd acc = i->acc;
acc_cond::mark_t acc = i->acc;
// compute the next expected state
const state* next;
@ -170,7 +169,7 @@ namespace spot
{
os << "ERROR: no transition with label="
<< bdd_format_formula(a->get_dict(), label)
<< " and acc=" << bdd_format_accset(a->get_dict(), acc)
<< " and acc=" << a->acc().format(acc)
<< " leaving state " << serial
<< " for state " << a->format_state(next) << '\n'
<< "The following transitions leave state " << serial
@ -185,9 +184,7 @@ namespace spot
<< bdd_format_formula(a->get_dict(),
j->current_condition())
<< " and acc="
<< (bdd_format_accset
(a->get_dict(),
j->current_acceptance_conditions()))
<< a->acc().format(j->current_acceptance_conditions())
<< " going to " << a->format_state(s2) << '\n';
s2->destroy();
}
@ -203,7 +200,7 @@ namespace spot
print_annotation(os, a, j);
os << " with label="
<< bdd_format_formula(a->get_dict(), label)
<< " and acc=" << bdd_format_accset(a->get_dict(), acc)
<< " and acc=" << a->acc().format(acc)
<< std::endl;
}
else
@ -212,7 +209,7 @@ namespace spot
print_annotation(os, a, j);
bdd_print_formula(os, a->get_dict(), label);
os << '\t';
bdd_print_accset(os, a->get_dict(), acc);
a->acc().format(acc);
os << std::endl;
}
a->release_iter(j);
@ -226,24 +223,24 @@ namespace spot
if (l == &run->cycle && i != l->begin())
{
all_acc |= acc;
if (!all_acc_seen && all_acc == expected_all_acc)
if (!all_acc_seen && a->acc().accepting(all_acc))
{
all_acc_seen = true;
if (debug)
os << "all acceptance conditions ("
<< bdd_format_accset(a->get_dict(), all_acc)
<< a->acc().format(all_acc)
<< ") have been seen\n";
}
}
}
s->destroy();
if (all_acc != expected_all_acc)
if (!a->acc().accepting(all_acc))
{
if (debug)
os << "ERROR: The cycle's acceptance conditions ("
<< bdd_format_accset(a->get_dict(), all_acc)
<< a->acc().format(all_acc)
<< ") do not\nmatch those of the automaton ("
<< bdd_format_accset(a->get_dict(), expected_all_acc)
<< a->acc().format(a->acc().all_sets())
<< ")\n";
return false;
}

View file

@ -76,8 +76,6 @@ namespace spot
todo.push_back(seen(aut->get_init_state()));
bdd all_acc = aut->all_acceptance_conditions();
bool all_accepting = true;
while (all_accepting && !todo.empty())
{
@ -86,8 +84,8 @@ namespace spot
for (auto it: aut->succ(s))
{
bdd acc = it->current_acceptance_conditions();
if (acc != all_acc)
auto acc = it->current_acceptance_conditions();
if (!aut->acc().accepting(acc))
{
all_accepting = false;
break;

View file

@ -43,8 +43,9 @@ namespace spot
void
start()
{
os_ << "acc =";
print_acc(aut_->all_acceptance_conditions()) << ";\n";
os_ << "acc = ";
aut_->acc().format_quoted(os_, aut_->acc().all_sets())
<< ";\n";
}
void
@ -61,7 +62,10 @@ namespace spot
os_ << "\", \"";
escape_str(os_, bdd_format_formula(d, si->current_condition()));
os_ << "\",";
print_acc(si->current_acceptance_conditions()) << ";\n";
if (si->current_acceptance_conditions())
aut_->acc().format_quoted(os_ << ' ',
si->current_acceptance_conditions());
os_ << ";\n";
dest->destroy();
}
while (si->next());
@ -69,28 +73,6 @@ namespace spot
private:
std::ostream& os_;
std::ostream&
print_acc(bdd acc)
{
const bdd_dict_ptr d = aut_->get_dict();
while (acc != bddfalse)
{
bdd cube = bdd_satone(acc);
acc -= cube;
const ltl::formula* f = d->oneacc_to_formula(cube);
std::string s = ltl::to_string(f);
if (is_atomic_prop(f) && s[0] == '"')
{
// Unquote atomic propositions.
s.erase(s.begin());
s.resize(s.size() - 1);
}
os_ << " \"";
escape_str(os_, s) << '"';
}
return os_;
}
};
}

View file

@ -86,7 +86,7 @@ namespace spot
{
if (scc_map_[n].trivial)
return false;
return acc_set_of(n) == aut_->all_acceptance_conditions();
return aut_->acc().accepting(acc_set_of(n));
}
const_tgba_ptr
@ -139,8 +139,6 @@ namespace spot
void
scc_map::build_map()
{
acceptance_convertor conv(aut_->neg_acceptance_conditions());
// Setup depth-first search from the initial state.
{
self_loops_ = 0;
@ -148,7 +146,7 @@ namespace spot
num_ = -1;
h_.emplace(init, num_);
root_.emplace_front(num_);
arc_acc_.push(bddfalse);
arc_acc_.push(0U);
arc_cond_.push(bddfalse);
tgba_succ_iterator* iter = aut_->succ_iter(init);
iter->first();
@ -209,7 +207,7 @@ namespace spot
const state* dest = succ->current_state();
if (!dest->compare(todo_.top().first))
++self_loops_;
bdd acc = succ->current_acceptance_conditions();
auto acc = succ->current_acceptance_conditions();
bdd cond = succ->current_condition();
root_.front().supp &= bdd_support(cond);
// ... and point the iterator to the next successor, for
@ -268,17 +266,18 @@ namespace spot
cond_set conds;
conds.insert(cond);
bdd supp = bddtrue;
bdd all = aut_->all_acceptance_conditions();
bdd useful = conv.as_full_product(acc);
std::set<acc_cond::mark_t> used_acc = { acc };
while (threshold > root_.front().index)
{
assert(!root_.empty());
assert(!arc_acc_.empty());
assert(arc_acc_.size() == arc_cond_.size());
acc |= root_.front().acc;
bdd lacc = arc_acc_.top();
auto lacc = arc_acc_.top();
acc |= lacc;
useful |= conv.as_full_product(lacc) | root_.front().useful_acc;
used_acc.insert(lacc);
used_acc.insert(root_.front().useful_acc.begin(),
root_.front().useful_acc.end());
states.splice(states.end(), root_.front().states);
succs.insert(root_.front().succ.begin(),
root_.front().succ.end());
@ -305,7 +304,8 @@ namespace spot
root_.front().supp &= supp;
// This SCC is no longer trivial.
root_.front().trivial = false;
root_.front().useful_acc |= useful;
assert(!used_acc.empty());
root_.front().useful_acc.insert(used_acc.begin(), used_acc.end());
}
// recursively update supp_rec
@ -339,7 +339,7 @@ namespace spot
}
bdd scc_map::acc_set_of(unsigned n) const
acc_cond::mark_t scc_map::acc_set_of(unsigned n) const
{
assert(scc_map_.size() > n);
return scc_map_[n].acc;
@ -367,7 +367,7 @@ namespace spot
return scc_map_.size();
}
bdd
const std::set<acc_cond::mark_t>&
scc_map::useful_acc_of(unsigned n) const
{
assert(scc_map_.size() > n);
@ -449,12 +449,14 @@ namespace spot
res.dead_paths = d.dead_paths[init];
res.useless_scc_map.reserve(res.scc_total);
res.useful_acc = bddfalse;
for (unsigned n = 0; n < res.scc_total; ++n)
{
res.useless_scc_map[n] = !d.acc_paths[n];
if (m.accepting(n))
res.useful_acc |= m.useful_acc_of(n);
{
auto& c = m.useful_acc_of(n);
res.useful_acc.insert(c.begin(), c.end());
}
}
return res;
}
@ -495,8 +497,7 @@ namespace spot
if (n > 1)
ostr << 's';
ostr << ")\\naccs=";
escape_str(ostr, bdd_format_accset(m.get_aut()->get_dict(),
m.acc_set_of(state)));
escape_str(ostr, m.get_aut()->acc().format(m.acc_set_of(state)));
ostr << "\\nconds=[";
for (scc_map::cond_set::const_iterator i = cs.begin();
i != cs.end(); ++i)
@ -514,8 +515,9 @@ namespace spot
escape_str(ostr, bdd_format_sat(m.get_aut()->get_dict(),
m.aprec_set_of(state)));
ostr << "]\\n useful=[";
escape_str(ostr, bdd_format_accset(m.get_aut()->get_dict(),
m.useful_acc_of(state))) << ']';
for (auto a: m.useful_acc_of(state))
m.get_aut()->acc().format(a);
ostr << ']';
}
out << " " << state << " [shape=box,"

View file

@ -61,7 +61,7 @@ namespace spot
/// The set of useful acceptance conditions (i.e. acceptance
/// conditions that are not always implied by other acceptance
/// conditions).
bdd useful_acc;
std::set<acc_cond::mark_t> useful_acc;
std::ostream& dump(std::ostream& out) const;
};
@ -144,13 +144,13 @@ namespace spot
/// \brief Return the set of acceptance conditions occurring in an SCC.
///
/// \pre This should only be called once build_map() has run.
bdd acc_set_of(unsigned n) const;
acc_cond::mark_t acc_set_of(unsigned n) const;
/// \brief Return the set of useful acceptance conditions of SCC \a n.
///
/// Useless acceptances conditions are always implied by other acceptances
/// conditions. This returns all the other acceptance conditions.
bdd useful_acc_of(unsigned n) const;
const std::set<acc_cond::mark_t>& useful_acc_of(unsigned n) const;
/// \brief Return the set of states of an SCC.
///
@ -183,14 +183,14 @@ namespace spot
struct scc
{
public:
scc(int index) : index(index), acc(bddfalse),
scc(int index) : index(index), acc(0U),
supp(bddtrue), supp_rec(bddfalse),
trivial(true), useful_acc(bddfalse) {};
trivial(true) {};
/// Index of the SCC.
int index;
/// The union of all acceptance conditions of transitions which
/// connect the states of the connected component.
bdd acc;
acc_cond::mark_t acc;
/// States of the component.
std::list<const state*> states;
/// Set of conditions used in the SCC.
@ -204,22 +204,13 @@ namespace spot
/// Trivial SCC have one state and no self-loops.
bool trivial;
/// \brief Set of acceptance combinations used in the SCC.
///
/// Note that the encoding used here differs from the
/// encoding used in automata.
/// If some transitions of the automaton are labeled by
/// Acc[a]&!Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&!Acc[c]
/// an other transitions are labeled by
/// !Acc[a]&Acc[b]&!Acc[c] | !Acc[a]&!Acc[b]&Acc[c]
/// then useful_acc will contain
/// Acc[a]&Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&Acc[c]
bdd useful_acc;
std::set<acc_cond::mark_t> useful_acc;
};
const_tgba_ptr aut_; // Automata to decompose.
typedef std::list<scc> stack_type;
stack_type root_; // Stack of SCC roots.
std::stack<bdd> arc_acc_; // A stack of acceptance conditions
std::stack<acc_cond::mark_t> arc_acc_; // A stack of acceptance conditions
// between each of these SCC.
std::stack<bdd> arc_cond_; // A stack of conditions
// between each of these SCC.

View file

@ -29,8 +29,7 @@ namespace spot
typedef std::map<int, unsigned> accremap_t;
typedef std::vector<accremap_t> remap_table_t;
typedef std::tuple<bool, bdd, bdd> filtered_trans;
typedef std::pair<bdd, bdd> acc_pair;
typedef std::tuple<bool, bdd, acc_cond::mark_t> filtered_trans;
// SCC filters are objects with two methods:
@ -53,13 +52,13 @@ namespace spot
return true;
}
acc_pair accsets(bdd all, bdd all_neg)
unsigned accsets(unsigned n)
{
return acc_pair(all, all_neg);
return n;
}
// Accept all transitions, unmodified
filtered_trans trans(unsigned, unsigned, bdd cond, bdd acc)
filtered_trans trans(unsigned, unsigned, bdd cond, acc_cond::mark_t acc)
{
return filtered_trans{true, cond, acc};
}
@ -101,7 +100,7 @@ namespace spot
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
@ -137,7 +136,7 @@ namespace spot
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
@ -149,7 +148,7 @@ namespace spot
// If the transition is between two SCCs, or in a
// non-accepting SCC. Remove the acceptance sets.
if (!this->si->is_accepting_scc(u) || u != this->si->scc_of(dst))
acc = bddfalse;
acc = 0U;
}
return filtered_trans(keep, cond, acc);
@ -168,14 +167,14 @@ namespace spot
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
if (!this->si->is_accepting_scc(this->si->scc_of(dst)))
acc = bddfalse;
acc = 0U;
return filtered_trans(keep, cond, acc);
}
};
@ -184,10 +183,8 @@ namespace spot
template <class next_filter = id_filter>
struct acc_filter_simplify: next_filter
{
std::vector<bdd> acc_;
typedef std::map<int, bdd> map_t;
typedef std::vector<map_t> remap_t;
remap_t remap_;
// Acceptance sets to strip in each SCC.
std::vector<acc_cond::mark_t> strip_;
template<typename... Args>
acc_filter_simplify(scc_info* si, Args&&... args)
@ -195,118 +192,27 @@ namespace spot
{
}
acc_pair accsets(bdd in_all, bdd in_all_neg)
unsigned accsets(unsigned n)
{
std::tie(in_all, in_all_neg) =
this->next_filter::accsets(in_all, in_all_neg);
unsigned scc_count = this->si->scc_count();
remap_table_t remap_table(scc_count);
std::vector<unsigned> max_table(scc_count);
std::vector<bdd> useful_table(scc_count);
std::vector<bdd> useless_table(scc_count);
unsigned max_num = 1;
const_tgba_digraph_ptr aut = this->si->get_aut();
std::vector<bdd> used_acc = this->si->used_acc();
auto& acc = this->si->get_aut()->acc();
assert(n == acc.num_sets());
(void) n;
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_accepting_scc(n))
continue;
bdd all = used_acc[n];
//std::cerr << "SCC #" << n << "; used = " << all << std::endl;
// Compute a set of useless acceptance sets.
// If the acceptance combinations occurring in
// the automata are { a, ab, abc, bd }, then
// ALL contains (a&!b&!c&!d)|(a&b&!c&!d)|(a&b&c&!d)|(!a&b&!c&d)
// and we want to find that 'a' and 'b' are useless because
// they always occur with 'c'.
// The way we check if 'a' is useless is to look whether ALL
// implications (x -> a) for some other acceptance set x.
//
// The two while() loops in the code perform the equivalent of
// for all a in allconds_a:
// for all x in allconds_x:
// check whether x -> a
// ...
//
// Initially allconds_a = allconds_x contains all acceptance
// sets. However when an acceptance set 'a' is determined to
// be useless, it can be removed from allconds_x from future
// iterations.
bdd allconds_a = bdd_support(in_all_neg);
bdd allconds_x = allconds_a;
bdd useless = bddtrue;
while (allconds_a != bddtrue)
{
// Speed-up the computation of implied acceptance sets by
// removing those that are always present. We detect
// those that appear as conjunction of positive variables
// at the start of ALL.
bdd prefix = bdd_satprefix(all);
if (prefix != bddtrue)
{
assert(prefix == bdd_support(prefix));
allconds_a = bdd_exist(allconds_a, prefix);
if (allconds_a != bddtrue)
{
useless &= prefix;
}
else
{
// Never erase all conditions: at least keep one.
useless &= bdd_high(prefix);
break;
}
allconds_x = bdd_exist(allconds_x, prefix);
}
// Pick an acceptance set 'a'.
bdd a = bdd_ithvar(bdd_var(allconds_a));
// For all acceptance sets 'x' that are not already
// useless...
bdd others = allconds_x;
while (others != bddtrue)
{
bdd x = bdd_ithvar(bdd_var(others));
// ... check whether 'x' always implies 'a'.
if (x != a && bdd_implies(all, x >> a))
{
// If so, 'a' is useless.
all = bdd_exist(all, a);
useless &= a;
allconds_x = bdd_exist(allconds_x, a);
break;
}
others = bdd_high(others);
}
allconds_a = bdd_high(allconds_a);
}
// We never remove ALL acceptance marks.
assert(in_all_neg == bddtrue || useless != bdd_support(in_all_neg));
useless_table[n] = useless;
bdd useful = bdd_exist(in_all_neg, useless);
//std::cerr << "SCC #" << n << "; useful = " << useful << std::endl;
// Go over all useful sets of acceptance marks, and give them
// a number.
unsigned num = 1;
// First compute the number of acceptance conditions used.
for (BDD c = useful.id(); c != 1; c = bdd_low(c))
++num;
max_table[n] = num;
if (num > max_num)
max_num = num;
useful_table[n] = useful;
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.
@ -314,118 +220,30 @@ namespace spot
{
if (!this->si->is_accepting_scc(n))
continue;
//std::cerr << "SCC " << n << '\n';
bdd useful = useful_table[n];
int missing = max_num - max_table[n];
bdd useless = useless_table[n];
while (missing--)
{
//std::cerr << useful << " : " << useless << std::endl;
useful &= bdd_nithvar(bdd_var(useless));
useless = bdd_high(useless);
}
int num = max_num;
// Then number all of these acceptance conditions in the
// reverse order. This makes sure that the associated number
// varies in the same direction as the bdd variables, which in
// turn makes sure we preserve the acceptance condition
// ordering (which matters for degeneralization).
for (BDD c = useful.id(); c != 1; c = bdd_low(c))
remap_table[n].emplace(bdd_var(c), --num);
max_table[n] = max_num;
if (cnt[n] < max)
strip_[n].remove_some(max - cnt[n]);
}
acc_.resize(max_num);
acc_[0] = bddfalse;
bdd tmp = in_all;
assert(aut->number_of_acceptance_conditions() >= max_num - 1);
bdd all = bddfalse;
bdd all_neg = bddtrue;
if (tmp != bddfalse)
{
for (unsigned n = max_num - 1; n > 0; --n)
{
assert(tmp != bddfalse);
int v = bdd_var(tmp);
bdd vn = bdd_nithvar(v);
all = (all & vn) | (all_neg & bdd_ithvar(v));
all_neg &= vn;
tmp = bdd_low(tmp);
}
tmp = in_all;
for (unsigned n = max_num - 1; n > 0; --n)
{
int v = bdd_var(tmp);
acc_[n] = bdd_compose(all_neg, bdd_nithvar(v), v);
tmp = bdd_low(tmp);
}
}
else
{
assert(max_num == 1);
}
remap_.resize(scc_count);
bdd all_orig_neg = in_all_neg;
bdd all_sup = bdd_support(all_orig_neg);
for (unsigned n = 0; n < scc_count; ++n)
{
//std::cerr << "SCC #" << n << '\n';
if (!this->si->is_accepting_scc(n))
continue;
bdd all = used_acc[n];
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, all_sup, bddtrue);
all -= one;
bdd res = bddfalse;
bdd resacc = bddfalse;
while (one != bddtrue)
{
if (bdd_high(one) == bddfalse)
{
one = bdd_low(one);
continue;
}
int vn = bdd_var(one);
bdd v = bdd_ithvar(vn);
resacc |= bdd_exist(all_orig_neg, v) & v;
res |= acc_[remap_table[n][vn]];
one = bdd_high(one);
}
int id = resacc.id();
//std::cerr << resacc << " -> " << res << '\n';
remap_[n][id] = res;
}
}
return acc_pair{all, all_neg};
return max;
}
filtered_trans trans(unsigned src, unsigned dst, bdd cond, bdd acc)
filtered_trans trans(unsigned src, unsigned dst, bdd cond,
acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
if (keep && acc != bddfalse)
if (keep && acc)
{
unsigned u = this->si->scc_of(dst);
auto i = remap_[u].find(acc.id());
if (i != remap_[u].end())
acc = i->second;
if (!this->si->is_accepting_scc(u))
acc = 0U;
else
acc = bddfalse;
acc = this->si->get_aut()->acc().strip(acc, strip_[u]);
}
return filtered_trans{keep, cond, acc};
}
};
@ -456,11 +274,8 @@ namespace spot
else
inout.push_back(-1U);
{
bdd all = aut->all_acceptance_conditions();
bdd neg = aut->neg_acceptance_conditions();
filtered->set_acceptance_conditions(filter.accsets(all, neg).first);
}
filtered->
set_acceptance_conditions(filter.accsets(aut->acc().num_sets()));
filtered->new_states(out_n);
for (unsigned isrc = 0; isrc < in_n; ++isrc)
{
@ -474,7 +289,7 @@ namespace spot
continue;
bool want;
bdd cond;
bdd acc;
acc_cond::mark_t acc;
std::tie(want, cond, acc) =
filter.trans(isrc, t.dst, t.cond, t.acc);
if (want)

View file

@ -33,14 +33,14 @@ namespace spot
struct scc
{
public:
scc(int index, bdd in_cond, bdd in_acc):
scc(int index, bdd in_cond, acc_cond::mark_t in_acc):
index(index), in_cond(in_cond), in_acc(in_acc)
{
}
int index; // Index of the SCC
bdd in_cond; // Condition on incoming transition
bdd in_acc; // Acceptance sets on the incoming transition
acc_cond::mark_t in_acc; // Acceptance sets on the incoming transition
scc_info::scc_node node;
};
}
@ -50,7 +50,6 @@ namespace spot
{
unsigned n = aut->num_states();
sccof_.resize(n, -1U);
bdd all_acc = aut->all_acceptance_conditions();
typedef std::list<scc> stack_type;
stack_type root_; // Stack of SCC roots.
@ -81,7 +80,7 @@ namespace spot
unsigned init = aut->get_init_state_number();
num_ = -1;
h_[init] = num_;
root_.emplace_front(num_, bddfalse, bddfalse);
root_.emplace_front(num_, bddfalse, 0U);
todo_.emplace(init, aut->out(init).begin());
}
@ -117,12 +116,12 @@ namespace spot
h_[s] = num + 1;
}
bdd cond = root_.front().in_cond;
bdd acc = root_.front().node.acc;
auto acc = root_.front().node.acc;
bool triv = root_.front().node.trivial;
node_.emplace_back(acc, triv);
std::swap(node_.back().succ, root_.front().node.succ);
std::swap(node_.back().states, root_.front().node.states);
node_.back().accepting = acc == all_acc;
node_.back().accepting = aut->acc().accepting(acc);
root_.pop_front();
// Record the transition between the SCC being popped
// and the previous SCC.
@ -135,7 +134,7 @@ namespace spot
// We have a successor to look at.
// Fetch the values we are interested in...
unsigned dest = succ->dst;
bdd acc = succ->acc;
auto acc = succ->acc;
bdd cond = succ->cond;
++todo_.top().second;
@ -191,7 +190,8 @@ namespace spot
while (threshold > root_.front().index)
{
assert(!root_.empty());
acc |= root_.front().node.acc | root_.front().in_acc;
acc |= root_.front().node.acc;
acc |= root_.front().in_acc;
states.splice(states.end(), root_.front().node.states);
succs.insert(succs.end(),
@ -229,22 +229,22 @@ namespace spot
}
std::vector<bdd> scc_info::used_acc() const
std::vector<std::set<acc_cond::mark_t>> scc_info::used_acc() const
{
unsigned n = aut_->num_states();
std::vector<bdd> result(scc_count());
acceptance_convertor conv(aut_->neg_acceptance_conditions());
std::vector<std::set<acc_cond::mark_t>> result(scc_count());
for (unsigned src = 0; src < n; ++src)
{
unsigned src_scc = scc_of(src);
if (src_scc == -1U || !is_accepting_scc(src_scc))
continue;
auto& s = result[src_scc];
for (auto& t: aut_->out(src))
{
if (scc_of(t.dst) != src_scc)
continue;
result[src_scc] |= conv.as_full_product(t.acc);
s.insert(t.acc);
}
}
return result;
@ -255,9 +255,8 @@ namespace spot
unsigned n = scc_count();
std::vector<bool> result(scc_count());
auto acc = used_acc();
bdd all = bdd_support(aut_->neg_acceptance_conditions());
for (unsigned s = 0; s < n; ++s)
result[s] = !is_accepting_scc(s) || acc[s] == all;
result[s] = !is_accepting_scc(s) || acc[s].size() == 1;
return result;
}
@ -276,8 +275,6 @@ namespace spot
{
scc_info* m = sccinfo ? sccinfo : new scc_info(aut);
bdd all_acc = aut->all_acceptance_conditions();
out << "digraph G {\n i [label=\"\", style=invis, height=0]\n";
int start = m->scc_of(aut->get_init_state_number());
out << " i -> " << start << std::endl;
@ -293,7 +290,7 @@ namespace spot
q.pop();
out << " " << state << " [shape=box,"
<< (m->acc(state) == all_acc ? "style=bold," : "")
<< (aut->acc().accepting(m->acc(state)) ? "style=bold," : "")
<< "label=\"" << state;
{
size_t n = m->states_of(state).size();

View file

@ -45,17 +45,17 @@ namespace spot
struct scc_node
{
scc_node():
acc(bddfalse), trivial(true)
acc(0U), trivial(true)
{
}
scc_node(bdd acc, bool trivial):
scc_node(acc_cond::mark_t acc, bool trivial):
acc(acc), trivial(trivial)
{
}
scc_succs succ;
bdd acc;
acc_cond::mark_t acc;
std::list<unsigned> states; // States of the component
bool trivial:1;
bool accepting:1;
@ -114,7 +114,7 @@ namespace spot
return node(scc).trivial;
}
bdd acc(unsigned scc) const
acc_cond::mark_t acc(unsigned scc) const
{
return node(scc).acc;
}
@ -134,18 +134,9 @@ namespace spot
return reachable_state(st) && node(scc_of(st)).useful;
}
/// \brief Return the set of all used acceptance combinations, for
/// each accepting SCC.
///
/// If SCC #i use {a,b} and {c}, which
/// are normally respectively encoded as
/// Acc[a]&!Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&!Acc[c]
/// and
/// !Acc[a]&!Acc[b]&Acc[c]
/// then the vector will contain
/// Acc[a]&Acc[b] | Acc[c]
/// at position #i.
std::vector<bdd> used_acc() const;
/// \brief Return the set of all used acceptance combinations, for
/// each accepting SCC.
std::vector<std::set<acc_cond::mark_t>> used_acc() const;
std::vector<bool> weak_sccs() const;

View file

@ -57,10 +57,9 @@ namespace spot
se05_search(const const_tgba_ptr a, size_t size,
option_map o = option_map())
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
h(size)
{
assert(a->number_of_acceptance_conditions() <= 1);
assert(a->acc().num_sets() <= 1);
}
virtual ~se05_search()
@ -98,7 +97,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, CYAN);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
if (dfs_blue())
return std::make_shared<se05_result>(t, options());
}
@ -151,7 +150,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -176,9 +175,6 @@ namespace spot
/// by the last dfs visiting it.
heap h;
/// The unique acceptance condition of the automaton \a a.
bdd all_cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -191,7 +187,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -203,8 +199,9 @@ namespace spot
h.add_new_state(s_prime, CYAN);
push(st_blue, s_prime, label, acc);
}
else if (c.get_color() == CYAN && (acc == all_cond ||
(f.s->compare(s_prime) != 0 && f.acc == all_cond)))
else if (c.get_color() == CYAN && (a_->acc().accepting(acc) ||
(f.s->compare(s_prime) != 0
&& a_->acc().accepting(f.acc))))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
@ -212,7 +209,7 @@ namespace spot
push(st_red, s_prime, label, acc);
return true;
}
else if (acc == all_cond && c.get_color() != RED)
else if (a_->acc().accepting(acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -241,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() &&
f_dest.acc == all_cond && 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
@ -281,7 +278,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();

View file

@ -215,7 +215,30 @@ namespace spot
protected:
// Shortcut used in update_po and go_to_next_it.
typedef std::map<bdd, bdd, bdd_less_than> map_bdd_bdd;
int acc_vars;
public:
bdd mark_to_bdd(acc_cond::mark_t m)
{
// FIXME: Use a cache.
bdd res = bddtrue;
for (auto n: a_->acc().sets(m))
res &= bdd_ithvar(acc_vars + n);
return res;
}
acc_cond::mark_t bdd_to_mark(const tgba_digraph_ptr& aut, 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 aut->acc().marks(res.begin(), res.end());
}
direct_simulation(const const_tgba_ptr& t,
const map_constraint* map_cst = 0)
: a_(0),
@ -234,9 +257,6 @@ namespace spot
old_a_ = a_;
acc_compl ac(a_->all_acceptance_conditions(),
a_->neg_acceptance_conditions());
// Replace all the acceptance conditions by their complements.
// (In the case of Cosimulation, we also flip the transitions.)
{
@ -253,7 +273,7 @@ namespace spot
{
for (auto& t: old_a_->out(s))
{
bdd acc;
acc_cond::mark_t acc;
if (Sba && Cosimulation)
{
// If the acceptance is interpreted as
@ -262,16 +282,16 @@ namespace spot
// the destination state on its incoming arcs
// (which now become outgoing arcs after
// transposition).
acc = bddfalse;
acc = 0U;
for (auto& td: old_a_->out(t.dst))
{
acc = ac.complement(td.acc);
acc = old_a_->acc().comp(td.acc);
break;
}
}
else
{
acc = ac.complement(t.acc);
acc = old_a_->acc().comp(t.acc);
}
if (Cosimulation)
a_->new_transition(t.dst, s, t.cond, acc);
@ -288,8 +308,13 @@ namespace spot
unsigned set_num = a_->get_dict()
->register_anonymous_variables(size_a_ + 1, this);
all_acceptance_conditions_ = a_->all_acceptance_conditions();
all_proms_ = bdd_support(all_acceptance_conditions_);
unsigned n_acc = a_->acc().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);
bdd_initial = bdd_ithvar(set_num++);
bdd init = bdd_ithvar(set_num++);
@ -397,7 +422,7 @@ namespace spot
}
else
{
acc = t.acc;
acc = mark_to_bdd(t.acc);
}
// to_add is a conjunction of the acceptance condition,
@ -527,23 +552,14 @@ namespace spot
// Build the minimal resulting automaton.
tgba_digraph_ptr build_result()
{
// We have all the a_'s acceptances conditions
// complemented. So we need to complement it when adding a
// transition. We *must* keep the complemented because it
// is easy to know if an acceptance condition is maximal or
// not.
acc_compl reverser(all_acceptance_conditions_,
a_->neg_acceptance_conditions());
tgba_digraph_ptr res = make_tgba_digraph(a_->get_dict());
res->copy_ap_of(a_);
res->set_acceptance_conditions(all_acceptance_conditions_);
res->copy_acceptance_conditions_of(a_);
if (Sba)
res->prop_state_based_acc();
bdd sup_all_acc = bdd_support(all_acceptance_conditions_);
// Non atomic propositions variables (= acc and class)
bdd nonapvars = sup_all_acc & bdd_support(all_class_var_);
bdd nonapvars = all_proms_ & bdd_support(all_class_var_);
auto* gb = res->create_namer<int>();
@ -558,9 +574,9 @@ namespace spot
}
// Acceptance of states. Only used if Sba && Cosimulation.
std::vector<bdd> accst;
std::vector<acc_cond::mark_t> accst;
if (Sba && Cosimulation)
accst.resize(res->num_states(), bddfalse);
accst.resize(res->num_states(), 0U);
stat.states = bdd_lstate_.size();
stat.transitions = 0;
@ -626,7 +642,8 @@ namespace spot
all_class_var_);
// Keep only ones who are acceptance condition.
bdd acc = bdd_existcomp(cond_acc_dest, sup_all_acc);
auto acc = bdd_to_mark(res, bdd_existcomp(cond_acc_dest,
all_proms_));
// Keep the other!
bdd cond = bdd_existcomp(cond_acc_dest,
@ -635,7 +652,7 @@ namespace spot
// Because we have complemented all the acceptance
// conditions on the input automaton, we must
// revert them to create a new transition.
acc = reverser.reverse_complement(acc);
acc = res->acc().comp(acc);
if (Cosimulation)
{
@ -647,7 +664,7 @@ namespace spot
// can't do this here, store this in a table
// so we can fix it later.
accst[gb->get_state(src.id())] = acc;
acc = bddfalse;
acc = 0U;
}
gb->new_transition(dst.id(), src.id(), cond, acc);
}
@ -671,8 +688,8 @@ namespace spot
unsigned ns = res->num_states();
for (unsigned s = 0; s < ns; ++s)
{
bdd acc = accst[s];
if (acc == bddfalse)
acc_cond::mark_t acc = accst[s];
if (acc == 0U)
continue;
for (auto& t: res->out(s))
t.acc = acc;
@ -774,8 +791,6 @@ namespace spot
const map_constraint* map_cst_;
const_tgba_ptr original_;
bdd all_acceptance_conditions_;
};
// For now, we don't try to handle cosimulation.
@ -807,8 +822,7 @@ namespace spot
// simulation to run.
has_limit_ = false;
notap = (bdd_support(all_acceptance_conditions_)
& all_class_var_ & on_cycle_);
notap = bdd_support(all_proms_) & all_class_var_ & on_cycle_;
}
// This function computes the don't care signature of the state
@ -831,13 +845,14 @@ namespace spot
if (scc != scc_info_->scc_of(t.dst))
acc = !on_cycle_;
else if (sccacc)
acc = on_cycle_ & t.acc;
acc = on_cycle_ & mark_to_bdd(t.acc);
else
acc = on_cycle_ & all_proms_;
bdd to_add = acc & t.cond & relation_[cl];
res |= to_add;
}
return res;
}
@ -864,9 +879,6 @@ namespace spot
bool could_imply_aux(bdd f1, bdd g1, bdd left_class,
bdd right, bdd right_class)
{
(void) left_class;
(void) right_class;
bdd f2g2 = bdd_exist(right, on_cycle_);
bdd f2g2n = bdd_exist(f2g2, all_proms_);
@ -973,8 +985,7 @@ namespace spot
bdd b = bdd_exist(right, notap);
bdd add = bdd_exist(left & b, bdd_support(b));
if (add != bddfalse
&& bdd_exist(add, all_acceptance_conditions_) == bddtrue)
if (add != bddfalse && bdd_exist(add, all_proms_) == bddtrue)
{
assert(src_right != dst_right);
@ -988,8 +999,7 @@ namespace spot
bdd b = bdd_exist(left, notap);
bdd add = bdd_exist(right & b, bdd_support(b));
if (add != bddfalse
&& bdd_exist(add, all_acceptance_conditions_) == bddtrue)
if (add != bddfalse && bdd_exist(add, all_proms_) == bddtrue)
{
assert(src_left != dst_left);
@ -1003,8 +1013,7 @@ namespace spot
bdd b = bdd_exist(left, notap);
bdd add = bdd_exist(right & b, bdd_support(b));
if (add != bddfalse
&& bdd_exist(add, all_acceptance_conditions_) == bddtrue)
if (add != bddfalse && bdd_exist(add, all_proms_) == bddtrue)
{
assert(src_left != dst_left && src_right != dst_right);
// FIXME: cas pas compris.
@ -1174,6 +1183,9 @@ namespace spot
}
while (diff != bddtrue);
}
#ifndef NDEBUG
for (auto& i: class2state)
assert(previous_class_[i.second] == i.first);

View file

@ -145,6 +145,10 @@ namespace spot
/// @}
// FIXME: Remove: dont_care_*_simulation is broken since the move to
// bitset acceptance, has never been really used, and really useful
// (nor really well tested and understood), so we should remove it.
SPOT_API tgba_digraph_ptr
dont_care_simulation(const const_tgba_ptr& t, int limit = -1);

View file

@ -180,7 +180,7 @@ namespace spot
}
if (has('a'))
acc_ = aut->number_of_acceptance_conditions();
acc_ = aut->acc().num_sets();
if (has('c') || has('S'))
scc_ = scc_info(aut).scc_count();

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 = bddfalse;
a->set_acceptance_conditions(bddfalse);
t.acc = 0U;
a->set_acceptance_conditions(0);
}
}

View file

@ -56,10 +56,9 @@ namespace spot
/// \brief Initialize the search algorithm on the automaton \a a
tau03_search(const const_tgba_ptr a, size_t size, option_map o)
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
h(size)
{
assert(a->number_of_acceptance_conditions() > 0);
assert(a->acc().num_sets() > 0);
}
virtual ~tau03_search()
@ -91,7 +90,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, BLUE);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
auto t = std::static_pointer_cast<tau03_search>
(this->emptiness_check::shared_from_this());
if (dfs_blue())
@ -124,7 +123,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -149,9 +148,6 @@ namespace spot
/// by the last dfs visiting it.
heap h;
/// The unique acceptance condition of the automaton \a a.
bdd all_cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -164,7 +160,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -199,10 +195,10 @@ namespace spot
<< a_->format_state(f.s) << " to "
<< a_->format_state(s_prime) << std::endl;
bdd label = i->current_condition();
bdd acc = i->current_acceptance_conditions();
auto acc = i->current_acceptance_conditions();
typename heap::color_ref c_prime = h.get_color_ref(s_prime);
assert(!c_prime.is_white());
bdd 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"
@ -212,7 +208,7 @@ namespace spot
dfs_red(acu);
}
}
if (c.get_acc() == all_cond)
if (a_->acc().accepting(c.get_acc()))
{
trace << "DFS_BLUE propagation is successful, report a"
<< " cycle" << std::endl;
@ -230,7 +226,7 @@ namespace spot
return false;
}
void dfs_red(const bdd& acu)
void dfs_red(acc_cond::mark_t acu)
{
assert(!st_red.empty());
@ -244,7 +240,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -254,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;
@ -286,7 +282,7 @@ namespace spot
class color_ref
{
public:
color_ref(color* c, bdd* a) :p(c), acc(a)
color_ref(color* c, acc_cond::mark_t* a) :p(c), acc(a)
{
}
color get_color() const
@ -298,15 +294,15 @@ namespace spot
assert(!is_white());
*p = c;
}
const bdd& get_acc() const
acc_cond::mark_t get_acc() const
{
assert(!is_white());
return *acc;
}
void cumulate_acc(const bdd& a)
void cumulate_acc(acc_cond::mark_t a)
{
assert(!is_white());
*acc |= a;
*acc |= a;
}
bool is_white() const
{
@ -314,7 +310,7 @@ namespace spot
}
private:
color *p;
bdd* acc;
acc_cond::mark_t* acc;
};
explicit_tau03_search_heap(size_t)
@ -349,7 +345,9 @@ namespace spot
void add_new_state(const state* s, color c)
{
assert(h.find(s) == h.end());
h.emplace(s, std::make_pair(c, bddfalse));
h.emplace(std::piecewise_construct,
std::forward_as_tuple(s),
std::forward_as_tuple(c, 0U));
}
void pop_notify(const state*) const
@ -369,7 +367,8 @@ namespace spot
}
private:
typedef std::unordered_map<const state*, std::pair<color, bdd>,
typedef std::unordered_map<const state*,
std::pair<color, acc_cond::mark_t>,
state_ptr_hash, state_ptr_equal> hash_type;
hash_type h;
};

View file

@ -67,24 +67,13 @@ namespace spot
/// \brief Initialize the search algorithm on the automaton \a a
tau03_opt_search(const const_tgba_ptr& a, size_t size, option_map o)
: emptiness_check(a, o),
current_weight(a->neg_acceptance_conditions()),
current_weight(a->acc()),
h(size),
all_acc(a->all_acceptance_conditions()),
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))
{
if (use_ordering)
{
bdd all_conds = all_acc;
while (all_conds != bddfalse)
{
bdd acc = bdd_satone(all_conds);
cond.push_back(acc);
all_conds -= acc;
}
}
}
virtual ~tau03_opt_search()
@ -116,7 +105,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, CYAN, current_weight);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
auto t = std::static_pointer_cast<tau03_opt_search>
(this->emptiness_check::shared_from_this());
if (dfs_blue())
@ -149,7 +138,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -164,14 +153,16 @@ namespace spot
st.pop_front();
}
bdd project_acc(bdd acc) const
acc_cond::mark_t project_acc(acc_cond::mark_t acc) const
{
bdd result = bddfalse;
for (std::vector<bdd>::const_iterator i = cond.begin();
i != cond.end() && (acc & *i) != bddfalse;
++i)
result |= *i;
return result;
if (!use_ordering)
return acc;
// FIXME: This should be improved.
std::vector<unsigned> res;
unsigned max = a_->acc().num_sets();
for (unsigned n = 0; n < max && a_->acc().has(acc, n); ++n)
res.push_back(n);
return a_->acc().marks(res.begin(), res.end());
}
/// \brief weight of the state on top of the blue stack.
@ -187,9 +178,6 @@ namespace spot
/// by the last dfs visiting it.
heap h;
/// The unique acceptance condition of the automaton \a a.
bdd all_acc;
/// Whether to use the "condition stack".
bool use_condition_stack;
/// Whether to use an ordering between the acceptance conditions.
@ -200,9 +188,6 @@ namespace spot
/// Whether to use weights in the red dfs.
bool use_red_weights;
/// Ordering of the acceptance conditions.
std::vector<bdd> cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -215,7 +200,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -224,7 +209,7 @@ namespace spot
{
trace << " It is white, go down" << std::endl;
if (use_weights)
current_weight += acc;
current_weight.add(a_->acc(), acc);
inc_states();
h.add_new_state(s_prime, CYAN, current_weight);
push(st_blue, s_prime, label, acc);
@ -234,22 +219,21 @@ namespace spot
typename heap::color_ref c = h.get_color_ref(f.s);
assert(!c.is_white());
if (c_prime.get_color() == CYAN
&& all_acc == ((current_weight - 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;
c_prime.cumulate_acc(all_acc);
c_prime.cumulate_acc(a_->acc().all_sets());
push(st_red, s_prime, label, acc);
return true;
}
else
{
trace << " It is cyan or blue and";
bdd acu = acc | c.get_acc();
bdd acp = (use_ordering ? project_acc(acu) : acu);
auto acu = acc | c.get_acc();
auto acp = project_acc(acu);
if ((c_prime.get_acc() & acp) != acp)
{
trace << " a propagation is needed, "
@ -276,7 +260,7 @@ namespace spot
stack_item f_dest(f);
pop(st_blue);
if (use_weights)
current_weight -= f_dest.acc;
current_weight.sub(a_->acc(), 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);
@ -285,8 +269,8 @@ namespace spot
typename heap::color_ref c =
h.get_color_ref(st_blue.front().s);
assert(!c.is_white());
bdd acu = f_dest.acc | c.get_acc();
bdd acp = (use_ordering ? project_acc(acu) : acu);
auto acu = f_dest.acc | c.get_acc();
auto acp = project_acc(acu);
if ((c_prime.get_acc() & acp) != acp)
{
trace << " The arc from "
@ -315,15 +299,15 @@ namespace spot
}
bool
dfs_red(bdd acu)
dfs_red(acc_cond::mark_t acu)
{
assert(!st_red.empty());
// These are useful only when USE_CONDITION_STACK is set.
typedef std::pair<bdd, unsigned> cond_level;
typedef std::pair<acc_cond::mark_t, unsigned> cond_level;
std::stack<cond_level> condition_stack;
unsigned depth = 1;
condition_stack.emplace(bddfalse, 0);
condition_stack.emplace(0U, 0);
while (!st_red.empty())
{
@ -335,7 +319,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -347,22 +331,23 @@ namespace spot
continue;
}
else if (c_prime.get_color() == CYAN &&
(all_acc == ((use_red_weights ?
(current_weight - c_prime.get_weight())
: bdd_false())
| c_prime.get_acc()
| acc
| acu)))
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(all_acc);
c_prime.cumulate_acc(a_->acc().all_sets());
push(st_red, s_prime, label, acc);
return true;
}
bdd acp;
acc_cond::mark_t acp;
if (use_ordering)
acp = project_acc(c_prime.get_acc() | acu | acc);
acp = project_acc(acu | acc | c_prime.get_acc());
else if (use_condition_stack)
acp = acu | acc;
else
@ -376,7 +361,7 @@ namespace spot
push(st_red, s_prime, label, acc);
if (use_condition_stack)
{
bdd old = acu;
auto old = acu;
acu |= acc;
condition_stack.emplace(acu - old, depth);
}
@ -412,20 +397,22 @@ namespace spot
class explicit_tau03_opt_search_heap
{
typedef std::unordered_map<const state*, std::pair<weight, bdd>,
typedef std::unordered_map<const state*, std::pair<weight,
acc_cond::mark_t>,
state_ptr_hash, state_ptr_equal> hcyan_type;
typedef std::unordered_map<const state*, std::pair<color, bdd>,
typedef std::unordered_map<const state*, std::pair<color,
acc_cond::mark_t>,
state_ptr_hash, state_ptr_equal> hash_type;
public:
class color_ref
{
public:
color_ref(hash_type* h, hcyan_type* hc, const state* s,
const weight* w, bdd* a)
const weight* w, acc_cond::mark_t* a)
: is_cyan(true), w(w), ph(h), phc(hc), ps(s), acc(a)
{
}
color_ref(color* c, bdd* a)
color_ref(color* c, acc_cond::mark_t* a)
: is_cyan(false), pc(c), acc(a)
{
}
@ -459,12 +446,12 @@ namespace spot
*pc=c;
}
}
const bdd& get_acc() const
acc_cond::mark_t get_acc() const
{
assert(!is_white());
return *acc;
}
void cumulate_acc(const bdd& a)
void cumulate_acc(acc_cond::mark_t a)
{
assert(!is_white());
*acc |= a;
@ -480,8 +467,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
bdd* 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)
@ -540,7 +527,7 @@ namespace spot
(void)c;
hc.emplace(std::piecewise_construct,
std::forward_as_tuple(s),
std::forward_as_tuple(w, bddfalse));
std::forward_as_tuple(w, 0U));
}
void pop_notify(const state*) const

View file

@ -26,96 +26,41 @@
namespace spot
{
weight::weight_vector* weight::pm = 0;
weight::weight(const bdd& neg_all_cond) : neg_all_acc(neg_all_cond)
weight::weight(const acc_cond& acc):
m(acc.num_sets())
{
}
void weight::inc_weight_handler(char* varset, int size)
weight& weight::add(const acc_cond& acc, acc_cond::mark_t a)
{
for (int v = 0; v < size; ++v)
if (varset[v] > 0)
{
weight::weight_vector::iterator it = pm->find(v);
if (it == pm->end())
pm->emplace(v, 1);
else
++(it->second);
break;
}
}
weight& weight::operator+=(const bdd& acc)
{
pm = &m;
bdd_allsat(acc, inc_weight_handler);
for (auto s: acc.sets(a))
++m[s];
return *this;
}
void weight::dec_weight_handler(char* varset, int size)
weight& weight::sub(const acc_cond& acc, acc_cond::mark_t a)
{
for (int v = 0; v < size; ++v)
if (varset[v] > 0)
{
weight::weight_vector::iterator it = pm->find(v);
assert(it != pm->end() && it->second > 0);
if (it->second > 1)
--(it->second);
else
pm->erase(it);
break;
}
}
weight& weight::operator-=(const bdd& acc)
{
pm = &m;
bdd_allsat(acc, dec_weight_handler);
for (auto s: acc.sets(a))
if (m[s] > 0)
--m[s];
return *this;
}
bdd weight::operator-(const weight& w) const
acc_cond::mark_t weight::diff(const acc_cond& acc, const weight& w) const
{
weight_vector::const_iterator itw1 = m.begin(), itw2 = w.m.begin();
bdd res = bddfalse;
while (itw1 != m.end() && itw2 != w.m.end())
{
assert(itw1->first <= itw2->first);
if (itw1->first < itw2->first)
{
res |= bdd_exist(neg_all_acc, bdd_ithvar(itw1->first)) &
bdd_ithvar(itw1->first);
++itw1;
}
else
{
assert(itw1->second >= itw2->second);
if (itw1->second > itw2->second)
{
res |= bdd_exist(neg_all_acc, bdd_ithvar(itw1->first)) &
bdd_ithvar(itw1->first);
}
++itw1;
++itw2;
}
}
assert(itw2 == w.m.end());
while (itw1 != m.end())
{
res |= bdd_exist(neg_all_acc, bdd_ithvar(itw1->first)) &
bdd_ithvar(itw1->first);
++itw1;
}
return res;
unsigned max = acc.num_sets();
std::vector<unsigned> res;
for (unsigned n = 0; n < max; ++n)
if (m[n] > w.m[n])
res.push_back(n);
return acc.marks(res.begin(), res.end());
}
std::ostream& operator<<(std::ostream& os, const weight& w)
{
weight::weight_vector::const_iterator it;
for (it = w.m.begin(); it != w.m.end(); ++it)
os << '(' << it->first << ',' << it->second << ')';
unsigned s = w.m.size();
for (unsigned n = 0; n < s; ++n)
os << '(' << n << ',' << w.m[n] << ')';
return os;
}

View file

@ -1,4 +1,4 @@
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// Copyright (C) 2004, 2014 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
@ -23,6 +23,7 @@
#include <iosfwd>
#include <map>
#include <bdd.h>
#include "tgba/acc.hh"
namespace spot
{
@ -33,29 +34,23 @@ namespace spot
{
public:
/// Construct a empty vector (all counters set to zero).
///
/// \param neg_all_cond : negation of all the acceptance conditions of
/// the automaton (the bdd returned by tgba::neg_acceptance_conditions()).
weight(const bdd& neg_all_cond);
weight(const acc_cond& acc);
/// Increment by one the counters of each acceptance condition in \a acc.
weight& operator+=(const bdd& acc);
weight& add(const acc_cond& acc, acc_cond::mark_t a);
/// Decrement by one the counters of each acceptance condition in \a acc.
weight& operator-=(const bdd& acc);
weight& sub(const acc_cond& acc, acc_cond::mark_t a);
/// Return the set of each acceptance condition such that its counter is
/// strictly greatest than the corresponding counter in w.
///
/// \pre For each acceptance condition, its counter is greatest or equal to
/// the corresponding counter in w.
bdd operator-(const weight& w) const;
friend std::ostream& operator<<(std::ostream& os, const weight& w);
acc_cond::mark_t diff(const acc_cond& acc, const weight& w) const;
friend std::ostream& operator<<(std::ostream& os,
const weight& w);
private:
typedef std::map<int, int> weight_vector;
typedef std::vector<int> weight_vector;
weight_vector m;
bdd neg_all_acc;
static weight_vector* pm;
static void inc_weight_handler(char* varset, int size);
static void dec_weight_handler(char* varset, int size);
};
};

View file

@ -54,7 +54,7 @@
int token;
std::string* str;
const spot::ltl::formula* f;
bdd* acc;
spot::acc_cond::mark_t acc;
}
%code
@ -80,10 +80,9 @@ typedef std::pair<bool, spot::ltl::formula*> pair;
%token ACC_DEF
%destructor { delete $$; } <str>
%destructor { delete $$; } <acc>
%printer { debug_stream() << *$$; } <str>
%printer { debug_stream() << *$$; } <acc>
%printer { debug_stream() << $$; } <acc>
%%
tgba: acceptance_decl lines
@ -94,7 +93,8 @@ tgba: acceptance_decl lines
{ namer->new_state("0"); };
acceptance_decl: ACC_DEF acc_decl ';'
{ acc_map.commit(); }
{
}
/* At least one line. */
lines: line
@ -137,11 +137,10 @@ line: strident ',' strident ',' condition ',' acc_list ';'
}
unsigned s = namer->new_state(*$1);
unsigned d = namer->new_state(*$3);
namer->graph().new_transition(s, d, cond, *$7);
namer->graph().new_transition(s, d, cond, $7);
delete $1;
delete $3;
delete $5;
delete $7;
}
;
@ -166,7 +165,7 @@ condition:
acc_list:
{
$$ = new bdd(bddfalse);
$$ = 0U;
}
| acc_list strident
{
@ -180,7 +179,7 @@ acc_list:
// $2 will be destroyed on error recovery.
YYERROR;
}
*$1 |= p.second;
$1 |= p.second;
}
delete $2;
$$ = $1;

Some files were not shown because too many files have changed in this diff Show more