Cache the LTL->BDD translation for every subformulae.

We used to cache it only for formulas used as states.

* src/tgbaalgos/ltl2tgba_fm.cc (translate_dict::ltl_to_bdd): New method.
(ltl_trad_visitor::recurse): Use ltl_to_bdd().
(formula_canonizer): Likewise.
(ltl_to_tgba_fm): Adjust.
This commit is contained in:
Alexandre Duret-Lutz 2011-11-11 15:36:22 +01:00
parent 77d704ea9e
commit f590ca4e96

View file

@ -79,13 +79,14 @@ namespace spot
{ {
public: public:
translate_dict(bdd_dict* dict, ltl_simplifier* ls) translate_dict(bdd_dict* dict, ltl_simplifier* ls, bool exprop)
: dict(dict), : dict(dict),
ls(ls), ls(ls),
a_set(bddtrue), a_set(bddtrue),
var_set(bddtrue), var_set(bddtrue),
next_set(bddtrue), next_set(bddtrue),
transdfa(*this) transdfa(*this),
exprop(exprop)
{ {
} }
@ -95,6 +96,14 @@ namespace spot
for (i = next_map.begin(); i != next_map.end(); ++i) for (i = next_map.begin(); i != next_map.end(); ++i)
i->first->destroy(); i->first->destroy();
dict->unregister_all_my_variables(this); dict->unregister_all_my_variables(this);
formula_to_bdd_map::iterator j = ltl_bdd_unmarked_.begin();
// Advance the iterator before destroying previous value.
while (j != ltl_bdd_unmarked_.end())
j++->first->destroy();
j = ltl_bdd_marked_.begin();
while (j != ltl_bdd_marked_.end())
j++->first->destroy();
} }
bdd_dict* dict; bdd_dict* dict;
@ -111,6 +120,22 @@ namespace spot
bdd next_set; bdd next_set;
ratexp_to_dfa transdfa; ratexp_to_dfa transdfa;
bool exprop;
struct translated
{
bdd symbolic;
bool has_rational:1;
bool has_marked:1;
};
typedef Sgi::hash_map<const formula*, translated, ptr_hash<formula> >
formula_to_bdd_map;
private:
formula_to_bdd_map ltl_bdd_unmarked_;
formula_to_bdd_map ltl_bdd_marked_;
public:
int int
register_proposition(const formula* f) register_proposition(const formula* f)
@ -259,6 +284,10 @@ namespace spot
assert(b != bddfalse); assert(b != bddfalse);
} }
} }
const translated&
ltl_to_bdd(const formula* f, bool mark_all);
}; };
#ifdef __GNUC__ #ifdef __GNUC__
@ -1484,11 +1513,10 @@ namespace spot
bdd bdd
recurse(const formula* f) recurse(const formula* f)
{ {
ltl_trad_visitor v(dict_, mark_all_, exprop_); const translate_dict::translated& t = dict_.ltl_to_bdd(f, mark_all_);
f->accept(v); rat_seen_ |= t.has_rational;
rat_seen_ |= v.has_rational(); has_marked_ |= t.has_marked;
has_marked_ |= v.has_marked(); return t.symbolic;
return v.result();
} }
@ -1501,6 +1529,26 @@ namespace spot
bool exprop_; bool exprop_;
}; };
const translate_dict::translated&
translate_dict::ltl_to_bdd(const formula* f, bool mark_all)
{
formula_to_bdd_map* m;
if (mark_all || f->is_ltl_formula())
m = &ltl_bdd_marked_;
else
m = &ltl_bdd_unmarked_;
formula_to_bdd_map::const_iterator i = m->find(f);
if (i != m->end())
return i->second;
ltl_trad_visitor v(*this, mark_all, exprop);
f->accept(v);
translated t = { v.result(), v.has_rational(), v.has_marked() };
return m->insert(std::make_pair(f->clone(), t)).first->second;
}
// Check whether a formula has a R, W, or G operator at its // Check whether a formula has a R, W, or G operator at its
// top-level (preceding logical operators do not count). // top-level (preceding logical operators do not count).
@ -1624,9 +1672,8 @@ namespace spot
{ {
public: public:
formula_canonizer(translate_dict& d, formula_canonizer(translate_dict& d,
bool fair_loop_approx, bdd all_promises, bool exprop) bool fair_loop_approx, bdd all_promises)
: v_(d, false, exprop), : fair_loop_approx_(fair_loop_approx),
fair_loop_approx_(fair_loop_approx),
all_promises_(all_promises), all_promises_(all_promises),
d_(d) d_(d)
{ {
@ -1637,27 +1684,20 @@ namespace spot
~formula_canonizer() ~formula_canonizer()
{ {
while (!f2b_.empty()) translate_dict::formula_to_bdd_map::iterator i = f2b_.begin();
{ while (i != f2b_.end())
formula_to_bdd_map::iterator i = f2b_.begin(); // Advance the iterator before destroying previous value.
const formula* f = i->first; i++->first->destroy();
f2b_.erase(i);
f->destroy();
}
} }
struct translated // This wrap translate_dict::ltl_to_bdd() for top-level formulas.
{ // In case the formula contains SERE operators, we need to decide
bdd symbolic; // if we have to mark unmarked operators, and more
bool has_rational:1; const translate_dict::translated&
bool has_marked:1;
};
const translated&
translate(const formula* f, bool* new_flag = 0) translate(const formula* f, bool* new_flag = 0)
{ {
// Use the cached result if available. // Use the cached result if available.
formula_to_bdd_map::const_iterator i = f2b_.find(f); translate_dict::formula_to_bdd_map::const_iterator i = f2b_.find(f);
if (i != f2b_.end()) if (i != f2b_.end())
return i->second; return i->second;
@ -1665,12 +1705,7 @@ namespace spot
*new_flag = true; *new_flag = true;
// Perform the actual translation. // Perform the actual translation.
v_.reset(!f->is_marked()); translate_dict::translated t = d_.ltl_to_bdd(f, !f->is_marked());
f->accept(v_);
translated t;
t.symbolic = v_.result();
t.has_rational = v_.has_rational();
t.has_marked = v_.has_marked();
// std::cerr << "-----" << std::endl; // std::cerr << "-----" << std::endl;
// std::cerr << "Formula: " << to_string(f) << std::endl; // std::cerr << "Formula: " << to_string(f) << std::endl;
@ -1706,7 +1741,7 @@ namespace spot
} }
else else
{ {
// We have left marked operators, but still // We have no marked operators, but still
// have other rational operator to check. // have other rational operator to check.
// Start a new marked cycle. // Start a new marked cycle.
formula* dest2 = mark_concat_ops(dest); formula* dest2 = mark_concat_ops(dest);
@ -1738,7 +1773,7 @@ namespace spot
if (b2f_.find(t.symbolic) == b2f_.end()) if (b2f_.find(t.symbolic) == b2f_.end())
b2f_[t.symbolic] = f; b2f_[t.symbolic] = f;
return f2b_[f->clone()] = t; return f2b_.insert(std::make_pair(f->clone(), t)).first->second;
} }
const formula* const formula*
@ -1762,18 +1797,16 @@ namespace spot
} }
private: private:
ltl_trad_visitor v_;
// Map each formula to its associated bdd. This speed things up when
// the same formula is translated several times, which especially
// occurs when canonize() is called repeatedly inside exprop.
typedef std::map<bdd, const formula*, bdd_less_than> bdd_to_formula_map;
bdd_to_formula_map b2f_;
// Map a representation of successors to a canonical formula. // Map a representation of successors to a canonical formula.
// We do this because many formulae (such as `aR(bRc)' and // We do this because many formulae (such as `aR(bRc)' and
// `aR(bRc).(bRc)') are equivalent, and are trivially identified // `aR(bRc).(bRc)') are equivalent, and are trivially identified
// by looking at the set of successors. // by looking at the set of successors.
typedef std::map<const formula*, translated> formula_to_bdd_map; typedef std::map<bdd, const formula*, bdd_less_than> bdd_to_formula_map;
formula_to_bdd_map f2b_; bdd_to_formula_map b2f_;
// Map each formula to its associated bdd. This speed things up when
// the same formula is translated several times, which especially
// occurs when canonize() is called repeatedly inside exprop.
translate_dict::formula_to_bdd_map f2b_;
possible_fair_loop_checker pflc_; possible_fair_loop_checker pflc_;
bool fair_loop_approx_; bool fair_loop_approx_;
@ -1836,7 +1869,7 @@ namespace spot
assert(dict == s->get_dict()); assert(dict == s->get_dict());
translate_dict d(dict, s); translate_dict d(dict, s, exprop);
// Compute the set of all promises that can possibly occur // Compute the set of all promises that can possibly occur
// inside the formula. // inside the formula.
@ -1848,7 +1881,7 @@ namespace spot
all_promises = pv.result(); all_promises = pv.result();
} }
formula_canonizer fc(d, fair_loop_approx, all_promises, exprop); formula_canonizer fc(d, fair_loop_approx, all_promises);
// These are used when atomic propositions are interpreted as // These are used when atomic propositions are interpreted as
// events. There are two kinds of events: observable events are // events. There are two kinds of events: observable events are
@ -1901,7 +1934,7 @@ namespace spot
formulae_to_translate.erase(formulae_to_translate.begin()); formulae_to_translate.erase(formulae_to_translate.begin());
// Translate it into a BDD to simplify it. // Translate it into a BDD to simplify it.
const formula_canonizer::translated& t = fc.translate(now); const translate_dict::translated& t = fc.translate(now);
bdd res = t.symbolic; bdd res = t.symbolic;
// Handle exclusive events. // Handle exclusive events.