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. 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 methods have been removed from the TGBA interface and all
subclasses. subclasses.
- tgba::succ_iter() now takes only one argument. The optional - Membership to acceptance sets are now stored using bit sets,
global_state and global_automaton arguments have been removed. 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 * Removed features
@ -87,6 +110,15 @@ New in spot 1.99a (not yet released)
automata (when viewed explictely), using the above and non automata (when viewed explictely), using the above and non
longuer supported tgba_bdd_concrete class. 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 in spot 1.2.5a (not yet released)
* New features: * New features:

View file

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

View file

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

View file

@ -23,6 +23,7 @@
#include "tgbaalgos/reachiter.hh" #include "tgbaalgos/reachiter.hh"
#include "tgbaalgos/gtec/gtec.hh" #include "tgbaalgos/gtec/gtec.hh"
#include "tgbaalgos/sccfilter.hh" #include "tgbaalgos/sccfilter.hh"
#include "tgbaalgos/dotty.hh"
namespace spot namespace spot
{ {
@ -55,7 +56,7 @@ namespace spot
{ {
typedef std::list<const state*> state_list; 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 == // 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 // 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 // masked version of dra->aut. So we should always explore the
@ -293,7 +294,7 @@ namespace spot
tgba_digraph_ptr out_; tgba_digraph_ptr out_;
const state_set& final_; const state_set& final_;
size_t num_states_; size_t num_states_;
bdd acc_; acc_cond::mark_t acc_;
const scc_map& sm_; const scc_map& sm_;
const std::vector<bool>& realizable_; const std::vector<bool>& realizable_;
}; };

View file

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

View file

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

View file

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

View file

@ -22,8 +22,8 @@
namespace spot namespace spot
{ {
fair_kripke_succ_iterator::fair_kripke_succ_iterator(const bdd& cond, fair_kripke_succ_iterator::fair_kripke_succ_iterator
const bdd& acc_cond) (const bdd& cond, acc_cond::mark_t acc_cond)
: cond_(cond), acc_cond_(acc_cond) : cond_(cond), acc_cond_(acc_cond)
{ {
} }
@ -40,7 +40,7 @@ namespace spot
return cond_; return cond_;
} }
bdd acc_cond::mark_t
fair_kripke_succ_iterator::current_acceptance_conditions() const fair_kripke_succ_iterator::current_acceptance_conditions() const
{ {
// Do not assert(!done()) here. It is OK to call // 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 /// The \a cond and \a acc_cond arguments will be those returned
/// by fair_kripke_succ_iterator::current_condition(), /// by fair_kripke_succ_iterator::current_condition(),
/// and fair_kripke_succ_iterator::current_acceptance_conditions(). /// 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 ~fair_kripke_succ_iterator();
virtual bdd current_condition() const; virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const; virtual acc_cond::mark_t current_acceptance_conditions() const;
protected: protected:
bdd cond_; bdd cond_;
bdd acc_cond_; acc_cond::mark_t acc_cond_;
}; };
/// \ingroup kripke /// \ingroup kripke
@ -89,13 +89,19 @@ namespace spot
class SPOT_API fair_kripke: public tgba class SPOT_API fair_kripke: public tgba
{ {
public: public:
fair_kripke(const bdd_dict_ptr& d)
: tgba(d)
{
}
/// \brief The condition that label the state \a s. /// \brief The condition that label the state \a s.
/// ///
/// This should be a conjunction of atomic propositions. /// This should be a conjunction of atomic propositions.
virtual bdd state_condition(const state* s) const = 0; virtual bdd state_condition(const state* s) const = 0;
/// \brief The set of acceptance conditions that label the state \a s. /// \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: protected:
virtual bdd compute_support_conditions(const state* s) const; virtual bdd compute_support_conditions(const state* s) const;

View file

@ -34,33 +34,21 @@ namespace spot
return cond_; return cond_;
} }
bdd acc_cond::mark_t
kripke_succ_iterator::current_acceptance_conditions() const kripke_succ_iterator::current_acceptance_conditions() const
{ {
// Do not assert(!done()) here. It is OK to call // Do not assert(!done()) here. It is OK to call
// this function on a state without successor. // this function on a state without successor.
return bddfalse; return 0U;
} }
kripke::~kripke() kripke::~kripke()
{ {
} }
bdd acc_cond::mark_t
kripke::state_acceptance_conditions(const state*) const 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 ~kripke_succ_iterator();
virtual bdd current_condition() const; virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const; virtual acc_cond::mark_t current_acceptance_conditions() const;
protected: protected:
bdd cond_; bdd cond_;
}; };
@ -92,11 +92,15 @@ namespace spot
class SPOT_API kripke: public fair_kripke class SPOT_API kripke: public fair_kripke
{ {
public: public:
kripke(const bdd_dict_ptr& d)
: fair_kripke(d)
{
}
virtual ~kripke(); virtual ~kripke();
virtual bdd state_acceptance_conditions(const state*) const; virtual acc_cond::mark_t state_acceptance_conditions(const state*) const;
virtual bdd neg_acceptance_conditions() const;
virtual bdd all_acceptance_conditions() const;
}; };

View file

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

View file

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

View file

@ -82,8 +82,11 @@ namespace spot
template<typename T, typename U> template<typename T, typename U>
std::size_t operator()(const std::pair<T, U> &p) const std::size_t operator()(const std::pair<T, U> &p) const
{ {
return wang32_hash(static_cast<size_t>(p.first) ^ std::hash<T> th;
static_cast<size_t>(p.second)); 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, namer->new_transition(*$1, *$1, bddtrue,
!strncmp("accept", $1->c_str(), 6) ? !strncmp("accept", $1->c_str(), 6) ?
result->all_acceptance_conditions() : result->acc().all_sets() :
static_cast<const bdd>(bddfalse)); spot::acc_cond::mark_t(0U));
delete $1; delete $1;
} }
| ident_list { delete $1; } | ident_list { delete $1; }
| ident_list "false" { delete $1; } | ident_list "false" { delete $1; }
| ident_list transition_block | ident_list transition_block
{ {
bdd acc = !strncmp("accept", $1->c_str(), 6) ? auto acc = !strncmp("accept", $1->c_str(), 6) ?
result->all_acceptance_conditions() : result->acc().all_sets() : spot::acc_cond::mark_t(0U);
static_cast<const bdd>(bddfalse);
for (auto& p: *$2) for (auto& p: *$2)
namer->new_transition(*$1, *p.second, *p.first, acc); namer->new_transition(*$1, *p.second, *p.first, acc);
// Free the list // Free the list

View file

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

View file

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

View file

@ -97,7 +97,7 @@ namespace spot
return (*i_)->condition; return (*i_)->condition;
} }
bdd acc_cond::mark_t
ta_explicit_succ_iterator::current_acceptance_conditions() const ta_explicit_succ_iterator::current_acceptance_conditions() const
{ {
assert(!done()); assert(!done());
@ -352,13 +352,14 @@ namespace spot
ta_explicit::ta_explicit(const const_tgba_ptr& tgba, ta_explicit::ta_explicit(const const_tgba_ptr& tgba,
bdd all_acceptance_conditions, unsigned n_acc,
state_ta_explicit* artificial_initial_state): state_ta_explicit* artificial_initial_state):
ta(tgba->get_dict()),
tgba_(tgba), tgba_(tgba),
all_acceptance_conditions_(all_acceptance_conditions),
artificial_initial_state_(artificial_initial_state) artificial_initial_state_(artificial_initial_state)
{ {
get_dict()->register_all_variables_of(&tgba_, this); get_dict()->register_all_variables_of(&tgba_, this);
acc().add_sets(n_acc);
if (artificial_initial_state != 0) if (artificial_initial_state != 0)
{ {
state_ta_explicit* is = add_state(artificial_initial_state); state_ta_explicit* is = add_state(artificial_initial_state);
@ -403,7 +404,7 @@ namespace spot
{ {
state_ta_explicit* i = state_ta_explicit* i =
down_cast<state_ta_explicit*>(get_artificial_initial_state()); 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 void
ta_explicit::create_transition(state_ta_explicit* source, bdd condition, 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* dest, bool add_at_beginning)
{ {
state_ta_explicit::transition* t = new state_ta_explicit::transition; 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 class SPOT_API ta_explicit : public ta
{ {
public: 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); state_ta_explicit* artificial_initial_state = 0);
const_tgba_ptr const_tgba_ptr
@ -55,7 +56,8 @@ namespace spot
void void
create_transition(state_ta_explicit* source, bdd condition, create_transition(state_ta_explicit* source, bdd condition,
bdd acceptance_conditions, state_ta_explicit* dest, acc_cond::mark_t acceptance_conditions,
state_ta_explicit* dest,
bool add_at_beginning = false); bool add_at_beginning = false);
void void
@ -115,27 +117,12 @@ namespace spot
return states_set_; 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: private:
// Disallow copy. // Disallow copy.
ta_explicit(const ta_explicit& other) SPOT_DELETED; ta_explicit(const ta_explicit& other) SPOT_DELETED;
ta_explicit& operator=(const ta_explicit& other) SPOT_DELETED; ta_explicit& operator=(const ta_explicit& other) SPOT_DELETED;
const_tgba_ptr tgba_; const_tgba_ptr tgba_;
bdd all_acceptance_conditions_;
state_ta_explicit* artificial_initial_state_; state_ta_explicit* artificial_initial_state_;
ta::states_set_t states_set_; ta::states_set_t states_set_;
ta::states_set_t initial_states_set_; ta::states_set_t initial_states_set_;
@ -152,7 +139,7 @@ namespace spot
struct transition struct transition
{ {
bdd condition; bdd condition;
bdd acceptance_conditions; acc_cond::mark_t acceptance_conditions;
state_ta_explicit* dest; state_ta_explicit* dest;
}; };
@ -255,7 +242,7 @@ namespace spot
virtual bdd virtual bdd
current_condition() const; current_condition() const;
virtual bdd virtual acc_cond::mark_t
current_acceptance_conditions() const; current_acceptance_conditions() const;
private: private:
@ -267,13 +254,11 @@ namespace spot
typedef std::shared_ptr<const ta_explicit> const_ta_explicit_ptr; typedef std::shared_ptr<const ta_explicit> const_ta_explicit_ptr;
inline ta_explicit_ptr make_ta_explicit(const const_tgba_ptr& tgba, inline ta_explicit_ptr make_ta_explicit(const const_tgba_ptr& tgba,
bdd all_acceptance_conditions, unsigned n_acc,
state_ta_explicit* state_ta_explicit*
artificial_initial_state = 0) artificial_initial_state = 0)
{ {
return std::make_shared<ta_explicit>(tgba, return std::make_shared<ta_explicit>(tgba, n_acc, artificial_initial_state);
all_acceptance_conditions,
artificial_initial_state);
} }
} }

View file

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

View file

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

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- 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). // de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -22,11 +22,9 @@
namespace spot namespace spot
{ {
tgta::tgta(const bdd_dict_ptr& d)
tgta::tgta() : tgba(d)
{}; {};
tgta::~tgta() tgta::~tgta()
{}; {};
} }

View file

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

View file

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

View file

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

View file

@ -244,7 +244,7 @@ namespace spot
return current_condition_; return current_condition_;
} }
bdd acc_cond::mark_t
tgta_succ_iterator_product::current_acceptance_conditions() const tgta_succ_iterator_product::current_acceptance_conditions() const
{ {
return current_acceptance_conditions_; return current_acceptance_conditions_;

View file

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

View file

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

View file

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

View file

@ -154,7 +154,8 @@ namespace spot
a->is_livelock_accepting_state(dst); a->is_livelock_accepting_state(dst);
state_ta_explicit* new_dst = state_ta_explicit* new_dst =
new state_ta_explicit(result_tgba->state_from_number(i->second), new state_ta_explicit
(result_tgba->state_from_number(i->second),
tgba_condition, is_initial_state, tgba_condition, is_initial_state,
is_accepting_state, is_accepting_state,
is_livelock_accepting_state); is_livelock_accepting_state);
@ -174,7 +175,8 @@ namespace spot
else if (is_initial_state) else if (is_initial_state)
result->add_to_initial_states_set(new_dst); result->add_to_initial_states_set(new_dst);
result->create_transition(ta_src, succit->current_condition(), result->create_transition
(ta_src, succit->current_condition(),
succit->current_acceptance_conditions(), succit->current_acceptance_conditions(),
ta_dst); ta_dst);
} }
@ -185,6 +187,26 @@ namespace spot
static partition_t static partition_t
build_partition(const const_ta_ptr& ta_) 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 cur_run;
partition_t next_run; partition_t next_run;
@ -237,7 +259,7 @@ namespace spot
// Use bdd variables to number sets. set_num is the first variable // Use bdd variables to number sets. set_num is the first variable
// available. // available.
unsigned set_num = unsigned set_num =
ta_->get_dict()->register_anonymous_variables(size, ta_); ta_->get_dict()->register_anonymous_variables(size, &m2b);
std::set<int> free_var; std::set<int> free_var;
for (unsigned i = set_num; i < set_num + size; ++i) for (unsigned i = set_num; i < set_num + size; ++i)
@ -335,6 +357,7 @@ namespace spot
delete S; delete S;
} }
// A bdd_states_map is a list of formulae (in a BDD form) // A bdd_states_map is a list of formulae (in a BDD form)
// associated with a destination set of states. // associated with a destination set of states.
typedef std::map<bdd, hash_set*, bdd_less_than> bdd_states_map; 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); hash_map::const_iterator i = state_set_map.find(dst);
assert(i != state_set_map.end()); assert(i != state_set_map.end());
bdd current_acceptance_conditions = auto curacc =
si->current_acceptance_conditions(); mark_to_bdd(si->current_acceptance_conditions());
if (current_acceptance_conditions == bddfalse) f |= (bdd_ithvar(i->second)
current_acceptance_conditions & si->current_condition() & curacc);
= bdd_false_acceptance_condition;
f |= (bdd_ithvar(i->second) & si->current_condition()
& current_acceptance_conditions);
trace trace
<< "+f: " << bdd_format_accset(ta_->get_dict(), f) << "+f: " << bdd_format_accset(ta_->get_dict(), f)
<< "\n -bdd_ithvar(i->second): " << "\n -bdd_ithvar(i->second): "
@ -388,8 +408,7 @@ namespace spot
<< bdd_format_accset(ta_->get_dict(), << bdd_format_accset(ta_->get_dict(),
si->current_condition()) si->current_condition())
<< "\n -current_acceptance_conditions: " << "\n -current_acceptance_conditions: "
<< bdd_format_accset(ta_->get_dict(), << si->current_acceptance_conditions()
current_acceptance_conditions)
<< std::endl; << std::endl;
} }
delete si; delete si;
@ -480,6 +499,7 @@ namespace spot
trace << std::endl; trace << std::endl;
#endif #endif
ta_->get_dict()->unregister_all_my_variables(&m2b);
return done; return done;
} }
} }
@ -489,7 +509,7 @@ namespace spot
{ {
auto tgba = make_tgba_digraph(ta_->get_dict()); 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_); partition_t partition = build_partition(ta_);
@ -509,7 +529,7 @@ namespace spot
{ {
auto tgba = make_tgba_digraph(tgta_->get_dict()); 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(); auto ta = tgta_->get_ta();

View file

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

View file

@ -26,6 +26,7 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS)
tgbadir = $(pkgincludedir)/tgba tgbadir = $(pkgincludedir)/tgba
tgba_HEADERS = \ tgba_HEADERS = \
acc.hh \
bdddict.hh \ bdddict.hh \
bddprint.hh \ bddprint.hh \
formula2bdd.hh \ formula2bdd.hh \
@ -33,11 +34,9 @@ tgba_HEADERS = \
taatgba.hh \ taatgba.hh \
tgba.hh \ tgba.hh \
tgbagraph.hh \ tgbagraph.hh \
tgbakvcomplement.hh \
tgbamask.hh \ tgbamask.hh \
tgbaproxy.hh \ tgbaproxy.hh \
tgbaproduct.hh \ tgbaproduct.hh \
tgbasgba.hh \
tgbasafracomplement.hh tgbasafracomplement.hh
noinst_LTLIBRARIES = libtgba.la noinst_LTLIBRARIES = libtgba.la
@ -48,9 +47,7 @@ libtgba_la_SOURCES = \
taatgba.cc \ taatgba.cc \
tgba.cc \ tgba.cc \
tgbagraph.cc \ tgbagraph.cc \
tgbakvcomplement.cc \
tgbaproduct.cc \ tgbaproduct.cc \
tgbamask.cc \ tgbamask.cc \
tgbaproxy.cc \ tgbaproxy.cc \
tgbasafracomplement.cc \ tgbasafracomplement.cc
tgbasgba.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; class tgba_product;
typedef std::shared_ptr<const tgba_product> const_tgba_product_ptr; typedef std::shared_ptr<const tgba_product> const_tgba_product_ptr;
typedef std::shared_ptr<tgba_product> 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 #endif // SPOT_TGBA_FWD_HH

View file

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

View file

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

View file

@ -25,10 +25,10 @@
namespace spot namespace spot
{ {
tgba::tgba() tgba::tgba(const bdd_dict_ptr& d)
: iter_cache_(nullptr), : iter_cache_(nullptr),
last_support_conditions_input_(0), acc_(d),
num_acc_(-1) last_support_conditions_input_(0)
{ {
props = 0U; props = 0U;
} }
@ -69,23 +69,6 @@ namespace spot
return ""; 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 bool
tgba::is_empty() const tgba::is_empty() const
{ {

View file

@ -23,8 +23,8 @@
#ifndef SPOT_TGBA_TGBA_HH #ifndef SPOT_TGBA_TGBA_HH
# define SPOT_TGBA_TGBA_HH # define SPOT_TGBA_TGBA_HH
#include "bdddict.hh"
#include "fwd.hh" #include "fwd.hh"
#include "acc.hh"
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include "misc/casts.hh" #include "misc/casts.hh"
@ -387,7 +387,7 @@ namespace spot
virtual bdd current_condition() const = 0; virtual bdd current_condition() const = 0;
/// \brief Get the acceptance conditions on the transition leading /// \brief Get the acceptance conditions on the transition leading
/// to this successor. /// 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> class SPOT_API tgba: public std::enable_shared_from_this<tgba>
{ {
protected: protected:
tgba(); tgba(const bdd_dict_ptr& d);
// Any iterator returned via release_iter. // Any iterator returned via release_iter.
mutable tgba_succ_iterator* iter_cache_; mutable tgba_succ_iterator* iter_cache_;
@ -572,7 +572,10 @@ namespace spot
/// formulae, and vice versa. This is useful when dealing with /// formulae, and vice versa. This is useful when dealing with
/// several automata (which may use the same BDD variable for /// several automata (which may use the same BDD variable for
/// different formula), or simply when printing. /// 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. /// \brief Format the state as a string for printing.
/// ///
@ -615,40 +618,27 @@ namespace spot
virtual state* project_state(const state* s, virtual state* project_state(const state* s,
const const_tgba_ptr& t) const; 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. const acc_cond& acc() const
virtual unsigned int number_of_acceptance_conditions() const; {
return acc_;
}
/// \brief Return the conjuction of all negated acceptance acc_cond& acc()
/// variables. {
/// return acc_;
/// 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;
virtual bool is_empty() const; virtual bool is_empty() const;
protected: protected:
acc_cond acc_;
/// Do the actual computation of tgba::support_conditions(). /// Do the actual computation of tgba::support_conditions().
virtual bdd compute_support_conditions(const state* state) const = 0; virtual bdd compute_support_conditions(const state* state) const = 0;
mutable const state* last_support_conditions_input_; mutable const state* last_support_conditions_input_;
private: private:
mutable bdd last_support_conditions_output_; mutable bdd last_support_conditions_output_;
mutable int num_acc_;
protected: protected:

View file

@ -23,41 +23,6 @@
namespace spot 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() void tgba_digraph::merge_transitions()
{ {
for (auto& s: g_.states()) for (auto& s: g_.states())
@ -65,7 +30,7 @@ namespace spot
// Map a pair (dest state, acc) to the first transition seen // Map a pair (dest state, acc) to the first transition seen
// with such characteristic. // 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; std::unordered_map<key_t, graph_t::transition, pair_hash> trmap;
auto t = g_.out_iteraser(s); auto t = g_.out_iteraser(s);
@ -78,7 +43,7 @@ namespace spot
continue; continue;
} }
key_t k(t->dst, t->acc.id()); key_t k(t->dst, t->acc);
auto p = trmap.emplace(k, t.trans()); auto p = trmap.emplace(k, t.trans());
if (!p.second) if (!p.second)
{ {

View file

@ -76,14 +76,14 @@ namespace spot
struct SPOT_API tgba_graph_trans_data struct SPOT_API tgba_graph_trans_data
{ {
bdd cond; bdd cond;
bdd acc; acc_cond::mark_t acc;
explicit tgba_graph_trans_data() 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) : cond(cond), acc(acc)
{ {
} }
@ -141,7 +141,7 @@ namespace spot
return g_->trans_data(p_).cond; return g_->trans_data(p_).cond;
} }
virtual bdd current_acceptance_conditions() const virtual acc_cond::mark_t current_acceptance_conditions() const
{ {
assert(!done()); assert(!done());
return g_->trans_data(p_).acc; return g_->trans_data(p_).acc;
@ -161,23 +161,18 @@ namespace spot
protected: protected:
graph_t g_; graph_t g_;
bdd_dict_ptr dict_;
bdd all_acceptance_conditions_;
bdd neg_acceptance_conditions_;
mutable unsigned init_number_; mutable unsigned init_number_;
public: public:
tgba_digraph(const bdd_dict_ptr& dict) tgba_digraph(const bdd_dict_ptr& dict)
: dict_(dict), : tgba(dict),
all_acceptance_conditions_(bddfalse),
neg_acceptance_conditions_(bddtrue),
init_number_(0) init_number_(0)
{ {
} }
virtual ~tgba_digraph() virtual ~tgba_digraph()
{ {
dict_->unregister_all_my_variables(this); get_dict()->unregister_all_my_variables(this);
// Prevent this state from being destroyed by ~tgba(), // Prevent this state from being destroyed by ~tgba(),
// as the state will be destroyed when g_ is destroyed. // as the state will be destroyed when g_ is destroyed.
last_support_conditions_input_ = 0; last_support_conditions_input_ = 0;
@ -212,11 +207,6 @@ namespace spot
return g_; return g_;
} }
virtual bdd_dict_ptr get_dict() const
{
return this->dict_;
}
unsigned num_states() const unsigned num_states() const
{ {
return g_.num_states(); return g_.num_states();
@ -314,8 +304,22 @@ namespace spot
return g_.trans_data(t); return g_.trans_data(t);
} }
void set_acceptance_conditions(bdd all); void set_acceptance_conditions(unsigned num)
bdd set_single_acceptance_set(); {
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() unsigned new_state()
{ {
@ -328,7 +332,7 @@ namespace spot
} }
unsigned new_transition(unsigned src, unsigned dst, 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); return g_.new_transition(src, dst, cond, acc);
} }
@ -337,7 +341,7 @@ namespace spot
bdd cond, bool acc = true) bdd cond, bool acc = true)
{ {
if (acc) if (acc)
return g_.new_transition(src, dst, cond, all_acceptance_conditions_); return g_.new_transition(src, dst, cond, acc_.all_sets());
else else
return g_.new_transition(src, dst, cond); return g_.new_transition(src, dst, cond);
} }
@ -364,22 +368,13 @@ namespace spot
/// \brief Copy the acceptance conditions of another tgba. /// \brief Copy the acceptance conditions of another tgba.
void copy_acceptance_conditions_of(const const_tgba_ptr& a) 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) void copy_ap_of(const const_tgba_ptr& a)
{ {
dict_->register_all_propositions_of(a, this); get_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_;
} }
virtual bdd compute_support_conditions(const state* s) const virtual bdd compute_support_conditions(const state* s) const
@ -400,7 +395,7 @@ namespace spot
for (auto& t: g_.out(s)) for (auto& t: g_.out(s))
// Stop at the first transition, since the remaining should be // Stop at the first transition, since the remaining should be
// labeled identically. // labeled identically.
return t.acc == all_acceptance_conditions_; return acc_.accepting(t.acc);
return false; 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; const state* dest;
bdd cond; bdd cond;
bdd acc; acc_cond::mark_t acc;
}; };
typedef std::vector<transition> transitions; typedef std::vector<transition> transitions;
@ -67,7 +67,7 @@ namespace spot
return it_->cond; return it_->cond;
} }
bdd current_acceptance_conditions() const acc_cond::mark_t current_acceptance_conditions() const
{ {
return it_->acc; return it_->acc;
} }
@ -128,19 +128,19 @@ namespace spot
for (auto it: original_->succ(local_state)) for (auto it: original_->succ(local_state))
{ {
const spot::state* s = it->current_state(); const spot::state* s = it->current_state();
bdd acc = it->current_acceptance_conditions(); auto acc = it->current_acceptance_conditions();
if (!wanted(s, acc)) if (!wanted(s, acc))
{ {
s->destroy(); s->destroy();
continue; continue;
} }
res->trans_.emplace_back(transition {s, it->current_condition(), res->trans_.emplace_back
acc}); (transition {s, it->current_condition(), acc});
} }
return res; 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: protected:
const state* init_; 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); state_set::const_iterator i = mask_.find(s);
return i != mask_.end(); 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); state_set::const_iterator i = mask_.find(s);
return i == mask_.end(); return i == mask_.end();
@ -186,19 +186,19 @@ namespace spot
class tgba_mask_acc_ignore: public tgba_mask class tgba_mask_acc_ignore: public tgba_mask
{ {
const bdd& mask_; unsigned mask_;
public: public:
tgba_mask_acc_ignore(const const_tgba_ptr& masked, tgba_mask_acc_ignore(const const_tgba_ptr& masked,
const bdd& mask, unsigned mask,
const state* init) const state* init)
: tgba_mask(masked, init), : tgba_mask(masked, init),
mask_(mask) 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 const_tgba_ptr
build_tgba_mask_acc_ignore(const const_tgba_ptr& to_mask, build_tgba_mask_acc_ignore(const const_tgba_ptr& to_mask,
const bdd to_ignore, unsigned to_ignore,
const state* init) const state* init)
{ {
return std::make_shared<tgba_mask_acc_ignore>(to_mask, to_ignore, 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 /// \ingroup tgba_on_the_fly_algorithms
/// \brief Mask a TGBA, rejecting some acceptance set of transitions. /// \brief Mask a TGBA, rejecting some acceptance set of transitions.
/// ///
/// This will ignore all transitions labeled by the acceptance ACC /// This will ignore all transitions that have the TO_IGNORE
/// such that ACC & TO_IGNORE != bddfalse. The initial state can /// acceptance mark. The initial state can optionally be reset to
/// optionally be reset to \a init. /// \a init.
/// ///
/// Note that the acceptance condition of the automaton (i.e. the /// Note that the acceptance condition of the automaton (i.e. the
/// set of all acceptance set) is not changed, because so far this /// set of all acceptance set) is not changed, because so far this
@ -62,7 +62,7 @@ namespace spot
/// all_acceptance_conditions(). /// all_acceptance_conditions().
SPOT_API const_tgba_ptr SPOT_API const_tgba_ptr
build_tgba_mask_acc_ignore(const const_tgba_ptr& to_mask, build_tgba_mask_acc_ignore(const const_tgba_ptr& to_mask,
const bdd to_ignore, unsigned to_ignore,
const state* init = 0); const state* init = 0);
} }

View file

@ -84,8 +84,9 @@ namespace spot
public: public:
tgba_succ_iterator_product_common(tgba_succ_iterator* left, tgba_succ_iterator_product_common(tgba_succ_iterator* left,
tgba_succ_iterator* right, tgba_succ_iterator* right,
const tgba_product* prod,
fixed_size_pool* pool) 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: protected:
tgba_succ_iterator* left_; tgba_succ_iterator* left_;
tgba_succ_iterator* right_; tgba_succ_iterator* right_;
const tgba_product* prod_;
fixed_size_pool* pool_; fixed_size_pool* pool_;
friend class spot::tgba_product; friend class spot::tgba_product;
}; };
@ -150,13 +152,9 @@ namespace spot
public: public:
tgba_succ_iterator_product(tgba_succ_iterator* left, tgba_succ_iterator_product(tgba_succ_iterator* left,
tgba_succ_iterator* right, tgba_succ_iterator* right,
bdd left_neg, bdd right_neg, const tgba_product* prod,
bddPair* right_common_acc,
fixed_size_pool* pool) fixed_size_pool* pool)
: tgba_succ_iterator_product_common(left, right, pool), : tgba_succ_iterator_product_common(left, right, prod, pool)
left_neg_(left_neg),
right_neg_(right_neg),
right_common_acc_(right_common_acc)
{ {
} }
@ -203,18 +201,17 @@ namespace spot
return current_cond_; return current_cond_;
} }
bdd current_acceptance_conditions() const acc_cond::mark_t current_acceptance_conditions() const
{ {
return ((left_->current_acceptance_conditions() & right_neg_) return
| (bdd_replace(right_->current_acceptance_conditions(), prod_->acc().join(prod_->left_acc(),
right_common_acc_) & left_neg_)); left_->current_acceptance_conditions(),
prod_->right_acc(),
right_->current_acceptance_conditions());
} }
protected: protected:
bdd current_cond_; bdd current_cond_;
bdd left_neg_;
bdd right_neg_;
bddPair* right_common_acc_;
}; };
/// Iterate over the successors of a product computed on the fly. /// Iterate over the successors of a product computed on the fly.
@ -225,8 +222,9 @@ namespace spot
public: public:
tgba_succ_iterator_product_kripke(tgba_succ_iterator* left, tgba_succ_iterator_product_kripke(tgba_succ_iterator* left,
tgba_succ_iterator* right, tgba_succ_iterator* right,
const tgba_product* prod,
fixed_size_pool* pool) 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_; return current_cond_;
} }
bdd current_acceptance_conditions() const acc_cond::mark_t current_acceptance_conditions() const
{ {
return right_->current_acceptance_conditions(); return right_->current_acceptance_conditions();
} }
@ -286,10 +284,10 @@ namespace spot
tgba_product::tgba_product(const const_tgba_ptr& left, tgba_product::tgba_product(const const_tgba_ptr& left,
const const_tgba_ptr& right) 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)) 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 // 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 // with (we don't have to fix the acceptance conditions, and
@ -308,55 +306,17 @@ namespace spot
left_kripke_ = false; left_kripke_ = false;
} }
dict_->register_all_variables_of(&left_, this); auto d = get_dict();
dict_->register_all_variables_of(&right_, this); d->register_all_propositions_of(&left_, this);
d->register_all_propositions_of(&right_, this);
if (left_kripke_) assert(acc_.num_sets() == 0);
{ acc_.add_sets(left->acc().num_sets() + right->acc().num_sets());
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;
} }
tgba_product::~tgba_product() tgba_product::~tgba_product()
{ {
if (!left_kripke_) get_dict()->unregister_all_my_variables(this);
bdd_freepair(right_common_acc_);
dict_->unregister_all_my_variables(this);
// Prevent these states from being destroyed by ~tgba(): they // Prevent these states from being destroyed by ~tgba(): they
// will be destroyed before when the pool is destructed. // will be destroyed before when the pool is destructed.
if (last_support_conditions_input_) if (last_support_conditions_input_)
@ -393,13 +353,9 @@ namespace spot
fixed_size_pool* p = const_cast<fixed_size_pool*>(&pool_); fixed_size_pool* p = const_cast<fixed_size_pool*>(&pool_);
if (left_kripke_) 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 else
return new tgba_succ_iterator_product(li, ri, return new tgba_succ_iterator_product(li, ri, this, p);
left_acc_complement_,
right_acc_complement_,
right_common_acc_,
p);
} }
bdd bdd
@ -412,10 +368,14 @@ namespace spot
return lsc & rsc; return lsc & rsc;
} }
bdd_dict_ptr const acc_cond& tgba_product::left_acc() const
tgba_product::get_dict() const
{ {
return dict_; return left_->acc();
}
const acc_cond& tgba_product::right_acc() const
{
return right_->acc();
} }
std::string std::string
@ -441,18 +401,6 @@ namespace spot
return right_->project_state(s2->right(), t); 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 std::string
tgba_product::transition_annotation(const tgba_succ_iterator* t) const tgba_product::transition_annotation(const tgba_succ_iterator* t) const
{ {

View file

@ -94,8 +94,6 @@ namespace spot
virtual tgba_succ_iterator* virtual tgba_succ_iterator*
succ_iter(const state* state) const; 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 format_state(const state* state) const;
virtual std::string virtual std::string
@ -103,22 +101,16 @@ namespace spot
virtual state* project_state(const state* s, const const_tgba_ptr& t) const; virtual state* project_state(const state* s, const const_tgba_ptr& t) const;
virtual bdd all_acceptance_conditions() const; const acc_cond& left_acc() const;
virtual bdd neg_acceptance_conditions() const; const acc_cond& right_acc() const;
protected: protected:
virtual bdd compute_support_conditions(const state* state) const; virtual bdd compute_support_conditions(const state* state) const;
protected: protected:
bdd_dict_ptr dict_;
const_tgba_ptr left_; const_tgba_ptr left_;
const_tgba_ptr right_; const_tgba_ptr right_;
bool left_kripke_; 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_; fixed_size_pool pool_;
private: private:

View file

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

View file

@ -46,8 +46,6 @@ namespace spot
virtual tgba_succ_iterator* virtual tgba_succ_iterator*
succ_iter(const state* state) const; 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 format_state(const state* state) const;
virtual std::string virtual std::string
@ -55,10 +53,6 @@ namespace spot
virtual state* project_state(const state* s, const const_tgba_ptr& t) const; 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: protected:
virtual bdd compute_support_conditions(const state* state) const; virtual bdd compute_support_conditions(const state* state) const;
const_tgba_ptr original_; const_tgba_ptr original_;

View file

@ -962,7 +962,7 @@ namespace spot
typedef std::multimap<bdd, state_complement*, bdd_less_than> succ_list_t; typedef std::multimap<bdd, state_complement*, bdd_less_than> succ_list_t;
tgba_safra_complement_succ_iterator(const succ_list_t& list, 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) : list_(list), the_acceptance_cond_(the_acceptance_cond)
{ {
} }
@ -979,10 +979,10 @@ namespace spot
virtual bool done() const; virtual bool done() const;
virtual state_complement* current_state() const; virtual state_complement* current_state() const;
virtual bdd current_condition() const; virtual bdd current_condition() const;
virtual bdd current_acceptance_conditions() const; virtual acc_cond::mark_t current_acceptance_conditions() const;
private: private:
succ_list_t list_; succ_list_t list_;
bdd the_acceptance_cond_; acc_cond::mark_t the_acceptance_cond_;
succ_list_t::const_iterator it_; succ_list_t::const_iterator it_;
}; };
@ -1020,7 +1020,7 @@ namespace spot
return it_->first; return it_->first;
} }
bdd acc_cond::mark_t
tgba_safra_complement_succ_iterator::current_acceptance_conditions() const tgba_safra_complement_succ_iterator::current_acceptance_conditions() const
{ {
assert(!done()); assert(!done());
@ -1075,38 +1075,22 @@ namespace spot
////////////////////////// //////////////////////////
tgba_safra_complement::tgba_safra_complement(const const_tgba_ptr& a) 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"); 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 #if TRANSFORM_TO_TBA
the_acceptance_cond_ = bdd_ithvar(v); the_acceptance_cond_ = acc_.mark(acc_.add_set());
#endif #endif
#if TRANSFORM_TO_TGBA #if TRANSFORM_TO_TGBA
unsigned nb_acc = unsigned nb_acc =
static_cast<safra_tree_automaton*>(safra_)->get_nb_acceptance_pairs(); static_cast<safra_tree_automaton*>(safra_)->get_nb_acceptance_pairs();
all_acceptance_cond_ = bddfalse;
neg_acceptance_cond_ = bddtrue;
acceptance_cond_vec_.reserve(nb_acc); acceptance_cond_vec_.reserve(nb_acc);
for (unsigned i = 0; i < nb_acc; ++i) for (unsigned i = 0; i < nb_acc; ++i)
{ acceptance_cond_vec_.push_back(acc_.mark(acc_.add_set()));
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;
}
#endif #endif
} }
@ -1171,7 +1155,7 @@ namespace spot
assert(tr != a->automaton.end()); assert(tr != a->automaton.end());
bdd condition = bddfalse; acc_cond::mark_t condition = 0U;
tgba_safra_complement_succ_iterator::succ_list_t succ_list; tgba_safra_complement_succ_iterator::succ_list_t succ_list;
int nb_acceptance_pairs = a->get_nb_acceptance_pairs(); int nb_acceptance_pairs = a->get_nb_acceptance_pairs();
bitvect* e = make_bitvect(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); 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 std::string
tgba_safra_complement::format_state(const state* state) const tgba_safra_complement::format_state(const state* state) const
{ {
@ -1264,26 +1242,6 @@ namespace spot
return s->to_string(); 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 bdd
tgba_safra_complement::compute_support_conditions(const state* state) const 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 state* get_init_state() const;
virtual tgba_succ_iterator* succ_iter(const state* 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 std::string format_state(const state* state) const;
virtual bdd all_acceptance_conditions() const;
virtual bdd neg_acceptance_conditions() const;
void* get_safra() const void* get_safra() const
{ {
@ -73,13 +70,11 @@ namespace spot
const_tgba_ptr automaton_; const_tgba_ptr automaton_;
void* safra_; void* safra_;
#if TRANSFORM_TO_TBA #if TRANSFORM_TO_TBA
bdd the_acceptance_cond_; acc_cond::mark_t the_acceptance_cond_;
#endif #endif
#if TRANSFORM_TO_TGBA #if TRANSFORM_TO_TGBA
bdd all_acceptance_cond_;
bdd neg_acceptance_cond_;
// Map to i the i-th acceptance condition of the final automaton. // 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 #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; continue;
bdd cond = i->current_condition(); 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 }; tgba_run::step s = { src, cond, acc };
if (match(s, dest)) if (match(s, dest))

View file

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

View file

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

View file

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

View file

@ -73,9 +73,8 @@ namespace spot
else else
{ {
si->first(); si->first();
accepting = ((!si->done()) auto a = si->current_acceptance_conditions();
&& (si->current_acceptance_conditions() == accepting = !si->done() && aut_->acc().accepting(a);
aut_->all_acceptance_conditions()));
} }
} }
else else
@ -96,10 +95,13 @@ namespace spot
{ {
std::string label = std::string label =
bdd_format_formula(aut_->get_dict(), bdd_format_formula(aut_->get_dict(),
si->current_condition()) si->current_condition());
+ "\n" auto a = si->current_acceptance_conditions();
+ bdd_format_accset(aut_->get_dict(), if (a)
si->current_acceptance_conditions()); {
label += "\n";
label += aut_->acc().format(a);
}
std::string s = aut_->transition_annotation(si); std::string s = aut_->transition_annotation(si);
if (!s.empty()) 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 // construction of contraints (4,5) : all loops in the product
// where no accepting run is detected in the ref. automaton, // where no accepting run is detected in the ref. automaton,
@ -477,7 +477,7 @@ namespace spot
if (sm.scc_of(dp) != q1p_scc) if (sm.scc_of(dp) != q1p_scc)
continue; continue;
if (tr.acc == all_acc) if (ra.accepting(tr.acc))
continue; continue;
for (unsigned q3 = 0; q3 < d.cand_size; ++q3) for (unsigned q3 = 0; q3 < d.cand_size; ++q3)
{ {
@ -574,7 +574,7 @@ namespace spot
{ {
// We only care about the looping case if // We only care about the looping case if
// it is accepting in the reference. // it is accepting in the reference.
if (tr.acc != all_acc) if (!ra.accepting(tr.acc))
continue; continue;
bdd all = tr.cond; bdd all = tr.cond;
while (all != bddfalse) while (all != bddfalse)
@ -636,7 +636,7 @@ namespace spot
auto autdict = aut->get_dict(); auto autdict = aut->get_dict();
auto a = make_tgba_digraph(autdict); auto a = make_tgba_digraph(autdict);
a->copy_ap_of(aut); 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); a->new_states(satdict.cand_size);
unsigned last_aut_trans = -1U; unsigned last_aut_trans = -1U;

View file

@ -28,18 +28,20 @@ namespace spot
// Clone the original automaton. // Clone the original automaton.
tgba_digraph_ptr res = tgba_dupexp_dfs(aut); 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 // We will modify res in place, and the resulting
// automaton will only have one acceptance set. // automaton will only have one acceptance set.
// This changes aut->acc();
res->set_single_acceptance_set(); res->set_single_acceptance_set();
unsigned num_acc = aut->number_of_acceptance_conditions(); unsigned num_sets = oldacc.num_sets();
unsigned n = res->num_states(); unsigned n = res->num_states();
// We will duplicate the automaton as many times as we have // We will duplicate the automaton as many times as we have
// acceptance sets, and we need one extra sink state. // 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; unsigned sink = res->num_states() - 1;
// The sink state has an accepting self-loop. // The sink state has an accepting self-loop.
res->new_acc_transition(sink, sink, bddtrue); res->new_acc_transition(sink, sink, bddtrue);
@ -54,29 +56,26 @@ namespace spot
if (t.dst >= n) // Ignore transitions we added. if (t.dst >= n) // Ignore transitions we added.
break; break;
missingcond -= t.cond; missingcond -= t.cond;
bdd curacc = t.acc; acc_cond::mark_t curacc = t.acc;
// The original transition must not accept anymore. // The original transition must not accept anymore.
t.acc = bddfalse; t.acc = 0U;
// Transition that were fully accepting are never cloned. // Transition that were fully accepting are never cloned.
if (curacc == oldaccs) if (oldacc.accepting(curacc))
continue; continue;
// Save t.cond and t.dst as the reference to t // Save t.cond and t.dst as the reference to t
// is invalided by calls to new_transition(). // is invalided by calls to new_transition().
unsigned dst = t.dst; unsigned dst = t.dst;
bdd cond = t.cond; 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', // 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. // belong to the acceptance set.
unsigned add = 0; unsigned add = 0;
while (curacc != bddtrue) for (unsigned set = 0; set < num_sets; ++set)
{ {
add += n; add += n;
bdd h = bdd_high(curacc); if (!oldacc.has(curacc, set))
if (h == bddfalse)
{ {
// Clone the transition // Clone the transition
res->new_acc_transition(src + add, dst + add, cond); res->new_acc_transition(src + add, dst + add, cond);
@ -93,26 +92,9 @@ namespace spot
// arc set would be better. // arc set would be better.
if (dst <= src) if (dst <= src)
res->new_transition(src, dst + add, cond); 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. // Complete the original automaton.
if (missingcond != bddfalse) if (missingcond != bddfalse)
@ -134,21 +116,18 @@ namespace spot
true, // inherently_weak true, // inherently_weak
true); // deterministic true); // deterministic
bdd oldaccs = aut->all_acceptance_conditions();
bdd oldnegs = aut->neg_acceptance_conditions();
scc_info si(res); scc_info si(res);
// We will modify res in place, and the resulting // We will modify res in place, and the resulting
// automaton will only have one acceptance set. // 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(); res->prop_state_based_acc();
unsigned sink = res->num_states(); unsigned sink = res->num_states();
for (unsigned src = 0; src < sink; ++src) for (unsigned src = 0; src < sink; ++src)
{ {
bdd acc = bddfalse; acc_cond::mark_t acc = 0U;
unsigned scc = si.scc_of(src); unsigned scc = si.scc_of(src);
if (!si.is_accepting_scc(scc) && !si.is_trivial(scc)) if (!si.is_accepting_scc(scc) && !si.is_trivial(scc))
acc = all_acc; acc = all_acc;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -54,10 +54,6 @@ namespace spot
struct gv04: public emptiness_check, public ec_statistics 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. // Map of visited states.
typedef std::unordered_map<const state*, size_t, typedef std::unordered_map<const state*, size_t,
state_ptr_hash, state_ptr_equal> hash_type; state_ptr_hash, state_ptr_equal> hash_type;
@ -72,9 +68,9 @@ namespace spot
bool violation; // Whether an accepting run was found. bool violation; // Whether an accepting run was found.
gv04(const const_tgba_ptr& a, option_map o) 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() ~gv04()
@ -125,7 +121,8 @@ namespace spot
else else
{ {
const state* s_prime = iter->current_state(); 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(); inc_transitions();
trace << " Next successor: s_prime = " trace << " Next successor: s_prime = "
@ -365,7 +362,7 @@ namespace spot
virtual bool virtual bool
match(tgba_run::step& step, const state*) 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_start = data.stack[scc_root].s;
const state* bfs_end = bfs_start; const state* bfs_end = bfs_start;
if (data.accepting != bddfalse) if (a_->acc().num_sets() > 0)
{ {
first_bfs b1(this, scc_root); first_bfs b1(this, scc_root);
bfs_start = b1.search(bfs_start, res->cycle); bfs_start = b1.search(bfs_start, res->cycle);

View file

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

View file

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

View file

@ -35,49 +35,12 @@ namespace spot
{ {
namespace 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 class lbtt_bfs : public tgba_reachable_iterator_breadth_first
{ {
public: public:
lbtt_bfs(const const_tgba_ptr& a, std::ostream& os, bool sba_format) lbtt_bfs(const const_tgba_ptr& a, std::ostream& os, bool sba_format)
: tgba_reachable_iterator_breadth_first(a), : tgba_reachable_iterator_breadth_first(a),
os_(os), os_(os),
all_acc_conds_(a->all_acceptance_conditions()),
acs_(all_acc_conds_),
sba_format_(sba_format), sba_format_(sba_format),
sba_(nullptr) sba_(nullptr)
{ {
@ -104,7 +67,7 @@ namespace spot
// iterator. // iterator.
tgba_succ_iterator* it = aut_->succ_iter(s); tgba_succ_iterator* it = aut_->succ_iter(s);
bool accepting = it->first() bool accepting = it->first()
&& it->current_acceptance_conditions() == all_acc_conds_; && aut_->acc().accepting(it->current_acceptance_conditions());
aut_->release_iter(it); aut_->release_iter(it);
return accepting; return accepting;
} }
@ -138,7 +101,8 @@ namespace spot
body_ << out - 1 << ' '; body_ << out - 1 << ' ';
if (!sba_format_) if (!sba_format_)
{ {
acs_.split(body_, si->current_acceptance_conditions()); for (auto s: aut_->acc().sets(si->current_acceptance_conditions()))
body_ << s << ' ';
body_ << "-1 "; body_ << "-1 ";
} }
const ltl::formula* f = bdd_to_formula(si->current_condition(), const ltl::formula* f = bdd_to_formula(si->current_condition(),
@ -155,7 +119,7 @@ namespace spot
if (sba_format_) if (sba_format_)
os_ << '1'; os_ << '1';
else else
os_ << aut_->number_of_acceptance_conditions() << 't'; os_ << aut_->acc().num_sets() << 't';
os_ << '\n' << body_.str() << "-1" << std::endl; os_ << '\n' << body_.str() << "-1" << std::endl;
} }
@ -163,7 +127,6 @@ namespace spot
std::ostream& os_; std::ostream& os_;
std::ostringstream body_; std::ostringstream body_;
bdd all_acc_conds_; bdd all_acc_conds_;
acceptance_cond_splitter acs_;
bool sba_format_; bool sba_format_;
const_tgba_digraph_ptr sba_; const_tgba_digraph_ptr sba_;
}; };
@ -196,7 +159,7 @@ namespace spot
break; break;
// Read the acceptance conditions. // Read the acceptance conditions.
bdd acc = bddfalse; acc_cond::mark_t acc = 0U;
for (;;) for (;;)
{ {
int acc_n = 0; int acc_n = 0;
@ -254,7 +217,7 @@ namespace spot
aut->set_init_state(src_state); aut->set_init_state(src_state);
// Read the acceptance conditions. // Read the acceptance conditions.
bdd acc = bddfalse; acc_cond::mark_t acc = 0U;
for (;;) for (;;)
{ {
int acc_n = 0; int acc_n = 0;

View file

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

View file

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

View file

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

View file

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

View file

@ -142,7 +142,7 @@ namespace spot
if (type_ == BA) if (type_ == BA)
state_based_ = true; state_based_ = true;
int original_acc = a->number_of_acceptance_conditions(); int original_acc = a->acc().num_sets();
// Remove useless SCCs. // Remove useless SCCs.
if (type_ == Monitor) if (type_ == Monitor)
@ -237,7 +237,7 @@ namespace spot
if (PREF_ == Deterministic if (PREF_ == Deterministic
&& f && f
&& f->is_syntactic_recurrence() && f->is_syntactic_recurrence()
&& sim->number_of_acceptance_conditions() > 1) && sim->acc().num_sets() > 1)
tmpd = degeneralize_tba(sim); tmpd = degeneralize_tba(sim);
auto in = tmpd ? tmpd : sim; auto in = tmpd ? tmpd : sim;
@ -306,7 +306,7 @@ namespace spot
// because the input TBA might be smaller. // because the input TBA might be smaller.
if (state_based_) if (state_based_)
in = degeneralize(dba); in = degeneralize(dba);
else if (dba->number_of_acceptance_conditions() != 1) else if (dba->acc().num_sets() != 1)
in = degeneralize_tba(dba); in = degeneralize_tba(dba);
else else
in = dba; in = dba;
@ -354,8 +354,7 @@ namespace spot
// Degeneralize the dba resulting from tba-determinization or // Degeneralize the dba resulting from tba-determinization or
// sat-minimization (which is a TBA) if requested and needed. // sat-minimization (which is a TBA) if requested and needed.
if (dba && !dba_is_wdba && type_ == BA if (dba && !dba_is_wdba && type_ == BA
&& !(dba_is_minimal && state_based_ && !(dba_is_minimal && state_based_ && dba->acc().num_sets() == 1))
&& dba->number_of_acceptance_conditions() == 1))
dba = degeneralize(dba); dba = degeneralize(dba);
if (dba && sim) if (dba && sim)

View file

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

View file

@ -35,20 +35,12 @@ namespace spot
namespace namespace
{ {
std::string
acc(int n)
{
std::stringstream s;
s << n;
return "a" + s.str();
}
void void
random_labels(tgba_digraph_ptr aut, random_labels(tgba_digraph_ptr aut,
unsigned src, unsigned src,
unsigned dest, unsigned dest,
int* props, int props_n, float t, int* props, int props_n, float t,
const std::list<bdd>& accs, float a) unsigned n_accs, float a)
{ {
int val = 0; int val = 0;
int size = 0; int size = 0;
@ -70,21 +62,18 @@ namespace spot
if (size > 0) if (size > 0)
p &= bdd_ibuildcube(val, size, props); p &= bdd_ibuildcube(val, size, props);
bdd ac = bddfalse; acc_cond::mark_t m = 0U;
for (std::list<bdd>::const_iterator i = accs.begin(); for (unsigned i = 0U; i < n_accs; ++i)
i != accs.end(); ++i)
if (drand() < a) if (drand() < a)
ac |= *i; m |= aut->acc().mark(i);
aut->new_transition(src, dest, p, m);
aut->new_transition(src, dest, p, ac);
} }
} }
tgba_digraph_ptr tgba_digraph_ptr
random_graph(int n, float d, random_graph(int n, float d,
const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict, const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict,
int n_acc, float a, float t, unsigned n_accs, float a, float t)
ltl::environment* env)
{ {
assert(n > 0); assert(n > 0);
auto res = make_tgba_digraph(dict); auto res = make_tgba_digraph(dict);
@ -96,20 +85,7 @@ namespace spot
for (auto i: *ap) for (auto i: *ap)
props[pi++] = dict->register_proposition(i, res); props[pi++] = dict->register_proposition(i, res);
std::list<bdd> accs; res->set_acceptance_conditions(n_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));
// Using std::unordered_set instead of std::set for these sets is 3 // Using std::unordered_set instead of std::set for these sets is 3
// times slower (tested on a 50000 nodes example). // times slower (tested on a 50000 nodes example).
@ -162,7 +138,7 @@ namespace spot
std::advance(i, index); std::advance(i, index);
// Link it from src. // 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); nodes_to_process.insert(*i);
unreachable_nodes.erase(i); unreachable_nodes.erase(i);
break; break;
@ -178,7 +154,7 @@ namespace spot
state_randomizer[index] = state_randomizer[possibilities]; state_randomizer[index] = state_randomizer[possibilities];
state_randomizer[possibilities] = x; 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); auto j = unreachable_nodes.find(x);
if (j != unreachable_nodes.end()) 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. /// 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 ap The list of atomic property that should label the transition.
/// \param dict The bdd_dict to used for this automata. /// \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 /// If this number is non null, then there is no guarantee
/// that the generated graph contains an accepting cycle (raise /// that the generated graph contains an accepting cycle (raise
/// the value of \a a to improve the chances). /// the value of \a a to improve the chances).
@ -49,7 +49,6 @@ namespace spot
/// to an acceptance set. /// to an acceptance set.
/// \param t The probability (between 0.0 and 1.0) that an atomic proposition /// \param t The probability (between 0.0 and 1.0) that an atomic proposition
/// is true. /// 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 /// This algorithms is adapted from the one in Fig 6.2 page 48 of
/** \verbatim /** \verbatim
@ -79,8 +78,7 @@ namespace spot
SPOT_API tgba_digraph_ptr SPOT_API tgba_digraph_ptr
random_graph(int n, float d, random_graph(int n, float d,
const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict, const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict,
int n_acc = 0, float a = 0.1, float t = 0.5, unsigned n_accs = 0, float a = 0.1, float t = 0.5);
ltl::environment* env = &ltl::default_environment::instance());
} }
#endif // SPOT_TGBAALGOS_RANDOMGRAPH_HH #endif // SPOT_TGBAALGOS_RANDOMGRAPH_HH

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -29,8 +29,7 @@ namespace spot
typedef std::map<int, unsigned> accremap_t; typedef std::map<int, unsigned> accremap_t;
typedef std::vector<accremap_t> remap_table_t; typedef std::vector<accremap_t> remap_table_t;
typedef std::tuple<bool, bdd, bdd> filtered_trans; typedef std::tuple<bool, bdd, acc_cond::mark_t> filtered_trans;
typedef std::pair<bdd, bdd> acc_pair;
// SCC filters are objects with two methods: // SCC filters are objects with two methods:
@ -53,13 +52,13 @@ namespace spot
return true; 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 // 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}; return filtered_trans{true, cond, acc};
} }
@ -101,7 +100,7 @@ namespace spot
} }
filtered_trans trans(unsigned src, unsigned dst, filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc) bdd cond, acc_cond::mark_t acc)
{ {
bool keep; bool keep;
std::tie(keep, cond, acc) = std::tie(keep, cond, acc) =
@ -137,7 +136,7 @@ namespace spot
} }
filtered_trans trans(unsigned src, unsigned dst, filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc) bdd cond, acc_cond::mark_t acc)
{ {
bool keep; bool keep;
std::tie(keep, cond, acc) = std::tie(keep, cond, acc) =
@ -149,7 +148,7 @@ namespace spot
// If the transition is between two SCCs, or in a // If the transition is between two SCCs, or in a
// non-accepting SCC. Remove the acceptance sets. // non-accepting SCC. Remove the acceptance sets.
if (!this->si->is_accepting_scc(u) || u != this->si->scc_of(dst)) if (!this->si->is_accepting_scc(u) || u != this->si->scc_of(dst))
acc = bddfalse; acc = 0U;
} }
return filtered_trans(keep, cond, acc); return filtered_trans(keep, cond, acc);
@ -168,14 +167,14 @@ namespace spot
} }
filtered_trans trans(unsigned src, unsigned dst, filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc) bdd cond, acc_cond::mark_t acc)
{ {
bool keep; bool keep;
std::tie(keep, cond, acc) = std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc); this->next_filter::trans(src, dst, cond, acc);
if (!this->si->is_accepting_scc(this->si->scc_of(dst))) if (!this->si->is_accepting_scc(this->si->scc_of(dst)))
acc = bddfalse; acc = 0U;
return filtered_trans(keep, cond, acc); return filtered_trans(keep, cond, acc);
} }
}; };
@ -184,10 +183,8 @@ namespace spot
template <class next_filter = id_filter> template <class next_filter = id_filter>
struct acc_filter_simplify: next_filter struct acc_filter_simplify: next_filter
{ {
std::vector<bdd> acc_; // Acceptance sets to strip in each SCC.
typedef std::map<int, bdd> map_t; std::vector<acc_cond::mark_t> strip_;
typedef std::vector<map_t> remap_t;
remap_t remap_;
template<typename... Args> template<typename... Args>
acc_filter_simplify(scc_info* si, Args&&... 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(); unsigned scc_count = this->si->scc_count();
remap_table_t remap_table(scc_count); auto& acc = this->si->get_aut()->acc();
std::vector<unsigned> max_table(scc_count); assert(n == acc.num_sets());
std::vector<bdd> useful_table(scc_count); (void) n;
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 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) for (unsigned n = 0; n < scc_count; ++n)
{ {
if (!this->si->is_accepting_scc(n)) if (!this->si->is_accepting_scc(n))
continue; continue;
bdd all = used_acc[n]; strip_[n] = acc.useless(used_acc[n].begin(), used_acc[n].end());
cnt[n] = acc.num_sets() - strip_[n].count();
//std::cerr << "SCC #" << n << "; used = " << all << std::endl; if (cnt[n] > max)
max = cnt[n];
// 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;
}
// Now that we know about the max number of acceptance // Now that we know about the max number of acceptance
// conditions, add extra acceptance conditions to those SCC // conditions, add extra acceptance conditions to those SCC
// that do not have enough. // that do not have enough.
@ -314,118 +220,30 @@ namespace spot
{ {
if (!this->si->is_accepting_scc(n)) if (!this->si->is_accepting_scc(n))
continue; continue;
//std::cerr << "SCC " << n << '\n'; if (cnt[n] < max)
bdd useful = useful_table[n]; strip_[n].remove_some(max - cnt[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; return max;
// 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;
} }
acc_.resize(max_num); filtered_trans trans(unsigned src, unsigned dst, bdd cond,
acc_[0] = bddfalse; acc_cond::mark_t acc)
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};
}
filtered_trans trans(unsigned src, unsigned dst, bdd cond, bdd acc)
{ {
bool keep; bool keep;
std::tie(keep, cond, acc) = std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc); this->next_filter::trans(src, dst, cond, acc);
if (keep && acc != bddfalse) if (keep && acc)
{ {
unsigned u = this->si->scc_of(dst); unsigned u = this->si->scc_of(dst);
auto i = remap_[u].find(acc.id()); if (!this->si->is_accepting_scc(u))
if (i != remap_[u].end()) acc = 0U;
acc = i->second;
else else
acc = bddfalse; acc = this->si->get_aut()->acc().strip(acc, strip_[u]);
} }
return filtered_trans{keep, cond, acc}; return filtered_trans{keep, cond, acc};
} }
}; };
@ -456,11 +274,8 @@ namespace spot
else else
inout.push_back(-1U); inout.push_back(-1U);
{ filtered->
bdd all = aut->all_acceptance_conditions(); set_acceptance_conditions(filter.accsets(aut->acc().num_sets()));
bdd neg = aut->neg_acceptance_conditions();
filtered->set_acceptance_conditions(filter.accsets(all, neg).first);
}
filtered->new_states(out_n); filtered->new_states(out_n);
for (unsigned isrc = 0; isrc < in_n; ++isrc) for (unsigned isrc = 0; isrc < in_n; ++isrc)
{ {
@ -474,7 +289,7 @@ namespace spot
continue; continue;
bool want; bool want;
bdd cond; bdd cond;
bdd acc; acc_cond::mark_t acc;
std::tie(want, cond, acc) = std::tie(want, cond, acc) =
filter.trans(isrc, t.dst, t.cond, t.acc); filter.trans(isrc, t.dst, t.cond, t.acc);
if (want) if (want)

View file

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

View file

@ -45,17 +45,17 @@ namespace spot
struct scc_node struct scc_node
{ {
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) acc(acc), trivial(trivial)
{ {
} }
scc_succs succ; scc_succs succ;
bdd acc; acc_cond::mark_t acc;
std::list<unsigned> states; // States of the component std::list<unsigned> states; // States of the component
bool trivial:1; bool trivial:1;
bool accepting:1; bool accepting:1;
@ -114,7 +114,7 @@ namespace spot
return node(scc).trivial; return node(scc).trivial;
} }
bdd acc(unsigned scc) const acc_cond::mark_t acc(unsigned scc) const
{ {
return node(scc).acc; return node(scc).acc;
} }
@ -136,16 +136,7 @@ namespace spot
/// \brief Return the set of all used acceptance combinations, for /// \brief Return the set of all used acceptance combinations, for
/// each accepting SCC. /// each accepting SCC.
/// std::vector<std::set<acc_cond::mark_t>> used_acc() const;
/// 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;
std::vector<bool> weak_sccs() 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, se05_search(const const_tgba_ptr a, size_t size,
option_map o = option_map()) option_map o = option_map())
: emptiness_check(a, o), : emptiness_check(a, o),
h(size), h(size)
all_cond(a->all_acceptance_conditions())
{ {
assert(a->number_of_acceptance_conditions() <= 1); assert(a->acc().num_sets() <= 1);
} }
virtual ~se05_search() virtual ~se05_search()
@ -98,7 +97,7 @@ namespace spot
const state* s0 = a_->get_init_state(); const state* s0 = a_->get_init_state();
inc_states(); inc_states();
h.add_new_state(s0, CYAN); h.add_new_state(s0, CYAN);
push(st_blue, s0, bddfalse, bddfalse); push(st_blue, s0, bddfalse, 0U);
if (dfs_blue()) if (dfs_blue())
return std::make_shared<se05_result>(t, options()); return std::make_shared<se05_result>(t, options());
} }
@ -151,7 +150,7 @@ namespace spot
private: private:
void push(stack_type& st, const state* s, void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc) const bdd& label, acc_cond::mark_t acc)
{ {
inc_depth(); inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s); tgba_succ_iterator* i = a_->succ_iter(s);
@ -176,9 +175,6 @@ namespace spot
/// by the last dfs visiting it. /// by the last dfs visiting it.
heap h; heap h;
/// The unique acceptance condition of the automaton \a a.
bdd all_cond;
bool dfs_blue() bool dfs_blue()
{ {
while (!st_blue.empty()) while (!st_blue.empty())
@ -191,7 +187,7 @@ namespace spot
trace << " Visit the successor: " trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl; << a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition(); 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) // Go down the edge (f.s, <label, acc>, s_prime)
f.it->next(); f.it->next();
inc_transitions(); inc_transitions();
@ -203,8 +199,9 @@ namespace spot
h.add_new_state(s_prime, CYAN); h.add_new_state(s_prime, CYAN);
push(st_blue, s_prime, label, acc); push(st_blue, s_prime, label, acc);
} }
else if (c.get_color() == CYAN && (acc == all_cond || else if (c.get_color() == CYAN && (a_->acc().accepting(acc) ||
(f.s->compare(s_prime) != 0 && f.acc == all_cond))) (f.s->compare(s_prime) != 0
&& a_->acc().accepting(f.acc))))
{ {
trace << " It is cyan and acceptance condition " trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl; << "is reached, report cycle" << std::endl;
@ -212,7 +209,7 @@ namespace spot
push(st_red, s_prime, label, acc); push(st_red, s_prime, label, acc);
return true; 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 test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive // 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); typename heap::color_ref c = h.get_color_ref(f_dest.s);
assert(!c.is_white()); assert(!c.is_white());
if (!st_blue.empty() && 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 test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive // the number of runs reported by successive
@ -281,7 +278,7 @@ namespace spot
trace << " Visit the successor: " trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl; << a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition(); 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) // Go down the edge (f.s, <label, acc>, s_prime)
f.it->next(); f.it->next();
inc_transitions(); inc_transitions();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,96 +26,41 @@
namespace spot namespace spot
{ {
weight::weight_vector* weight::pm = 0; weight::weight(const acc_cond& acc):
m(acc.num_sets())
weight::weight(const bdd& neg_all_cond) : neg_all_acc(neg_all_cond)
{ {
} }
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) for (auto s: acc.sets(a))
if (varset[v] > 0) ++m[s];
{
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);
return *this; 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) for (auto s: acc.sets(a))
if (varset[v] > 0) if (m[s] > 0)
{ --m[s];
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);
return *this; 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(); unsigned max = acc.num_sets();
bdd res = bddfalse; std::vector<unsigned> res;
for (unsigned n = 0; n < max; ++n)
while (itw1 != m.end() && itw2 != w.m.end()) if (m[n] > w.m[n])
{ res.push_back(n);
assert(itw1->first <= itw2->first); return acc.marks(res.begin(), res.end());
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;
} }
std::ostream& operator<<(std::ostream& os, const weight& w) std::ostream& operator<<(std::ostream& os, const weight& w)
{ {
weight::weight_vector::const_iterator it; unsigned s = w.m.size();
for (it = w.m.begin(); it != w.m.end(); ++it) for (unsigned n = 0; n < s; ++n)
os << '(' << it->first << ',' << it->second << ')'; os << '(' << n << ',' << w.m[n] << ')';
return os; 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 // département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie. // et Marie Curie.
// //
@ -23,6 +23,7 @@
#include <iosfwd> #include <iosfwd>
#include <map> #include <map>
#include <bdd.h> #include <bdd.h>
#include "tgba/acc.hh"
namespace spot namespace spot
{ {
@ -33,29 +34,23 @@ namespace spot
{ {
public: public:
/// Construct a empty vector (all counters set to zero). /// Construct a empty vector (all counters set to zero).
/// weight(const acc_cond& acc);
/// \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);
/// Increment by one the counters of each acceptance condition in \a 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. /// 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 /// Return the set of each acceptance condition such that its counter is
/// strictly greatest than the corresponding counter in w. /// strictly greatest than the corresponding counter in w.
/// ///
/// \pre For each acceptance condition, its counter is greatest or equal to /// \pre For each acceptance condition, its counter is greatest or equal to
/// the corresponding counter in w. /// the corresponding counter in w.
bdd operator-(const weight& w) const; acc_cond::mark_t diff(const acc_cond& acc, const weight& w) const;
friend std::ostream& operator<<(std::ostream& os, const weight& w); friend std::ostream& operator<<(std::ostream& os,
const weight& w);
private: private:
typedef std::map<int, int> weight_vector; typedef std::vector<int> weight_vector;
weight_vector m; 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; int token;
std::string* str; std::string* str;
const spot::ltl::formula* f; const spot::ltl::formula* f;
bdd* acc; spot::acc_cond::mark_t acc;
} }
%code %code
@ -80,10 +80,9 @@ typedef std::pair<bool, spot::ltl::formula*> pair;
%token ACC_DEF %token ACC_DEF
%destructor { delete $$; } <str> %destructor { delete $$; } <str>
%destructor { delete $$; } <acc>
%printer { debug_stream() << *$$; } <str> %printer { debug_stream() << *$$; } <str>
%printer { debug_stream() << *$$; } <acc> %printer { debug_stream() << $$; } <acc>
%% %%
tgba: acceptance_decl lines tgba: acceptance_decl lines
@ -94,7 +93,8 @@ tgba: acceptance_decl lines
{ namer->new_state("0"); }; { namer->new_state("0"); };
acceptance_decl: ACC_DEF acc_decl ';' acceptance_decl: ACC_DEF acc_decl ';'
{ acc_map.commit(); } {
}
/* At least one line. */ /* At least one line. */
lines: line lines: line
@ -137,11 +137,10 @@ line: strident ',' strident ',' condition ',' acc_list ';'
} }
unsigned s = namer->new_state(*$1); unsigned s = namer->new_state(*$1);
unsigned d = namer->new_state(*$3); 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 $1;
delete $3; delete $3;
delete $5; delete $5;
delete $7;
} }
; ;
@ -166,7 +165,7 @@ condition:
acc_list: acc_list:
{ {
$$ = new bdd(bddfalse); $$ = 0U;
} }
| acc_list strident | acc_list strident
{ {
@ -180,7 +179,7 @@ acc_list:
// $2 will be destroyed on error recovery. // $2 will be destroyed on error recovery.
YYERROR; YYERROR;
} }
*$1 |= p.second; $1 |= p.second;
} }
delete $2; delete $2;
$$ = $1; $$ = $1;

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