Cache formula translations, and canonize formulae before doing
branching postponement. * src/tgbaalgos/ltl2tgba_fm.cc (formula_canonizer): New class, with bits extracted from fill_dests and ltl_to_tgba_fm. (fill_dests, ltl_to_tgba_fm): Adjust to use formula_canonizer.
This commit is contained in:
parent
aa5cef3c83
commit
040f8beec7
2 changed files with 101 additions and 68 deletions
|
|
@ -1,5 +1,11 @@
|
||||||
2004-05-10 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
2004-05-10 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
||||||
|
|
||||||
|
Cache formula translations, and canonize formulae before doing
|
||||||
|
branching postponement.
|
||||||
|
* src/tgbaalgos/ltl2tgba_fm.cc (formula_canonizer): New class, with
|
||||||
|
bits extracted from fill_dests and ltl_to_tgba_fm.
|
||||||
|
(fill_dests, ltl_to_tgba_fm): Adjust to use formula_canonizer.
|
||||||
|
|
||||||
* src/tgbaalgos/ltl2tgba_fm.hh (ltl_to_tgba_fm): Add argument
|
* src/tgbaalgos/ltl2tgba_fm.hh (ltl_to_tgba_fm): Add argument
|
||||||
fair_loop_approx.
|
fair_loop_approx.
|
||||||
* src/tgbaalgos/ltl2tgba_fm.cc (ltl_to_tgba_fm): Implement the
|
* src/tgbaalgos/ltl2tgba_fm.cc (ltl_to_tgba_fm): Implement the
|
||||||
|
|
|
||||||
|
|
@ -524,66 +524,105 @@ namespace spot
|
||||||
bool
|
bool
|
||||||
check(const formula* f)
|
check(const formula* f)
|
||||||
{
|
{
|
||||||
pfl_map::const_iterator i = pfl.find(f);
|
pfl_map::const_iterator i = pfl_.find(f);
|
||||||
if (i != pfl.end())
|
if (i != pfl_.end())
|
||||||
return i->second;
|
return i->second;
|
||||||
ltl_possible_fair_loop_visitor v;
|
ltl_possible_fair_loop_visitor v;
|
||||||
f->accept(v);
|
f->accept(v);
|
||||||
bool rel = v.result();
|
bool rel = v.result();
|
||||||
pfl[f] = rel;
|
pfl_[f] = rel;
|
||||||
return rel;
|
return rel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef Sgi::hash_map<const formula*, bool, ptr_hash<formula> > pfl_map;
|
typedef Sgi::hash_map<const formula*, bool, ptr_hash<formula> > pfl_map;
|
||||||
pfl_map pfl;
|
pfl_map pfl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class formula_canonizer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
formula_canonizer(translate_dict& d)
|
||||||
|
: v_(d)
|
||||||
|
{
|
||||||
|
// For cosmetics, register 1 initially, so the algorithm will
|
||||||
|
// not register an equivalent formula first.
|
||||||
|
b2f_[bddtrue] = constant::true_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
~formula_canonizer()
|
||||||
|
{
|
||||||
|
while (f2b_.size())
|
||||||
|
{
|
||||||
|
formula_to_bdd_map::iterator i = f2b_.begin();
|
||||||
|
const formula* f = i->first;
|
||||||
|
f2b_.erase(i);
|
||||||
|
destroy(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
translate(const formula* f)
|
||||||
|
{
|
||||||
|
// Use the cached result if available.
|
||||||
|
formula_to_bdd_map::const_iterator i = f2b_.find(f);
|
||||||
|
if (i != f2b_.end())
|
||||||
|
return i->second;
|
||||||
|
|
||||||
|
// Perform the actual translation.
|
||||||
|
f->accept(v_);
|
||||||
|
bdd res = v_.result();
|
||||||
|
f2b_[clone(f)] = res;
|
||||||
|
|
||||||
|
// Register the reverse mapping if it is not already done.
|
||||||
|
if (b2f_.find(res) == b2f_.end())
|
||||||
|
b2f_[res] = f;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formula*
|
||||||
|
canonize(const formula* f)
|
||||||
|
{
|
||||||
|
bdd b = translate(f);
|
||||||
|
|
||||||
|
bdd_to_formula_map::iterator i = b2f_.find(b);
|
||||||
|
// Since we have just translated the formula, it is necessary in b2f_.
|
||||||
|
assert(i != b2f_.end());
|
||||||
|
|
||||||
|
if (i->second != f)
|
||||||
|
{
|
||||||
|
destroy(f);
|
||||||
|
f = clone(i->second);
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
// We do this because many formulae (such as `aR(bRc)' and
|
||||||
|
// `aR(bRc).(bRc)') are equivalent, and are trivially identified
|
||||||
|
// by looking at the set of successors.
|
||||||
|
typedef std::map<const formula*, bdd> formula_to_bdd_map;
|
||||||
|
formula_to_bdd_map f2b_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::map<bdd, bdd, bdd_less_than> prom_map;
|
typedef std::map<bdd, bdd, bdd_less_than> prom_map;
|
||||||
typedef Sgi::hash_map<const formula*, prom_map, ptr_hash<formula> > dest_map;
|
typedef Sgi::hash_map<const formula*, prom_map, ptr_hash<formula> > dest_map;
|
||||||
typedef std::map<bdd, const formula*, bdd_less_than> succ_to_formula;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fill_dests(translate_dict& d, bool symb_merge,
|
fill_dests(translate_dict& d, dest_map& dests, bdd label, const formula* dest)
|
||||||
std::set<const formula*>& formulae_seen,
|
|
||||||
succ_to_formula& canonical_succ, ltl_trad_visitor& v,
|
|
||||||
dest_map& dests, bdd label, formula* dest)
|
|
||||||
{
|
{
|
||||||
// If we already know a state with the same successors,
|
|
||||||
// use it in lieu of the current one. (See the comments
|
|
||||||
// for canonical_succ.) We need to do this only for new
|
|
||||||
// destinations.
|
|
||||||
if (symb_merge
|
|
||||||
&& formulae_seen.find(dest) == formulae_seen.end())
|
|
||||||
{
|
|
||||||
dest->accept(v);
|
|
||||||
bdd succbdd = v.result();
|
|
||||||
succ_to_formula::iterator cs =
|
|
||||||
canonical_succ.find(succbdd);
|
|
||||||
if (cs != canonical_succ.end())
|
|
||||||
{
|
|
||||||
destroy(dest);
|
|
||||||
dest = clone(cs->second);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
canonical_succ[succbdd] = clone(dest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bdd conds = bdd_existcomp(label, d.var_set);
|
bdd conds = bdd_existcomp(label, d.var_set);
|
||||||
bdd promises = bdd_existcomp(label, d.a_set);
|
bdd promises = bdd_existcomp(label, d.a_set);
|
||||||
|
|
||||||
// Clear the promises if the destination is the True state.
|
|
||||||
// (Normally this is already the case unless the fair_loop_approx
|
|
||||||
// optimization is used, because this can get confused by formulae
|
|
||||||
// like X(1): it doesn't know that X(1) is equivalent to 1, so it
|
|
||||||
// puts all promises on arcs going to X(1).)
|
|
||||||
if (dest == constant::true_instance())
|
|
||||||
promises = bddtrue;
|
|
||||||
|
|
||||||
dest_map::iterator i = dests.find(dest);
|
dest_map::iterator i = dests.find(dest);
|
||||||
if (i == dests.end())
|
if (i == dests.end())
|
||||||
{
|
{
|
||||||
|
|
@ -614,17 +653,9 @@ namespace spot
|
||||||
|
|
||||||
std::set<const formula*> formulae_seen;
|
std::set<const formula*> formulae_seen;
|
||||||
std::set<const formula*> formulae_to_translate;
|
std::set<const formula*> formulae_to_translate;
|
||||||
// Map a representation of successors to a canonical formula.
|
|
||||||
// We do this because many formulae (such as `aR(bRc)' and
|
|
||||||
// `aR(bRc).(bRc)') are equivalent, and are trivially identified
|
|
||||||
// by looking at the set of successors.
|
|
||||||
succ_to_formula canonical_succ;
|
|
||||||
// For cosmetics, register 1 initially, so the algorithm will not
|
|
||||||
// register an equivalent formula first.
|
|
||||||
canonical_succ[bddtrue] = constant::true_instance();
|
|
||||||
|
|
||||||
translate_dict d(dict);
|
translate_dict d(dict);
|
||||||
ltl_trad_visitor v(d);
|
formula_canonizer fc(d);
|
||||||
|
|
||||||
// Compute the set of all promises occurring inside the formula.
|
// Compute the set of all promises occurring inside the formula.
|
||||||
bdd all_promises = bddtrue;
|
bdd all_promises = bddtrue;
|
||||||
|
|
@ -649,14 +680,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.
|
||||||
// FIXME: Currently the same formula can be converted into a
|
bdd res = fc.translate(f);
|
||||||
// BDD twice. Once in the symb_merge block in fill_dests,
|
|
||||||
// and then once here.
|
|
||||||
f->accept(v);
|
|
||||||
bdd res = v.result();
|
|
||||||
succ_to_formula::iterator cs = canonical_succ.find(res);
|
|
||||||
if (cs == canonical_succ.end())
|
|
||||||
canonical_succ[res] = clone(f);
|
|
||||||
|
|
||||||
std::string now = to_string(f);
|
std::string now = to_string(f);
|
||||||
|
|
||||||
|
|
@ -709,7 +733,7 @@ namespace spot
|
||||||
exprop ? bdd_satoneset(all_props, var_set, bddtrue) : bddtrue;
|
exprop ? bdd_satoneset(all_props, var_set, bddtrue) : bddtrue;
|
||||||
all_props -= one_prop_set;
|
all_props -= one_prop_set;
|
||||||
|
|
||||||
typedef std::map<bdd, formula*, bdd_less_than> succ_map;
|
typedef std::map<bdd, const formula*, bdd_less_than> succ_map;
|
||||||
succ_map succs;
|
succ_map succs;
|
||||||
|
|
||||||
minato_isop isop(res & one_prop_set);
|
minato_isop isop(res & one_prop_set);
|
||||||
|
|
@ -718,12 +742,18 @@ namespace spot
|
||||||
{
|
{
|
||||||
bdd label = bdd_exist(cube, d.next_set);
|
bdd label = bdd_exist(cube, d.next_set);
|
||||||
bdd dest_bdd = bdd_existcomp(cube, d.next_set);
|
bdd dest_bdd = bdd_existcomp(cube, d.next_set);
|
||||||
formula* dest = d.conj_bdd_to_formula(dest_bdd);
|
const formula* dest = d.conj_bdd_to_formula(dest_bdd);
|
||||||
|
|
||||||
|
// If we already know a state with the same
|
||||||
|
// successors, use it in lieu of the current one.
|
||||||
|
if (symb_merge)
|
||||||
|
dest = fc.canonize(dest);
|
||||||
|
|
||||||
// If the destination cannot possibly be part of a fair
|
// If the destination cannot possibly be part of a fair
|
||||||
// loop, make all possible promises.
|
// loop, make all possible promises.
|
||||||
if (fair_loop_approx
|
if (fair_loop_approx
|
||||||
&& dest_bdd != bddtrue && !pflc.check(dest))
|
&& dest != constant::true_instance()
|
||||||
|
&& !pflc.check(dest))
|
||||||
label &= all_promises;
|
label &= all_promises;
|
||||||
|
|
||||||
// If we are not postponing the branching, we can
|
// If we are not postponing the branching, we can
|
||||||
|
|
@ -733,8 +763,7 @@ namespace spot
|
||||||
// second loop.
|
// second loop.
|
||||||
if (!branching_postponement)
|
if (!branching_postponement)
|
||||||
{
|
{
|
||||||
fill_dests(d, symb_merge, formulae_seen, canonical_succ,
|
fill_dests(d, dests, label, dest);
|
||||||
v, dests, label, dest);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -742,15 +771,16 @@ namespace spot
|
||||||
if (si == succs.end())
|
if (si == succs.end())
|
||||||
succs[label] = dest;
|
succs[label] = dest;
|
||||||
else
|
else
|
||||||
si->second = multop::instance(multop::Or,
|
si->second =
|
||||||
si->second, dest);
|
multop::instance(multop::Or,
|
||||||
|
const_cast<formula*>(si->second),
|
||||||
|
const_cast<formula*>(dest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (branching_postponement)
|
if (branching_postponement)
|
||||||
for (succ_map::const_iterator si = succs.begin();
|
for (succ_map::const_iterator si = succs.begin();
|
||||||
si != succs.end(); ++si)
|
si != succs.end(); ++si)
|
||||||
fill_dests(d, symb_merge, formulae_seen, canonical_succ, v,
|
fill_dests(d, dests, si->first, si->second);
|
||||||
dests, si->first, si->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for an arc going to 1 (True). Register it first, that
|
// Check for an arc going to 1 (True). Register it first, that
|
||||||
|
|
@ -834,9 +864,6 @@ namespace spot
|
||||||
for (std::set<const formula*>::iterator i = formulae_seen.begin();
|
for (std::set<const formula*>::iterator i = formulae_seen.begin();
|
||||||
i != formulae_seen.end(); ++i)
|
i != formulae_seen.end(); ++i)
|
||||||
destroy(*i);
|
destroy(*i);
|
||||||
for (succ_to_formula::iterator i = canonical_succ.begin();
|
|
||||||
i != canonical_succ.end(); ++i)
|
|
||||||
destroy(i->second);
|
|
||||||
|
|
||||||
// Turn all promises into real acceptance conditions.
|
// Turn all promises into real acceptance conditions.
|
||||||
a->complement_all_acceptance_conditions();
|
a->complement_all_acceptance_conditions();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue