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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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