Switch from "promises" to "accepting set". Fix the definitions

of these accepting set so that they are really usable.  Provide
a all_accepting_conditions() method for use in the emptyness
check, and a neg_accepting_conditions() for products.
Predeclare TGBA accepting conditions is the i/o.

* src/tgba/bddprint.cc (want_prom): Rename as ...
(want_prom): ... this.
(print_handler): Adjust to display Acc[].
(print_acc_handler, bdd_print_acc): New functions.
* src/tgba/bddprint.hh (print_acc_handler, bdd_print_acc):
New functions.
* src/tgba/succiter.hh (current_promise): Rename as ...
(current_accepting_conditions): ... this.
* src/tgba/succiterconcrete.cc (current_state):
Rename next to now.
(current_promise): Rename as ...
(current_accepting_conditions): ... this, and compute
the accepting conditions.
* src/tgba/dictunion.cc, src/tgba/ltl2tgba.cc,
src/tgba/succiterconcrete.hh,
src/tgba/tgbabddconcretefactory.cc,
src/tgba/tgbabddcoredata.cc, src/tgba/tgbabddcoredata.hh,
src/tgba/tgbabdddict.hh, src/tgba/tgbabdddict.cc,
src/tgba/tgbabddtranslatefactory.cc,
src/tgbaalgos/dotty.cc: Adjust to new names.
* src/tgba/tgba.hh (all_accepting_conditions,
neg_accepting_conditions): New functions.
* src/tgba/tgbabddconcretefactory.cc: Adjust to new
names, and record accepting conditions instead of promises.
* src/tgba/tgbabddcoredata.hh (accepting_conditions,
all_accepting_conditions, negacc_set): New variables.
(notnow_set, notprom_set, declare_promise): Rename as ...
(notnext_set, notacc_set, declare_accepting_condition): ... these.
* src/tgba/tgbaexplicit.hh
(tgba_explicit_succ_iterator::current_promise): Rename as ...
(tgba_explicit_succ_iterator::current_accepting_conditions): ... this.
(tgba_explicit::add_promise): Rename as ...
(tgba_explicit::add_accepting_condition): ... this.
(tgba_explicit::declare_accepting_condition,
tgba_explicit::has_accepting_condition): New variables.
(tgba_explicit::get_promise): Rename as ...
(tgba_explicit::get_accepting_condition): ... this.
(tgba_explicit::all_accepting_conditions,
tgba_explicit::neg_accepting_conditions): Implement them.
(all_accepting_conditions, neg_accepting_conditions,
all_accepting_conditions): New variables.
(tgba_explicit_succ_iterator): Embed all_accepting_conditions_.
* src/tgba/tgbaexplicit.cc: Likewise.
* src/tgba/tgbaproduct.hh
(tgba_product_succ_uterator): Embed left_neg_ and right_neg_.
(tgba_product::all_accepting_conditions,
tgba_product::neg_accepting_conditions): Implement them.
* src/tgba/tgbatranslateproxy.hh:
(tgba_translate_proxy::all_accepting_conditions,
tgba_translate_proxy::neg_accepting_conditions): Implement them.
* src/tgba/tgbatranslateproxy.cc: Likewise.
* src/tgbaalgos/save.cc (save_rec): Call bdd_print
(tgba_save_reachable): Output the `acc =' line.
* src/tgbaparse/tgbaparse.yy: Support the for
accepting conditions definitions using an "acc =" line
at the start.  Later, use has_accepting_condition while
parsing	accepting conditions to ensure they were declared.
Disallow !cond in accepting conditions.
* src/tgbaparse/tgbascan.ll (ACC_DEF): New token.
* src/tgbatest/explicit.cc (main): Declare accepting conditions.
* src/tgbatest/ltl2tgba.cc (main): Add support for the -a, -A,
and -R new options.
* src/tgbatest/tgbaread.cc (main): Really exit on parse error.
* src/tgbatest/explicit.test, src/tgbatest/explprod.test,
src/tgbatest/mixprod.test, src/tgbatest/readsave.test,
src/tgbatest/tgbaread.test, src/tgbatest/tripprod.test: Reflect
recent changes.
This commit is contained in:
Alexandre Duret-Lutz 2003-06-23 17:28:26 +00:00
parent fbbfda43f2
commit 25e6cca4b4
37 changed files with 662 additions and 220 deletions

View file

@ -1,3 +1,79 @@
2003-06-23 Alexandre Duret-Lutz <aduret@src.lip6.fr>
Switch from "promises" to "accepting set". Fix the definitions
of these accepting set so that they are really usable. Provide
a all_accepting_conditions() method for use in the emptyness
check, and a neg_accepting_conditions() for products.
Predeclare TGBA accepting conditions is the i/o.
* src/tgba/bddprint.cc (want_prom): Rename as ...
(want_prom): ... this.
(print_handler): Adjust to display Acc[].
(print_acc_handler, bdd_print_acc): New functions.
* src/tgba/bddprint.hh (print_acc_handler, bdd_print_acc):
New functions.
* src/tgba/succiter.hh (current_promise): Rename as ...
(current_accepting_conditions): ... this.
* src/tgba/succiterconcrete.cc (current_state):
Rename next to now.
(current_promise): Rename as ...
(current_accepting_conditions): ... this, and compute
the accepting conditions.
* src/tgba/dictunion.cc, src/tgba/ltl2tgba.cc,
src/tgba/succiterconcrete.hh,
src/tgba/tgbabddconcretefactory.cc,
src/tgba/tgbabddcoredata.cc, src/tgba/tgbabddcoredata.hh,
src/tgba/tgbabdddict.hh, src/tgba/tgbabdddict.cc,
src/tgba/tgbabddtranslatefactory.cc,
src/tgbaalgos/dotty.cc: Adjust to new names.
* src/tgba/tgba.hh (all_accepting_conditions,
neg_accepting_conditions): New functions.
* src/tgba/tgbabddconcretefactory.cc: Adjust to new
names, and record accepting conditions instead of promises.
* src/tgba/tgbabddcoredata.hh (accepting_conditions,
all_accepting_conditions, negacc_set): New variables.
(notnow_set, notprom_set, declare_promise): Rename as ...
(notnext_set, notacc_set, declare_accepting_condition): ... these.
* src/tgba/tgbaexplicit.hh
(tgba_explicit_succ_iterator::current_promise): Rename as ...
(tgba_explicit_succ_iterator::current_accepting_conditions): ... this.
(tgba_explicit::add_promise): Rename as ...
(tgba_explicit::add_accepting_condition): ... this.
(tgba_explicit::declare_accepting_condition,
tgba_explicit::has_accepting_condition): New variables.
(tgba_explicit::get_promise): Rename as ...
(tgba_explicit::get_accepting_condition): ... this.
(tgba_explicit::all_accepting_conditions,
tgba_explicit::neg_accepting_conditions): Implement them.
(all_accepting_conditions, neg_accepting_conditions,
all_accepting_conditions): New variables.
(tgba_explicit_succ_iterator): Embed all_accepting_conditions_.
* src/tgba/tgbaexplicit.cc: Likewise.
* src/tgba/tgbaproduct.hh
(tgba_product_succ_uterator): Embed left_neg_ and right_neg_.
(tgba_product::all_accepting_conditions,
tgba_product::neg_accepting_conditions): Implement them.
* src/tgba/tgbatranslateproxy.hh:
(tgba_translate_proxy::all_accepting_conditions,
tgba_translate_proxy::neg_accepting_conditions): Implement them.
* src/tgba/tgbatranslateproxy.cc: Likewise.
* src/tgbaalgos/save.cc (save_rec): Call bdd_print
(tgba_save_reachable): Output the `acc =' line.
* src/tgbaparse/tgbaparse.yy: Support the for
accepting conditions definitions using an "acc =" line
at the start. Later, use has_accepting_condition while
parsing accepting conditions to ensure they were declared.
Disallow !cond in accepting conditions.
* src/tgbaparse/tgbascan.ll (ACC_DEF): New token.
* src/tgbatest/explicit.cc (main): Declare accepting conditions.
* src/tgbatest/ltl2tgba.cc (main): Add support for the -a, -A,
and -R new options.
* src/tgbatest/tgbaread.cc (main): Really exit on parse error.
* src/tgbatest/explicit.test, src/tgbatest/explprod.test,
src/tgbatest/mixprod.test, src/tgbatest/readsave.test,
src/tgbatest/tgbaread.test, src/tgbatest/tripprod.test: Reflect
recent changes.
2003-06-22 Alexandre Duret-Lutz <aduret@src.lip6.fr> 2003-06-22 Alexandre Duret-Lutz <aduret@src.lip6.fr>
* src/tgbatest/tripprod.test, src/tgbatest/explprod.test: * src/tgbatest/tripprod.test, src/tgbatest/explprod.test:

View file

@ -8,8 +8,8 @@ namespace spot
/// Global dictionary used by print_handler() to lookup variables. /// Global dictionary used by print_handler() to lookup variables.
static const tgba_bdd_dict* dict; static const tgba_bdd_dict* dict;
/// Global flag to enable Prom[x] output (instead of `x'). /// Global flag to enable Acc[x] output (instead of `x').
static bool want_prom; static bool want_acc;
/// Stream handler used by Buddy to display BDD variables. /// Stream handler used by Buddy to display BDD variables.
static void static void
@ -21,12 +21,12 @@ namespace spot
to_string(isi->second, o); to_string(isi->second, o);
else else
{ {
isi = dict->prom_formula_map.find(var); isi = dict->acc_formula_map.find(var);
if (isi != dict->prom_formula_map.end()) if (isi != dict->acc_formula_map.end())
{ {
if (want_prom) if (want_acc)
{ {
o << "Prom["; o << "Acc[";
to_string(isi->second, o) << "]"; to_string(isi->second, o) << "]";
} }
else else
@ -83,12 +83,37 @@ namespace spot
{ {
dict = &d; dict = &d;
where = &os; where = &os;
want_prom = false; want_acc = false;
assert(bdd_satone(b) == b); assert(bdd_satone(b) == b);
bdd_allsat(b, print_sat_handler); bdd_allsat(b, print_sat_handler);
return os; return os;
} }
static void
print_acc_handler(char* varset, int size)
{
for (int v = 0; v < size; ++v)
{
if (varset[v] < 0)
continue;
if (varset[v] > 0)
{
*where << " ";
print_handler(*where, v);
}
}
}
std::ostream&
bdd_print_acc(std::ostream& os, const tgba_bdd_dict& d, bdd b)
{
dict = &d;
where = &os;
want_acc = false;
bdd_allsat(b, print_acc_handler);
return os;
}
std::string std::string
bdd_format_sat(const tgba_bdd_dict& d, bdd b) bdd_format_sat(const tgba_bdd_dict& d, bdd b)
{ {
@ -101,7 +126,7 @@ namespace spot
bdd_print_set(std::ostream& os, const tgba_bdd_dict& d, bdd b) bdd_print_set(std::ostream& os, const tgba_bdd_dict& d, bdd b)
{ {
dict = &d; dict = &d;
want_prom = true; want_acc = true;
bdd_strm_hook(print_handler); bdd_strm_hook(print_handler);
os << bddset << b; os << bddset << b;
bdd_strm_hook(0); bdd_strm_hook(0);
@ -120,7 +145,7 @@ namespace spot
bdd_print_dot(std::ostream& os, const tgba_bdd_dict& d, bdd b) bdd_print_dot(std::ostream& os, const tgba_bdd_dict& d, bdd b)
{ {
dict = &d; dict = &d;
want_prom = true; want_acc = true;
bdd_strm_hook(print_handler); bdd_strm_hook(print_handler);
os << bdddot << b; os << bdddot << b;
bdd_strm_hook(0); bdd_strm_hook(0);
@ -131,7 +156,7 @@ namespace spot
bdd_print_table(std::ostream& os, const tgba_bdd_dict& d, bdd b) bdd_print_table(std::ostream& os, const tgba_bdd_dict& d, bdd b)
{ {
dict = &d; dict = &d;
want_prom = true; want_acc = true;
bdd_strm_hook(print_handler); bdd_strm_hook(print_handler);
os << bddtable << b; os << bddtable << b;
bdd_strm_hook(0); bdd_strm_hook(0);

View file

@ -26,6 +26,14 @@ namespace spot
/// \return The BDD formated as a string. /// \return The BDD formated as a string.
std::string bdd_format_sat(const tgba_bdd_dict& dict, bdd b); std::string bdd_format_sat(const tgba_bdd_dict& dict, bdd b);
/// \brief Print a BDD as a list of accepting conditions.
///
/// This is used when saving a TGBA.
/// \param b The BDD to print.
/// \return The BDD formated as a string.
std::ostream& bdd_print_acc(std::ostream& os,
const tgba_bdd_dict& dict, bdd b);
/// \brief Print a BDD as a set. /// \brief Print a BDD as a set.
/// \param os The output stream. /// \param os The output stream.
/// \param dict The dictionary to use, to lookup variables. /// \param dict The dictionary to use, to lookup variables.

View file

@ -29,9 +29,9 @@ namespace spot
var.insert(i->first); var.insert(i->first);
// Merge promises. // Merge promises.
for (i = l.prom_map.begin(); i != l.prom_map.end(); ++i) for (i = l.acc_map.begin(); i != l.acc_map.end(); ++i)
prom.insert(i->first); prom.insert(i->first);
for (i = r.prom_map.begin(); i != r.prom_map.end(); ++i) for (i = r.acc_map.begin(); i != r.acc_map.end(); ++i)
prom.insert(i->first); prom.insert(i->first);
// Ensure we have enough BDD variables. // Ensure we have enough BDD variables.
@ -54,8 +54,8 @@ namespace spot
for (f = prom.begin(); f != prom.end(); ++f) for (f = prom.begin(); f != prom.end(); ++f)
{ {
clone(*f); clone(*f);
res.prom_map[*f] = v; res.acc_map[*f] = v;
res.prom_formula_map[v] = *f; res.acc_formula_map[v] = *f;
++v; ++v;
} }
for (f = var.begin(); f != var.end(); ++f) for (f = var.begin(); f != var.end(); ++f)

View file

@ -73,12 +73,13 @@ namespace spot
fact_.add_relation(bdd_apply(now, x | next, bddop_biimp)); fact_.add_relation(bdd_apply(now, x | next, bddop_biimp));
/* /*
`x | next', doesn't actually encode the fact that x `x | next', doesn't actually encode the fact that x
should be fulfilled at eventually. So we declare any should be fulfilled at eventually. We ensure
transition going to NEXT without checking X as this by creating a new generalized Büchi accepting set,
"promising x". This promises will be checked by during Acc[x], and leave any transition going to NEXT without
the emptiness check. checking X out of this set. Such accepting conditions
are checked for during the emptiness check.
*/ */
fact_.declare_promise(next & !x, node->child()); fact_.declare_accepting_condition(x | !next, node->child());
res_ = now; res_ = now;
return; return;
} }
@ -145,10 +146,10 @@ namespace spot
/* /*
The rightmost conjunction, f1 & next, doesn't actually The rightmost conjunction, f1 & next, doesn't actually
encode the fact that f2 should be fulfilled eventually. encode the fact that f2 should be fulfilled eventually.
We declare a promise for this purpose (see the comment We declare an accepting condition for this purpose (see
in the unop::F case). the comment in the unop::F case).
*/ */
fact_.declare_promise(next & !f2, node->second()); fact_.declare_accepting_condition(f2 | !next, node->second());
res_ = now; res_ = now;
return; return;
} }

View file

@ -68,8 +68,9 @@ namespace spot
virtual state* current_state() = 0; virtual state* current_state() = 0;
/// \brief Get the condition on the transition leading to this successor. /// \brief Get the condition on the transition leading to this successor.
virtual bdd current_condition() = 0; virtual bdd current_condition() = 0;
/// \brief Get the promise on the transition leading to this successor. /// \brief Get the accepting conditions on the transition leading
virtual bdd current_promise() = 0; /// to this successor.
virtual bdd current_accepting_conditions() = 0;
//@} //@}
}; };

View file

@ -45,7 +45,9 @@ namespace spot
tgba_succ_iterator_concrete::current_state() tgba_succ_iterator_concrete::current_state()
{ {
assert(!done()); assert(!done());
return new state_bdd(bdd_exist(current_, data_.notnow_set));
return new state_bdd(bdd_replace(bdd_exist(current_, data_.notnext_set),
data_.next_to_now));
} }
bdd bdd
@ -56,10 +58,11 @@ namespace spot
} }
bdd bdd
tgba_succ_iterator_concrete::current_promise() tgba_succ_iterator_concrete::current_accepting_conditions()
{ {
assert(!done()); assert(!done());
return bdd_exist(current_, data_.notprom_set); return bdd_exist(bdd_restrict(data_.accepting_conditions, current_),
data_.notacc_set);
} }
} }

View file

@ -30,7 +30,7 @@ namespace spot
// inspection // inspection
state_bdd* current_state(); state_bdd* current_state();
bdd current_condition(); bdd current_condition();
bdd current_promise(); bdd current_accepting_conditions();
private: private:
const tgba_bdd_core_data& data_; ///< Core data of the automata. const tgba_bdd_core_data& data_; ///< Core data of the automata.

View file

@ -77,6 +77,28 @@ namespace spot
/// This formating is the responsability of the automata /// This formating is the responsability of the automata
/// who owns the state. /// who owns the state.
virtual std::string format_state(const state* state) const = 0; virtual std::string format_state(const state* state) const = 0;
/// \brief Return the set of all accepting 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_accepting_conditions() const = 0;
/// \brief Return the conjuction of all negated accepting
/// variables.
///
/// For instance if the automaton uses variables \c Acc[a],
/// \c Acc[b] and \c Acc[c] to describe accepting sets,
/// this function should return \c !Acc[a]\&!Acc[b]\&!Acc[c].
///
/// This is useful when making products: each operand conditions
/// set should be augmented with the neg_accepting_conditions() of
/// the other operand.
virtual bdd neg_accepting_conditions() const = 0;
}; };
} }

View file

@ -41,9 +41,7 @@ namespace spot
{ {
const state_bdd* s = dynamic_cast<const state_bdd*>(state); const state_bdd* s = dynamic_cast<const state_bdd*>(state);
assert(s); assert(s);
bdd succ_set = bdd_replace(bdd_exist(data_.relation & s->as_bdd(), bdd succ_set = bdd_exist(data_.relation & s->as_bdd(), data_.now_set);
data_.now_set),
data_.next_to_now);
return new tgba_succ_iterator_concrete(data_, succ_set); return new tgba_succ_iterator_concrete(data_, succ_set);
} }
@ -61,6 +59,18 @@ namespace spot
return dict_; return dict_;
} }
bdd
tgba_bdd_concrete::all_accepting_conditions() const
{
return data_.all_accepting_conditions;
}
bdd
tgba_bdd_concrete::neg_accepting_conditions() const
{
return data_.negacc_set;
}
const tgba_bdd_core_data& const tgba_bdd_core_data&
tgba_bdd_concrete::get_core_data() const tgba_bdd_concrete::get_core_data() const
{ {

View file

@ -52,6 +52,9 @@ namespace spot
/// rules, etc. /// rules, etc.
const tgba_bdd_core_data& get_core_data() const; const tgba_bdd_core_data& get_core_data() const;
virtual bdd all_accepting_conditions() const;
virtual bdd neg_accepting_conditions() const;
protected: protected:
tgba_bdd_core_data data_; ///< Core data associated to the automaton. tgba_bdd_core_data data_; ///< Core data associated to the automaton.
tgba_bdd_dict dict_; ///< Dictionary used by the automaton. tgba_bdd_dict dict_; ///< Dictionary used by the automaton.

View file

@ -1,14 +1,13 @@
#include "ltlvisit/clone.hh" #include "ltlvisit/clone.hh"
#include "ltlvisit/destroy.hh" #include "ltlvisit/destroy.hh"
#include "tgbabddconcretefactory.hh" #include "tgbabddconcretefactory.hh"
namespace spot namespace spot
{ {
tgba_bdd_concrete_factory::~tgba_bdd_concrete_factory() tgba_bdd_concrete_factory::~tgba_bdd_concrete_factory()
{ {
promise_map_::iterator pi; acc_map_::iterator ai;
for (pi = prom_.begin(); pi != prom_.end(); ++pi) for (ai = acc_.begin(); ai != acc_.end(); ++ai)
destroy(pi->first); destroy(ai->first);
} }
int int
@ -56,43 +55,50 @@ namespace spot
} }
void void
tgba_bdd_concrete_factory::declare_promise(bdd b, tgba_bdd_concrete_factory::declare_accepting_condition(bdd b,
const ltl::formula* p) const ltl::formula* a)
{ {
// Maintain a disjunction of BDDs associated to P. // Maintain a conjunction of BDDs associated to A. We will latter
// We will latter (in tgba_bdd_concrete_factory::finish()) // (in tgba_bdd_concrete_factory::finish()) associate this
// record this disjunction as equivalant to P. // conjunction to A.
promise_map_::iterator pi = prom_.find(p); acc_map_::iterator ai = acc_.find(a);
if (pi == prom_.end()) if (ai == acc_.end())
{ {
p = clone(p); a = clone(a);
prom_[p] = b; acc_[a] = b;
} }
else else
{ {
pi->second |= b; ai->second &= b;
} }
} }
void void
tgba_bdd_concrete_factory::finish() tgba_bdd_concrete_factory::finish()
{ {
promise_map_::iterator pi; acc_map_::iterator ai;
for (pi = prom_.begin(); pi != prom_.end(); ++pi) for (ai = acc_.begin(); ai != acc_.end(); ++ai)
{ {
// Register a BDD variable for this promise. // Register a BDD variable for this accepting condition.
int p = create_node(); int a = create_node();
const ltl::formula* f = clone(pi->first); // The promised formula. const ltl::formula* f = clone(ai->first); // The associated formula.
dict_.prom_map[f] = p; dict_.acc_map[f] = a;
dict_.prom_formula_map[p] = f; dict_.acc_formula_map[a] = f;
bdd acc = ithvar(a);
// Keep track of all accepting conditions for easy
// existential quantification.
data_.declare_accepting_condition(acc);
}
for (ai = acc_.begin(); ai != acc_.end(); ++ai)
{
bdd acc = ithvar(dict_.acc_map[ai->first]);
bdd prom = ithvar(p); // Complete acc with all the other accepting conditions negated.
// Keep track of all promises for easy existential quantification. acc &= bdd_exist(data_.negacc_set, acc);
data_.declare_promise(prom);
// The promise P must hold if we have to verify any of the // Any state matching the BDD formulae registered is part
// (BDD) formulae registered. // of this accepting set.
add_relation(bdd_apply(prom, pi->second, bddop_biimp)); data_.accepting_conditions |= ai->second & acc;
} }
} }

View file

@ -34,17 +34,18 @@ namespace spot
/// can be turned into BDD using ithvar(). /// can be turned into BDD using ithvar().
int create_atomic_prop(const ltl::formula* f); int create_atomic_prop(const ltl::formula* f);
/// Declare a promise. /// Declare an accepting condition.
///
/// \param b that BDD of the expression that makes a promise
/// \param p the formula promised
/// ///
/// Formula such as 'f U g' or 'F g' make the promise /// Formula such as 'f U g' or 'F g' make the promise
/// that 'g' will be fulfilled eventually. So once /// that 'g' will be fulfilled eventually. So once
/// one of this formula has been translated into a BDD, /// one of this formula has been translated into a BDD,
/// we use declare_promise() to associate the promise 'g' /// we use declare_accepting_condition() to associate
/// to this BDD. /// all other states to the accepting set of 'g'.
void declare_promise(bdd b, const ltl::formula* p); ///
/// \param b a BDD indicating which variables are in the
/// accepting set
/// \param a the formula associated
void declare_accepting_condition(bdd b, const ltl::formula* a);
const tgba_bdd_core_data& get_core_data() const; const tgba_bdd_core_data& get_core_data() const;
const tgba_bdd_dict& get_dict() const; const tgba_bdd_dict& get_dict() const;
@ -63,8 +64,8 @@ namespace spot
tgba_bdd_core_data data_; ///< Core data for the new automata. tgba_bdd_core_data data_; ///< Core data for the new automata.
tgba_bdd_dict dict_; ///< Dictionary for the new automata. tgba_bdd_dict dict_; ///< Dictionary for the new automata.
typedef std::map<const ltl::formula*, bdd> promise_map_; typedef std::map<const ltl::formula*, bdd> acc_map_;
promise_map_ prom_; ///< BDD associated to each promises acc_map_ acc_; ///< BDD associated to each accepting condition
}; };
} }

View file

@ -3,17 +3,18 @@
namespace spot namespace spot
{ {
tgba_bdd_core_data::tgba_bdd_core_data() tgba_bdd_core_data::tgba_bdd_core_data()
: relation(bddtrue), : relation(bddtrue), accepting_conditions(bddfalse),
now_set(bddtrue), negnow_set(bddtrue), notnow_set(bddtrue), now_set(bddtrue), negnow_set(bddtrue), notnext_set(bddtrue),
notvar_set(bddtrue), notprom_set(bddtrue), next_to_now(bdd_newpair()) notvar_set(bddtrue), notacc_set(bddtrue), negacc_set(bddtrue),
next_to_now(bdd_newpair())
{ {
} }
tgba_bdd_core_data::tgba_bdd_core_data(const tgba_bdd_core_data& copy) tgba_bdd_core_data::tgba_bdd_core_data(const tgba_bdd_core_data& copy)
: relation(copy.relation), : relation(copy.relation), accepting_conditions(copy.accepting_conditions),
now_set(copy.now_set), negnow_set(copy.negnow_set), now_set(copy.now_set), negnow_set(copy.negnow_set),
notnow_set(copy.notnow_set), notvar_set(copy.notvar_set), notnext_set(copy.notnext_set), notvar_set(copy.notvar_set),
notprom_set(copy.notprom_set), notacc_set(copy.notacc_set), negacc_set(copy.negacc_set),
next_to_now(bdd_copypair(copy.next_to_now)) next_to_now(bdd_copypair(copy.next_to_now))
{ {
} }
@ -22,11 +23,14 @@ namespace spot
tgba_bdd_core_data::tgba_bdd_core_data(const tgba_bdd_core_data& left, tgba_bdd_core_data::tgba_bdd_core_data(const tgba_bdd_core_data& left,
const tgba_bdd_core_data& right) const tgba_bdd_core_data& right)
: relation(left.relation & right.relation), : relation(left.relation & right.relation),
accepting_conditions(left.accepting_conditions
| right.accepting_conditions),
now_set(left.now_set & right.now_set), now_set(left.now_set & right.now_set),
negnow_set(left.negnow_set & right.negnow_set), negnow_set(left.negnow_set & right.negnow_set),
notnow_set(left.notnow_set & right.notnow_set), notnext_set(left.notnext_set & right.notnext_set),
notvar_set(left.notvar_set & right.notvar_set), notvar_set(left.notvar_set & right.notvar_set),
notprom_set(left.notprom_set & right.notprom_set), notacc_set(left.notacc_set & right.notacc_set),
negacc_set(left.negacc_set & right.negacc_set),
next_to_now(bdd_mergepairs(left.next_to_now, right.next_to_now)) next_to_now(bdd_mergepairs(left.next_to_now, right.next_to_now))
{ {
} }
@ -52,23 +56,24 @@ namespace spot
{ {
now_set &= now; now_set &= now;
negnow_set &= !now; negnow_set &= !now;
notnow_set &= next; notnext_set &= now;
bdd both = now & next; bdd both = now & next;
notvar_set &= both; notvar_set &= both;
notprom_set &= both; notacc_set &= both;
} }
void void
tgba_bdd_core_data::declare_atomic_prop(bdd var) tgba_bdd_core_data::declare_atomic_prop(bdd var)
{ {
notnow_set &= var; notnext_set &= var;
notprom_set &= var; notacc_set &= var;
} }
void void
tgba_bdd_core_data::declare_promise(bdd prom) tgba_bdd_core_data::declare_accepting_condition(bdd acc)
{ {
notnow_set &= prom; notnext_set &= acc;
notvar_set &= prom; notvar_set &= acc;
negacc_set &= !acc;
} }
} }

View file

@ -10,28 +10,72 @@ namespace spot
{ {
/// \brief encodes the transition relation of the TGBA. /// \brief encodes the transition relation of the TGBA.
/// ///
/// \c relation uses four kinds of variables: /// \c relation uses three kinds of variables:
/// \li "Now" variables, that encode the current state /// \li "Now" variables, that encode the current state
/// \li "Next" variables, that encode the destination state /// \li "Next" variables, that encode the destination state
/// \li atomic propositions, which are things to verify before going on /// \li atomic propositions, which are things to verify before going on
/// to the next state /// to the next state
/// \li promises: \c a \c U \c b, or \c F \c b, both imply that \c b
/// should be verified eventually. We encode this with \c Prom[b],
/// and check that promises are fullfilled in the emptyness check.
bdd relation; bdd relation;
/// \brief encodes the accepting conditions
///
/// \c a \c U \c b, or \c F \c b, both imply that \c b
/// should be verified eventually. We encode this with generalized
/// Büchi acceptating conditions. An accepting set, called Acc[b],
/// hold all the state that do not promise to verify \c b eventually.
/// (I.e., all the states that contain \c b, or do not conatain
/// \c a \c U \c b, or \c F \c b.)
///
/// The spot::succ_iter::current_accepting_conditions() method
/// will return the Acc[x] variables of the accepting sets
/// in which a transition is. Actually we never return Acc[x]
/// alone, but Acc[x] and all other accepting variables negated.
///
/// So if there is three accepting set \c a, \c b, and \c c, and
/// a transition is in set \c a, we'll return \c Acc[a]&!Acc[b]&!Acc[c].
/// If the transition is in both \c a and \c b, we'll return
/// \c (Acc[a]\&!Acc[b]\&!Acc[c]) \c | \c (!Acc[a]\&Acc[b]\&!Acc[c]).
///
/// Accepting conditions are attributed to transitions and are
/// only concerned by atomic propositions (which label the
/// transitions) and Next variables (the destination). Typically,
/// a transition should bear the variable Acc[b] if it doesn't
/// check for `b' and have a destination of the form \c a \c U \c
/// b, or \c F \c b.
///
/// To summarize, \c accepting_conditions contains three kinds of
/// variables:
/// \li "Next" variables, that encode the destination state,
/// \li atomic propositions, which are things to verify before going on
/// to the next state,
/// \li promise variables.
bdd accepting_conditions;
/// The set of all accepting conditions used by the 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_accepting_conditions;
/// The conjunction of all Now variables, in their positive form. /// The conjunction of all Now variables, in their positive form.
bdd now_set; bdd now_set;
/// The conjunction of all Now variables, in their negated form. /// The conjunction of all Now variables, in their negated form.
bdd negnow_set; bdd negnow_set;
/// \brief The (positive) conjunction of all variables which are /// \brief The (positive) conjunction of all variables which are
/// not Now variables. /// not Next variables.
bdd notnow_set; bdd notnext_set;
/// \brief The (positive) conjunction of all variables which are /// \brief The (positive) conjunction of all variables which are
/// not atomic propositions. /// not atomic propositions.
bdd notvar_set; bdd notvar_set;
/// The (positive) conjunction of all variables which are not promises. /// The (positive) conjunction of all variables which are not
bdd notprom_set; /// accepting conditions.
bdd notacc_set;
/// The negative conjunction of all variables which are accepting
/// conditions.
bdd negacc_set;
/// Record pairings between Next and Now variables. /// Record pairings between Next and Now variables.
bddPair* next_to_now; bddPair* next_to_now;
@ -60,8 +104,9 @@ namespace spot
/// \brief Update the variable sets to take a new automic proposition into /// \brief Update the variable sets to take a new automic proposition into
/// account. /// account.
void declare_atomic_prop(bdd var); void declare_atomic_prop(bdd var);
/// Update the variable sets to take a new promise into account. /// \brief Update the variable sets to take a new accepting condition
void declare_promise(bdd prom); /// into account.
void declare_accepting_condition(bdd prom);
}; };
} }

View file

@ -23,8 +23,8 @@ namespace spot
os << " " << sii->second + 1 << ": Next["; os << " " << sii->second + 1 << ": Next[";
to_string(sii->first, os) << "]" << std::endl; to_string(sii->first, os) << "]" << std::endl;
} }
os << "Promises:" << std::endl; os << "Accepting Conditions:" << std::endl;
for (sii = prom_map.begin(); sii != prom_map.end(); ++sii) for (sii = acc_map.begin(); sii != acc_map.end(); ++sii)
{ {
os << " " << sii->second << ": "; os << " " << sii->second << ": ";
to_string(sii->first, os) << std::endl; to_string(sii->first, os) << std::endl;
@ -48,10 +48,10 @@ namespace spot
if (i2 == now_map.end() || i->second != i2->second) if (i2 == now_map.end() || i->second != i2->second)
return false; return false;
} }
for (i = other.prom_map.begin(); i != other.prom_map.end(); ++i) for (i = other.acc_map.begin(); i != other.acc_map.end(); ++i)
{ {
fv_map::const_iterator i2 = prom_map.find(i->first); fv_map::const_iterator i2 = acc_map.find(i->first);
if (i2 == prom_map.end() || i->second != i2->second) if (i2 == acc_map.end() || i->second != i2->second)
return false; return false;
} }
return true; return true;
@ -66,15 +66,15 @@ namespace spot
now_formula_map(other.now_formula_map), now_formula_map(other.now_formula_map),
var_map(other.var_map), var_map(other.var_map),
var_formula_map(other.var_formula_map), var_formula_map(other.var_formula_map),
prom_map(other.prom_map), acc_map(other.acc_map),
prom_formula_map(other.prom_formula_map) acc_formula_map(other.acc_formula_map)
{ {
fv_map::iterator i; fv_map::iterator i;
for (i = now_map.begin(); i != now_map.end(); ++i) for (i = now_map.begin(); i != now_map.end(); ++i)
ltl::clone(i->first); ltl::clone(i->first);
for (i = var_map.begin(); i != var_map.end(); ++i) for (i = var_map.begin(); i != var_map.end(); ++i)
ltl::clone(i->first); ltl::clone(i->first);
for (i = prom_map.begin(); i != prom_map.end(); ++i) for (i = acc_map.begin(); i != acc_map.end(); ++i)
ltl::clone(i->first); ltl::clone(i->first);
} }
@ -96,7 +96,7 @@ namespace spot
ltl::destroy(i->first); ltl::destroy(i->first);
for (i = var_map.begin(); i != var_map.end(); ++i) for (i = var_map.begin(); i != var_map.end(); ++i)
ltl::destroy(i->first); ltl::destroy(i->first);
for (i = prom_map.begin(); i != prom_map.end(); ++i) for (i = acc_map.begin(); i != acc_map.end(); ++i)
ltl::destroy(i->first); ltl::destroy(i->first);
} }

View file

@ -16,12 +16,12 @@ namespace spot
/// BDD-variable-to-formula maps. /// BDD-variable-to-formula maps.
typedef std::map<int, const ltl::formula*> vf_map; typedef std::map<int, const ltl::formula*> vf_map;
fv_map now_map; ///< Maps formulae to "Now" BDD variables. fv_map now_map; ///< Maps formulae to "Now" BDD variables
vf_map now_formula_map; ///< Maps "Now" BDD variables to formulae. vf_map now_formula_map; ///< Maps "Now" BDD variables to formulae
fv_map var_map; ///< Maps atomic propisitions to BDD variables fv_map var_map; ///< Maps atomic propisitions to BDD variables
vf_map var_formula_map; ///< Maps BDD variables to atomic propisitions vf_map var_formula_map; ///< Maps BDD variables to atomic propisitions
fv_map prom_map; ///< Maps promises to BDD variables. fv_map acc_map; ///< Maps accepting conditions to BDD variables
vf_map prom_formula_map; ///< Maps BDD variables to promises. vf_map acc_formula_map; ///< Maps BDD variables to accepting conditions
/// \brief Dump all variables for debugging. /// \brief Dump all variables for debugging.
/// \param os The output stream. /// \param os The output stream.

View file

@ -13,11 +13,12 @@ namespace spot
const tgba_bdd_core_data& in = from.get_core_data(); const tgba_bdd_core_data& in = from.get_core_data();
data_.relation = bdd_replace(in.relation, rewrite); data_.relation = bdd_replace(in.relation, rewrite);
data_.accepting_conditions = bdd_replace(in.accepting_conditions, rewrite);
data_.now_set = bdd_replace(in.now_set, rewrite); data_.now_set = bdd_replace(in.now_set, rewrite);
data_.negnow_set = bdd_replace(in.negnow_set, rewrite); data_.negnow_set = bdd_replace(in.negnow_set, rewrite);
data_.notnow_set = bdd_replace(in.notnow_set, rewrite); data_.notnext_set = bdd_replace(in.notnext_set, rewrite);
data_.notvar_set = bdd_replace(in.notvar_set, rewrite); data_.notvar_set = bdd_replace(in.notvar_set, rewrite);
data_.notprom_set = bdd_replace(in.notprom_set, rewrite); data_.notacc_set = bdd_replace(in.notacc_set, rewrite);
init_ = bdd_replace(from.get_init_bdd(), rewrite); init_ = bdd_replace(from.get_init_bdd(), rewrite);
@ -40,7 +41,6 @@ namespace spot
{ {
i_to = dict_.now_map.find(i_from->first); i_to = dict_.now_map.find(i_from->first);
assert(i_to != dict_.now_map.end()); assert(i_to != dict_.now_map.end());
bdd_setpair(rewrite, i_from->second, i_to->second); bdd_setpair(rewrite, i_from->second, i_to->second);
bdd_setpair(rewrite, i_from->second + 1, i_to->second + 1); bdd_setpair(rewrite, i_from->second + 1, i_to->second + 1);
bdd_setpair(data_.next_to_now, i_to->second + 1, i_to->second); bdd_setpair(data_.next_to_now, i_to->second + 1, i_to->second);
@ -51,12 +51,12 @@ namespace spot
assert(i_to != dict_.var_map.end()); assert(i_to != dict_.var_map.end());
bdd_setpair(rewrite, i_from->second, i_to->second); bdd_setpair(rewrite, i_from->second, i_to->second);
} }
for (i_from = from.prom_map.begin(); for (i_from = from.acc_map.begin();
i_from != from.prom_map.end(); i_from != from.acc_map.end();
++i_from) ++i_from)
{ {
i_to = dict_.prom_map.find(i_from->first); i_to = dict_.acc_map.find(i_from->first);
assert(i_to != dict_.prom_map.end()); assert(i_to != dict_.acc_map.end());
bdd_setpair(rewrite, i_from->second, i_to->second); bdd_setpair(rewrite, i_from->second, i_to->second);
} }
return rewrite; return rewrite;

View file

@ -1,4 +1,5 @@
#include "ltlast/atomic_prop.hh" #include "ltlast/atomic_prop.hh"
#include "ltlast/constant.hh"
#include "ltlvisit/destroy.hh" #include "ltlvisit/destroy.hh"
#include "tgbaexplicit.hh" #include "tgbaexplicit.hh"
#include <cassert> #include <cassert>
@ -10,8 +11,8 @@ namespace spot
// tgba_explicit_succ_iterator // tgba_explicit_succ_iterator
tgba_explicit_succ_iterator::tgba_explicit_succ_iterator tgba_explicit_succ_iterator::tgba_explicit_succ_iterator
(const tgba_explicit::state* s) (const tgba_explicit::state* s, bdd all_acc)
: s_(s) : s_(s), all_accepting_conditions_(all_acc)
{ {
} }
@ -46,9 +47,9 @@ namespace spot
} }
bdd bdd
tgba_explicit_succ_iterator::current_promise() tgba_explicit_succ_iterator::current_accepting_conditions()
{ {
return (*i_)->promise; return (*i_)->accepting_conditions & all_accepting_conditions_;
} }
@ -80,7 +81,9 @@ namespace spot
tgba_explicit::tgba_explicit() tgba_explicit::tgba_explicit()
: init_(0) : init_(0), all_accepting_conditions_(bddfalse),
neg_accepting_conditions_(bddtrue),
all_accepting_conditions_computed_(false)
{ {
} }
@ -124,12 +127,13 @@ namespace spot
transition* t = new transition; transition* t = new transition;
t->dest = d; t->dest = d;
t->condition = bddtrue; t->condition = bddtrue;
t->promise = bddtrue; t->accepting_conditions = bddfalse;
s->push_back(t); s->push_back(t);
return t; return t;
} }
int tgba_explicit::get_condition(ltl::formula* f) bdd
tgba_explicit::get_condition(ltl::formula* f)
{ {
assert(dynamic_cast<ltl::atomic_prop*>(f)); assert(dynamic_cast<ltl::atomic_prop*>(f));
tgba_bdd_dict::fv_map::iterator i = dict_.var_map.find(f); tgba_bdd_dict::fv_map::iterator i = dict_.var_map.find(f);
@ -145,45 +149,72 @@ namespace spot
ltl::destroy(f); ltl::destroy(f);
v = i->second; v = i->second;
} }
return v; return ithvar(v);
} }
void tgba_explicit::add_condition(transition* t, ltl::formula* f) void
tgba_explicit::add_condition(transition* t, ltl::formula* f)
{ {
t->condition &= ithvar(get_condition(f)); t->condition &= get_condition(f);
} }
void tgba_explicit::add_neg_condition(transition* t, ltl::formula* f) void
tgba_explicit::add_neg_condition(transition* t, ltl::formula* f)
{ {
t->condition &= ! ithvar(get_condition(f)); t->condition &= ! get_condition(f);
} }
int tgba_explicit::get_promise(ltl::formula* f) void
tgba_explicit::declare_accepting_condition(ltl::formula* f)
{
tgba_bdd_dict::fv_map::iterator i = dict_.acc_map.find(f);
if (i == dict_.acc_map.end())
{ {
tgba_bdd_dict::fv_map::iterator i = dict_.prom_map.find(f);
int v; int v;
if (i == dict_.prom_map.end())
{
v = create_node(); v = create_node();
dict_.prom_map[f] = v; dict_.acc_map[f] = v;
dict_.prom_formula_map[v] = f; dict_.acc_formula_map[v] = f;
neg_accepting_conditions_ &= !ithvar(v);
} }
else }
bool
tgba_explicit::has_accepting_condition(ltl::formula* f) const
{ {
ltl::destroy(f); tgba_bdd_dict::fv_map::const_iterator i = dict_.acc_map.find(f);
v = i->second; return i != dict_.acc_map.end();
} }
bdd
tgba_explicit::get_accepting_condition(ltl::formula* f)
{
ltl::constant* c = dynamic_cast<ltl::constant*>(f);
if (c)
{
switch (c->val())
{
case ltl::constant::True:
return bddtrue;
case ltl::constant::False:
return bddfalse;
}
/* Unreachable code. */
assert(0);
}
tgba_bdd_dict::fv_map::iterator i = dict_.acc_map.find(f);
assert (i != dict_.acc_map.end());
ltl::destroy(f);
bdd v = ithvar(i->second);
v &= bdd_exist(neg_accepting_conditions_, v);
return v; return v;
} }
void tgba_explicit::add_promise(transition* t, ltl::formula* f) void
tgba_explicit::add_accepting_condition(transition* t, ltl::formula* f)
{ {
t->promise &= ithvar(get_promise(f)); bdd c = get_accepting_condition(f);
} t->accepting_conditions |= c;
void tgba_explicit::add_neg_promise(transition* t, ltl::formula* f)
{
t->promise &= ! ithvar(get_promise(f));
} }
state* state*
@ -197,7 +228,8 @@ namespace spot
{ {
const state_explicit* s = dynamic_cast<const state_explicit*>(state); const state_explicit* s = dynamic_cast<const state_explicit*>(state);
assert(s); assert(s);
return new tgba_explicit_succ_iterator(s->get_state()); return new tgba_explicit_succ_iterator(s->get_state(),
all_accepting_conditions());
} }
const tgba_bdd_dict& const tgba_bdd_dict&
@ -216,4 +248,28 @@ namespace spot
return i->second; return i->second;
} }
bdd
tgba_explicit::all_accepting_conditions() const
{
if (!all_accepting_conditions_computed_)
{
bdd all = bddfalse;
tgba_bdd_dict::fv_map::const_iterator i;
for (i = dict_.acc_map.begin(); i != dict_.acc_map.end(); ++i)
{
bdd v = ithvar(i->second);
all |= v & bdd_exist(neg_accepting_conditions_, v);
}
all_accepting_conditions_ = all;
all_accepting_conditions_computed_ = true;
}
return all_accepting_conditions_;
}
bdd
tgba_explicit::neg_accepting_conditions() const
{
return neg_accepting_conditions_;
}
} }

View file

@ -24,7 +24,7 @@ namespace spot
struct transition struct transition
{ {
bdd condition; bdd condition;
bdd promise; bdd accepting_conditions;
state* dest; state* dest;
}; };
@ -33,8 +33,9 @@ namespace spot
void add_condition(transition* t, ltl::formula* f); void add_condition(transition* t, ltl::formula* f);
void add_neg_condition(transition* t, ltl::formula* f); void add_neg_condition(transition* t, ltl::formula* f);
void add_promise(transition* t, ltl::formula* f); void declare_accepting_condition(ltl::formula* f);
void add_neg_promise(transition* t, ltl::formula* f); bool has_accepting_condition(ltl::formula* f) const;
void add_accepting_condition(transition* t, ltl::formula* f);
// tgba interface // tgba interface
virtual ~tgba_explicit(); virtual ~tgba_explicit();
@ -44,10 +45,13 @@ namespace spot
virtual const tgba_bdd_dict& get_dict() const; virtual const tgba_bdd_dict& get_dict() const;
virtual std::string format_state(const spot::state* state) const; virtual std::string format_state(const spot::state* state) const;
virtual bdd all_accepting_conditions() const;
virtual bdd neg_accepting_conditions() const;
protected: protected:
state* add_state(const std::string& name); state* add_state(const std::string& name);
int get_condition(ltl::formula* f); bdd get_condition(ltl::formula* f);
int get_promise(ltl::formula* f); bdd get_accepting_condition(ltl::formula* f);
typedef std::map<const std::string, tgba_explicit::state*> ns_map; typedef std::map<const std::string, tgba_explicit::state*> ns_map;
typedef std::map<const tgba_explicit::state*, std::string> sn_map; typedef std::map<const tgba_explicit::state*, std::string> sn_map;
@ -55,6 +59,9 @@ namespace spot
sn_map state_name_map_; sn_map state_name_map_;
tgba_bdd_dict dict_; tgba_bdd_dict dict_;
tgba_explicit::state* init_; tgba_explicit::state* init_;
mutable bdd all_accepting_conditions_;
bdd neg_accepting_conditions_;
mutable bool all_accepting_conditions_computed_;
}; };
@ -83,7 +90,7 @@ namespace spot
class tgba_explicit_succ_iterator : public tgba_succ_iterator class tgba_explicit_succ_iterator : public tgba_succ_iterator
{ {
public: public:
tgba_explicit_succ_iterator(const tgba_explicit::state* s); tgba_explicit_succ_iterator(const tgba_explicit::state* s, bdd all_acc);
virtual virtual
~tgba_explicit_succ_iterator() ~tgba_explicit_succ_iterator()
@ -96,11 +103,12 @@ namespace spot
virtual state_explicit* current_state(); virtual state_explicit* current_state();
virtual bdd current_condition(); virtual bdd current_condition();
virtual bdd current_promise(); virtual bdd current_accepting_conditions();
private: private:
const tgba_explicit::state* s_; const tgba_explicit::state* s_;
tgba_explicit::state::const_iterator i_; tgba_explicit::state::const_iterator i_;
bdd all_accepting_conditions_;
}; };
} }

View file

@ -43,8 +43,11 @@ namespace spot
// tgba_product_succ_iterator // tgba_product_succ_iterator
tgba_product_succ_iterator::tgba_product_succ_iterator tgba_product_succ_iterator::tgba_product_succ_iterator
(tgba_succ_iterator* left, tgba_succ_iterator* right) (tgba_succ_iterator* left, tgba_succ_iterator* right,
: left_(left), right_(right) bdd left_neg, bdd right_neg)
: left_(left), right_(right),
left_neg_(left_neg),
right_neg_(right_neg)
{ {
} }
@ -131,9 +134,10 @@ namespace spot
return current_cond_; return current_cond_;
} }
bdd tgba_product_succ_iterator::current_promise() bdd tgba_product_succ_iterator::current_accepting_conditions()
{ {
return left_->current_promise() & right_->current_promise(); return ((left_->current_accepting_conditions() & right_neg_)
| (right_->current_accepting_conditions() & left_neg_));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -165,6 +169,13 @@ namespace spot
right_ = new tgba_translate_proxy(right, dict_); right_ = new tgba_translate_proxy(right, dict_);
right_should_be_freed_ = true; right_should_be_freed_ = true;
} }
all_accepting_conditions_ = ((left_->all_accepting_conditions()
& right_->neg_accepting_conditions())
| (right_->all_accepting_conditions()
& left_->neg_accepting_conditions()));
neg_accepting_conditions_ = (left_->neg_accepting_conditions()
& right_->neg_accepting_conditions());
} }
tgba_product::~tgba_product() tgba_product::~tgba_product()
@ -190,7 +201,9 @@ namespace spot
tgba_succ_iterator* li = left_->succ_iter(s->left()); tgba_succ_iterator* li = left_->succ_iter(s->left());
tgba_succ_iterator* ri = right_->succ_iter(s->right()); tgba_succ_iterator* ri = right_->succ_iter(s->right());
return new tgba_product_succ_iterator(li, ri); return new tgba_product_succ_iterator(li, ri,
left_->neg_accepting_conditions(),
right_->neg_accepting_conditions());
} }
const tgba_bdd_dict& const tgba_bdd_dict&
@ -209,5 +222,16 @@ namespace spot
+ right_->format_state(s->right())); + right_->format_state(s->right()));
} }
bdd
tgba_product::all_accepting_conditions() const
{
return all_accepting_conditions_;
}
bdd
tgba_product::neg_accepting_conditions() const
{
return neg_accepting_conditions_;
}
} }

View file

@ -57,7 +57,8 @@ namespace spot
{ {
public: public:
tgba_product_succ_iterator(tgba_succ_iterator* left, tgba_product_succ_iterator(tgba_succ_iterator* left,
tgba_succ_iterator* right); tgba_succ_iterator* right,
bdd left_neg, bdd right_neg);
virtual ~tgba_product_succ_iterator(); virtual ~tgba_product_succ_iterator();
@ -69,7 +70,7 @@ namespace spot
// inspection // inspection
state_bdd_product* current_state(); state_bdd_product* current_state();
bdd current_condition(); bdd current_condition();
bdd current_promise(); bdd current_accepting_conditions();
private: private:
//@{ //@{
@ -82,6 +83,8 @@ namespace spot
tgba_succ_iterator* left_; tgba_succ_iterator* left_;
tgba_succ_iterator* right_; tgba_succ_iterator* right_;
bdd current_cond_; bdd current_cond_;
bdd left_neg_;
bdd right_neg_;
}; };
/// \brief A lazy product. (States are computed on the fly.) /// \brief A lazy product. (States are computed on the fly.)
@ -105,12 +108,17 @@ namespace spot
virtual std::string format_state(const state* state) const; virtual std::string format_state(const state* state) const;
virtual bdd all_accepting_conditions() const;
virtual bdd neg_accepting_conditions() const;
private: private:
const tgba* left_; const tgba* left_;
bool left_should_be_freed_; bool left_should_be_freed_;
const tgba* right_; const tgba* right_;
bool right_should_be_freed_; bool right_should_be_freed_;
tgba_bdd_dict dict_; tgba_bdd_dict dict_;
bdd all_accepting_conditions_;
bdd neg_accepting_conditions_;
}; };
} }

View file

@ -53,9 +53,9 @@ namespace spot
} }
bdd bdd
tgba_translate_proxy_succ_iterator::current_promise() tgba_translate_proxy_succ_iterator::current_accepting_conditions()
{ {
return bdd_replace(iter_->current_promise(), rewrite_); return bdd_replace(iter_->current_accepting_conditions(), rewrite_);
} }
@ -89,13 +89,18 @@ namespace spot
bdd_setpair(rewrite_to_, i_from->second, i_to->second); bdd_setpair(rewrite_to_, i_from->second, i_to->second);
bdd_setpair(rewrite_from_, i_to->second, i_from->second); bdd_setpair(rewrite_from_, i_to->second, i_from->second);
} }
for (i_from = f.prom_map.begin(); i_from != f.prom_map.end(); ++i_from) for (i_from = f.acc_map.begin(); i_from != f.acc_map.end(); ++i_from)
{ {
i_to = to_.prom_map.find(i_from->first); i_to = to_.acc_map.find(i_from->first);
assert(i_to != to_.prom_map.end()); assert(i_to != to_.acc_map.end());
bdd_setpair(rewrite_to_, i_from->second, i_to->second); bdd_setpair(rewrite_to_, i_from->second, i_to->second);
bdd_setpair(rewrite_from_, i_to->second, i_from->second); bdd_setpair(rewrite_from_, i_to->second, i_from->second);
} }
all_accepting_conditions_ = bdd_replace(from.all_accepting_conditions(),
rewrite_to_);
neg_accepting_conditions_ = bdd_replace(from.neg_accepting_conditions(),
rewrite_to_);
} }
tgba_translate_proxy::~tgba_translate_proxy() tgba_translate_proxy::~tgba_translate_proxy()
@ -140,4 +145,15 @@ namespace spot
return res; return res;
} }
bdd
tgba_translate_proxy::all_accepting_conditions() const
{
return all_accepting_conditions_;
}
bdd tgba_translate_proxy::neg_accepting_conditions() const
{
return neg_accepting_conditions_;
}
} }

View file

@ -22,7 +22,7 @@ namespace spot
// inspection // inspection
state* current_state(); state* current_state();
bdd current_condition(); bdd current_condition();
bdd current_promise(); bdd current_accepting_conditions();
protected: protected:
tgba_succ_iterator* iter_; tgba_succ_iterator* iter_;
bddPair* rewrite_; bddPair* rewrite_;
@ -51,11 +51,17 @@ namespace spot
virtual std::string format_state(const state* state) const; virtual std::string format_state(const state* state) const;
virtual bdd all_accepting_conditions() const;
virtual bdd neg_accepting_conditions() const;
private: private:
const tgba& from_; ///< The spot::tgba to masquerade. const tgba& from_; ///< The spot::tgba to masquerade.
tgba_bdd_dict to_; ///< The new dictionar to use. tgba_bdd_dict to_; ///< The new dictionar to use.
bddPair* rewrite_to_; ///< The rewriting pair for from->to. bddPair* rewrite_to_; ///< The rewriting pair for from->to.
bddPair* rewrite_from_; ///< The rewriting pair for to->from. bddPair* rewrite_from_; ///< The rewriting pair for to->from.
bdd all_accepting_conditions_;
bdd neg_accepting_conditions_;
}; };
} }

View file

@ -42,8 +42,8 @@ namespace spot
bool recurse = dotty_state(os, g, s, m, node); bool recurse = dotty_state(os, g, s, m, node);
os << " " << father << " -> " << node << " [label=\""; os << " " << father << " -> " << node << " [label=\"";
bdd_print_set(os, g.get_dict(), si->current_condition()) << "\\n"; bdd_print_set(os, g.get_dict(), si->current_condition()) << "\\n";
bdd_print_set(os, g.get_dict(), si->current_promise()) << "\"]" bdd_print_set(os, g.get_dict(), si->current_accepting_conditions())
<< std::endl; << "\"]" << std::endl;
if (recurse) if (recurse)
{ {
dotty_rec(os, g, s, m, node); dotty_rec(os, g, s, m, node);

View file

@ -2,6 +2,7 @@
#include "tgba/tgba.hh" #include "tgba/tgba.hh"
#include "save.hh" #include "save.hh"
#include "tgba/bddprint.hh" #include "tgba/bddprint.hh"
#include "ltlvisit/tostring.hh"
namespace spot namespace spot
{ {
@ -20,8 +21,8 @@ namespace spot
os << "\"" << cur << "\", \"" << g.format_state(s) << "\", "; os << "\"" << cur << "\", \"" << g.format_state(s) << "\", ";
bdd_print_sat(os, g.get_dict(), si->current_condition()) << ","; bdd_print_sat(os, g.get_dict(), si->current_condition()) << ",";
bdd_print_sat(os, g.get_dict(), si->current_promise()) << ";" bdd_print_acc(os, g.get_dict(), si->current_accepting_conditions())
<< std::endl; << ";" << std::endl;
// Destination already explored? // Destination already explored?
seen_set::iterator i = m.find(s); seen_set::iterator i = m.find(s);
@ -41,6 +42,16 @@ namespace spot
std::ostream& std::ostream&
tgba_save_reachable(std::ostream& os, const tgba& g) tgba_save_reachable(std::ostream& os, const tgba& g)
{ {
const tgba_bdd_dict& d = g.get_dict();
os << "acc =";
for (tgba_bdd_dict::fv_map::const_iterator ai = d.acc_map.begin();
ai != d.acc_map.end(); ++ai)
{
os << " \"";
ltl::to_string(ai->first, os) << "\"";
}
os << ";" << std::endl;
seen_set m; seen_set m;
state* state = g.get_init_state(); state* state = g.get_init_state();
save_rec(os, g, state, m); save_rec(os, g, state, m);

View file

@ -12,10 +12,14 @@
{ {
int token; int token;
std::string* str; std::string* str;
std::list<std::pair<bool, spot::ltl::formula*> >* list; std::list<std::pair<bool, spot::ltl::formula*> >* listp;
std::list<spot::ltl::formula*>* list;
} }
%{ %{
#include "ltlast/constant.hh"
#include "ltlvisit/destroy.hh"
/* tgbaparse.hh and parsedecl.hh include each other recursively. /* tgbaparse.hh and parsedecl.hh include each other recursively.
We mut ensure that YYSTYPE is declared (by the above %union) We mut ensure that YYSTYPE is declared (by the above %union)
before parsedecl.hh uses it. */ before parsedecl.hh uses it. */
@ -33,15 +37,20 @@ typedef std::pair<bool, spot::ltl::formula*> pair;
%token <str> STRING %token <str> STRING
%token <str> IDENT %token <str> IDENT
%type <str> strident %type <str> strident
%type <list> prop_list %type <listp> cond_list
%type <list> acc_list
%token ACC_DEF
%% %%
tgba: accepting_decl lines | lines;
accepting_decl: ACC_DEF acc_decl ';'
lines: lines:
| lines line | lines line
; ;
line: strident ',' strident ',' prop_list ',' prop_list ';' line: strident ',' strident ',' cond_list ',' acc_list ';'
{ {
spot::tgba_explicit::transition* t spot::tgba_explicit::transition* t
= result->create_transition(*$1, *$3); = result->create_transition(*$1, *$3);
@ -51,11 +60,9 @@ line: strident ',' strident ',' prop_list ',' prop_list ';'
result->add_neg_condition(t, i->second); result->add_neg_condition(t, i->second);
else else
result->add_condition(t, i->second); result->add_condition(t, i->second);
for (i = $7->begin(); i != $7->end(); ++i) std::list<formula*>::iterator i2;
if (i->first) for (i2 = $7->begin(); i2 != $7->end(); ++i2)
result->add_neg_promise(t, i->second); result->add_accepting_condition(t, *i2);
else
result->add_promise(t, i->second);
delete $1; delete $1;
delete $3; delete $3;
delete $5; delete $5;
@ -65,26 +72,66 @@ line: strident ',' strident ',' prop_list ',' prop_list ';'
strident: STRING | IDENT; strident: STRING | IDENT;
prop_list: cond_list:
{ {
$$ = new std::list<pair>; $$ = new std::list<pair>;
} }
| prop_list strident | cond_list strident
{ {
if (*$2 != "") if (*$2 != "")
{
$1->push_back(pair(false, parse_environment.require(*$2))); $1->push_back(pair(false, parse_environment.require(*$2)));
}
delete $2; delete $2;
$$ = $1; $$ = $1;
} }
| prop_list '!' strident | cond_list '!' strident
{ {
if (*$3 != "") if (*$3 != "")
{
$1->push_back(pair(true, parse_environment.require(*$3))); $1->push_back(pair(true, parse_environment.require(*$3)));
}
delete $3; delete $3;
$$ = $1; $$ = $1;
} }
; ;
acc_list:
{
$$ = new std::list<formula*>;
}
| acc_list strident
{
if (*$2 == "true")
{
$1->push_back(constant::true_instance());
}
else if (*$2 != "" && *$2 != "false")
{
formula* f = parse_environment.require(*$2);
if (! result->has_accepting_condition(f))
{
error_list.push_back(spot::tgba_parse_error(@2,
"undeclared accepting condition"));
destroy(f);
delete $2;
YYERROR;
}
$1->push_back(f);
}
delete $2;
$$ = $1;
}
;
acc_decl:
| acc_decl strident
{
formula* f = parse_environment.require(*$2);
result->declare_accepting_condition(f);
delete $2;
}
; ;
%% %%

View file

@ -35,6 +35,8 @@ eol \n|\r|\n\r|\r\n
return STRING; return STRING;
} }
acc[ \t]*= return ACC_DEF;
[a-zA-Z][a-zA-Z0-9_]* { [a-zA-Z][a-zA-Z0-9_]* {
yylval->str = new std::string(yytext); yylval->str = new std::string(yytext);
return IDENT; return IDENT;

View file

@ -18,9 +18,12 @@ main()
a.add_condition(t2, e.require("a")); a.add_condition(t2, e.require("a"));
a.add_condition(t3, e.require("b")); a.add_condition(t3, e.require("b"));
a.add_condition(t3, e.require("c")); a.add_condition(t3, e.require("c"));
a.add_promise(t1, e.require("p")); a.declare_accepting_condition(e.require("p"));
a.add_promise(t1, e.require("q")); a.declare_accepting_condition(e.require("q"));
a.add_promise(t2, e.require("r")); a.declare_accepting_condition(e.require("r"));
a.add_accepting_condition(t1, e.require("p"));
a.add_accepting_condition(t1, e.require("q"));
a.add_accepting_condition(t2, e.require("r"));
spot::dotty_reachable(std::cout, a); spot::dotty_reachable(std::cout, a);
} }

View file

@ -13,10 +13,10 @@ digraph G {
1 [label="state 0"] 1 [label="state 0"]
0 -> 1 0 -> 1
2 [label="state 1"] 2 [label="state 1"]
1 -> 2 [label="T\n<Prom[p]:1, Prom[q]:1>"] 1 -> 2 [label="T\n<Acc[p]:0, Acc[q]:1, Acc[r]:0><Acc[p]:1, Acc[q]:0, Acc[r]:0>"]
3 [label="state 2"] 3 [label="state 2"]
2 -> 3 [label="<a:1>\n<Prom[r]:1>"] 2 -> 3 [label="<a:1>\n<Acc[p]:0, Acc[q]:0, Acc[r]:1>"]
3 -> 1 [label="<b:1, c:1>\nT"] 3 -> 1 [label="<b:1, c:1>\nF"]
} }
EOF EOF

View file

@ -5,28 +5,31 @@
set -e set -e
cat >input1 <<EOF cat >input1 <<EOF
s1, s3, a,; acc = p1;
s1, s3, a, true;
s1, s2, b, p1; s1, s2, b, p1;
s2, s1, !a,; s2, s1, !a, true;
s2, s3, c,; s2, s3, c, true;
EOF EOF
cat >input2 <<EOF cat >input2 <<EOF
acc=p2 p3;
s1, s2, b, p2; s1, s2, b, p2;
s2, s1, a, p3; s2, s1, a, p3;
EOF EOF
cat >expected <<EOF cat >expected <<EOF
"s1 * s1", "s3 * s2", a b, "p2"; acc = "p1" "p2" "p3";
"s1 * s1", "s3 * s2", a b, "p1" "p2";
"s1 * s1", "s2 * s2", b, "p1" "p2"; "s1 * s1", "s2 * s2", b, "p1" "p2";
"s2 * s2", "s3 * s1", a c, "p3"; "s2 * s2", "s3 * s1", a c, "p1" "p3";
EOF EOF
./explprod input1 input2 > stdout ./explprod input1 input2 > stdout
# Sort out some possible inversions in the output. # Sort out some possible inversions in the output.
# (The order is not guaranteed by SPOT.) # (The order is not guaranteed by SPOT.)
sed 's/c a/a c/g;s/b a/a b/g;s/"p2" "p1"/"p1" "p2"/g' stdout > tmp_ && sed 's/c a/a c/g;s/b a/a b/g;s/"p3" "p1"/"p1" "p3"/g;s/"p3" "p2"/"p1" "p3"/g;s/"p2" "p1"/"p1" "p2"/g' stdout > tmp_ &&
mv tmp_ stdout mv tmp_ stdout
cat stdout cat stdout

View file

@ -13,10 +13,14 @@ syntax(char* prog)
{ {
std::cerr << "Usage: "<< prog << " [-d][-o][-r] formula" << std::endl std::cerr << "Usage: "<< prog << " [-d][-o][-r] formula" << std::endl
<< std::endl << std::endl
<< " -a display the accepting_conditions BDD, not the reachability graph"
<< " -A same as -a, but as a set" << std::endl
<< " -d turn on traces during parsing" << std::endl << " -d turn on traces during parsing" << std::endl
<< " -o re-order BDD variables in the automata" << std::endl << " -o re-order BDD variables in the automata" << std::endl
<< std::endl
<< " -r display the relation BDD, not the reachability graph" << " -r display the relation BDD, not the reachability graph"
<< std::endl; << std::endl
<< " -R same as -r, but as a set" << std::endl;
exit(2); exit(2);
} }
@ -27,7 +31,7 @@ main(int argc, char** argv)
bool debug_opt = false; bool debug_opt = false;
bool defrag_opt = false; bool defrag_opt = false;
bool rel_opt = false; int output = 0;
int formula_index = 0; int formula_index = 0;
for (;;) for (;;)
@ -37,7 +41,15 @@ main(int argc, char** argv)
++formula_index; ++formula_index;
if (!strcmp(argv[formula_index], "-d")) if (!strcmp(argv[formula_index], "-a"))
{
output = 2;
}
else if (!strcmp(argv[formula_index], "-A"))
{
output = 4;
}
else if (!strcmp(argv[formula_index], "-d"))
{ {
debug_opt = true; debug_opt = true;
} }
@ -47,7 +59,11 @@ main(int argc, char** argv)
} }
else if (!strcmp(argv[formula_index], "-r")) else if (!strcmp(argv[formula_index], "-r"))
{ {
rel_opt = true; output = 1;
}
else if (!strcmp(argv[formula_index], "-R"))
{
output = 3;
} }
else else
{ {
@ -70,11 +86,30 @@ main(int argc, char** argv)
spot::ltl::destroy(f); spot::ltl::destroy(f);
if (defrag_opt) if (defrag_opt)
a = spot::defrag(a); a = spot::defrag(a);
if (rel_opt) switch (output)
{
case 0:
spot::dotty_reachable(std::cout, a);
break;
case 1:
spot::bdd_print_dot(std::cout, a.get_dict(), spot::bdd_print_dot(std::cout, a.get_dict(),
a.get_core_data().relation); a.get_core_data().relation);
else break;
spot::dotty_reachable(std::cout, a); case 2:
spot::bdd_print_dot(std::cout, a.get_dict(),
a.get_core_data().accepting_conditions);
break;
case 3:
spot::bdd_print_set(std::cout, a.get_dict(),
a.get_core_data().relation);
break;
case 4:
spot::bdd_print_set(std::cout, a.get_dict(),
a.get_core_data().accepting_conditions);
break;
default:
assert(!"unknown output option");
}
} }
else else
{ {

View file

@ -8,6 +8,7 @@ set -e
# trigger assertions or I/O errors. # trigger assertions or I/O errors.
cat >input1 <<EOF cat >input1 <<EOF
acc = p1;
s1, s3, a,; s1, s3, a,;
s1, s2, b, p1; s1, s2, b, p1;
s2, s1, !a,; s2, s1, !a,;

View file

@ -5,23 +5,34 @@
set -e set -e
cat >input <<EOF cat >input <<EOF
acc = c d;
s1, "s2", a!b, c d; s1, "s2", a!b, c d;
"s2", "state 3", a, !c; "s2", "state 3", a, c;
"state 3", s1,,; "state 3", s1,,;
EOF EOF
./readsave input > stdout ./readsave input > stdout
cat >expected <<EOF cat >expected <<EOF
acc = "c" "d";
"s1", "s2", a !b, "c" "d"; "s1", "s2", a !b, "c" "d";
"s2", "state 3", a, !"c"; "s2", "state 3", a, "c";
"state 3", "s1", ,; "state 3", "s1", ,;
EOF EOF
# Sort out some possible inversions in the output.
# (The order is not guaranteed by SPOT.)
sed 's/"d" "c"/"c" "d"/g' stdout > tmp_ && mv tmp_ stdout
diff stdout expected diff stdout expected
mv stdout input mv stdout input
./readsave input > stdout ./readsave input > stdout
# Sort out some possible inversions in the output.
# (The order is not guaranteed by SPOT.)
sed 's/"d" "c"/"c" "d"/g' stdout > tmp_ && mv tmp_ stdout
diff input stdout diff input stdout
rm input stdout expected rm input stdout expected

View file

@ -34,8 +34,8 @@ main(int argc, char** argv)
spot::tgba_explicit* a = spot::tgba_parse(argv[filename_index], spot::tgba_explicit* a = spot::tgba_parse(argv[filename_index],
pel, env, debug); pel, env, debug);
exit_code = if (spot::format_tgba_parse_errors(std::cerr, pel))
spot::format_tgba_parse_errors(std::cerr, pel); return 2;
if (a) if (a)
{ {
@ -44,7 +44,7 @@ main(int argc, char** argv)
} }
else else
{ {
exit_code = 1; return 1;
} }
return exit_code; return 0;
} }

View file

@ -5,8 +5,9 @@
set -e set -e
cat >input <<EOF cat >input <<EOF
acc = c d;
s1, "s2", a!b, c d; s1, "s2", a!b, c d;
"s2", "state 3", a, !c; "s2", "state 3", a, c;
"state 3", s1,,; "state 3", s1,,;
EOF EOF
@ -19,10 +20,10 @@ digraph G {
1 [label="s1"] 1 [label="s1"]
0 -> 1 0 -> 1
2 [label="s2"] 2 [label="s2"]
1 -> 2 [label="<a:1, b:0>\n<Prom[c]:1, Prom[d]:1>"] 1 -> 2 [label="<a:1, b:0>\n<Acc[c]:0, Acc[d]:1><Acc[c]:1, Acc[d]:0>"]
3 [label="state 3"] 3 [label="state 3"]
2 -> 3 [label="<a:1>\n<Prom[c]:0>"] 2 -> 3 [label="<a:1>\n<Acc[c]:1, Acc[d]:0>"]
3 -> 1 [label="T\nT"] 3 -> 1 [label="T\nF"]
} }
EOF EOF

View file

@ -5,18 +5,21 @@
set -e set -e
cat >input1 <<EOF cat >input1 <<EOF
s1, s3, a,; acc = p1;
s1, s3, a, true;
s1, s2, b, p1; s1, s2, b, p1;
s2, s1, !a,; s2, s1, !a, true;
s2, s3, c,; s2, s3, c,;
EOF EOF
cat >input2 <<EOF cat >input2 <<EOF
acc = p2 p3;
s1, s2, b, p2; s1, s2, b, p2;
s2, s1, a, p3; s2, s1, a, p3;
EOF EOF
cat >input3 <<EOF cat >input3 <<EOF
acc = p4;
s1, s2, a,; s1, s2, a,;
s1, s3, b,; s1, s3, b,;
s3, s2,, p4; s3, s2,, p4;
@ -24,10 +27,11 @@ s2, s3,, p4;
EOF EOF
cat >expected <<EOF cat >expected <<EOF
"s1 * s1 * s1", "s3 * s2 * s2", a b, "p2"; acc = "p2" "p3" "p4" "p1";
"s1 * s1 * s1", "s3 * s2 * s2", a b, "p1" "p2";
"s1 * s1 * s1", "s2 * s2 * s2", a b, "p1" "p2"; "s1 * s1 * s1", "s2 * s2 * s2", a b, "p1" "p2";
"s2 * s2 * s2", "s3 * s1 * s3", a c, "p3" "p4"; "s2 * s2 * s2", "s3 * s1 * s3", a c, "p3" "p4";
"s1 * s1 * s1", "s3 * s2 * s3", a b, "p2"; "s1 * s1 * s1", "s3 * s2 * s3", a b, "p1" "p2";
"s1 * s1 * s1", "s2 * s2 * s3", b, "p1" "p2"; "s1 * s1 * s1", "s2 * s2 * s3", b, "p1" "p2";
"s2 * s2 * s3", "s3 * s1 * s2", a c, "p3" "p4"; "s2 * s2 * s3", "s3 * s1 * s2", a c, "p3" "p4";
EOF EOF