Before this change, all automata would construct their own
dictionaries (map of BDD variables to LTL formulae). This was cumbersome, because to multiply two automata we had to build a common dictionary (the union of the two LTL formula spaces), and install wrappers to translate each automaton's BDD answers into the common dictionary. This translation, that had to be repeated when several products were nested, was time consuming and was a hindrance for some optimizations. In the new scheme, all automata involved in a product must share the same dictionary. An empty dictionary should be constructed by the user and passed to the automaton' constructors as necessary. This huge change removes most code than it adds. * src/Makefile.am (libspot_la_LIBADD): Add misc/libmisc.la. * src/misc/bddalloc.hh, src/misc/bddalloc.cc: New files. These partly replace src/tgba/bddfactory.hh and src/tgba/bddfactory.cc. * src/misc/Makefile.am: Adjust to build bddalloc.hh and bddalloc.cc. * src/tgba/bddfactory.hh, src/tgba/bddfactory.cc, src/tgba/dictunion.hh, src/tgba/dictunion.cc, src/tgba/tgbabdddict.hh, src/tgba/tgbabdddict.cc, src/tgba/tgbabddtranslatefactory.hh, src/tgba/tgbabddtranslatefactory.cc, src/tgba/tgbatranslateproxy.hh, src/tgba/tgbatranslateproxy.cc: Delete. * src/tgba/bdddict.hh, src/tgba/bdddict.cc: New files. These replaces tgbabdddict.hh and tgbabdddict.cc, and also part of bddfactory.hh and bddfactory.cc. * src/tgba/bddprint.cc, src/tgba/bddprint.hh: Adjust to use bdd_dict* instead of tgba_bdd_dict&. * src/tgba/succiterconcrete.cc (succ_iter_concrete::next()): Get next_to_now from the dictionary. * src/tgba/tgba.hh (tgba::get_dict): Return a bdd_dict*, not a const tgba_bdd_dict*. * src/tgba/tgbabddconcrete.cc, src/tgba/tgbabddconcrete.hh: Adjust to use the new dictionary, stored in data_. * src/tgba/tgbabddconcretefactory.cc, src/tgba/tgbabddconcretefactory.hh: Likewise. Plus now_to_next_ is now also stored in the dictionary. * src/tgba/tgbabddconcreteproduct.cc: Likewise. Now that both operand share the same product, there is not point in using tgba_bdd_translate_factory. * src/tgba/tgbabddcoredata.cc, src/tgba/tgbabddcoredata.hh: Store a bdd_dict (taken as constructor argument). (tgba_bdd_core_data::~tgba_bdd_core_data): Remove. (tgba_bdd_core_data::translate): Remove. (tgba_bdd_core_data::next_to_now): Remove (now in dict). (tgba_bdd_core_data::dict): New pointer. * src/tgba/tgbabddfactory.hh: (tgba_bdd_factory::get_dict): Remove. * src/tgba/tgbaexplicit.cc, src/tgba/tgbaexplicit.hh: Adjust to use the new dictionary. * src/tgba/tgbaproduct.cc, src/tgba/tgbaproduct.hh: Likewise. Do not use tgba_bdd_dict_union and tgba_bdd_translate_proxy anymore. * src/tgbaalgos/lbtt.cc, src/tgbaalgos/save.cc: Adjust to use bdd_dict* instead of tgba_bdd_dict&. * src/tgbaalgos/ltl2tgba.cc, src/tgbaalgos/ltl2tgba.cc: Likewise. (ltl_to_tgba): Take a dict argument. * src/tgbaparse/public.hh (tgba_parse): Take a dict argument. * src/tgbaparse/tgbaparse.yy (tgba_parse): Take a dict argument. * src/tgbatest/explicit.cc, src/tgbatest/explprod.cc, src/tgbatest/ltlprod.cc, src/tgbatest/mixprod.cc, src/tgbatest/readsave.cc, src/tgbatest/spotlbtt.cc, src/tgbatest/tgbaread.cc, src/tgbatest/tripprod.cc: Instantiate a dictionary, and pass it to the automata' constructors. * src/tgbatest/ltl2tgba.cc: Likewise, and remove the -o (defrag) option. * iface/gspn/gspn.hh (tgba_gspn::tgba_gspn): Take a bdd_dict argument. (tgba_gspn::get_dict): Adjust return type. * iface/gspn/gspn.cc: Do not use bdd_factory, adjust to use the new dictionary instead.
This commit is contained in:
parent
3013ba8da6
commit
cab3be9795
52 changed files with 930 additions and 1034 deletions
271
src/tgba/bdddict.cc
Normal file
271
src/tgba/bdddict.cc
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
#include <ltlvisit/clone.hh>
|
||||
#include <ltlvisit/destroy.hh>
|
||||
#include <ltlvisit/tostring.hh>
|
||||
#include <cassert>
|
||||
#include "bdddict.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
bdd_dict::bdd_dict()
|
||||
: bdd_allocator(),
|
||||
next_to_now(bdd_newpair()),
|
||||
now_to_next(bdd_newpair())
|
||||
{
|
||||
}
|
||||
|
||||
bdd_dict::~bdd_dict()
|
||||
{
|
||||
assert_emptiness();
|
||||
bdd_freepair(next_to_now);
|
||||
bdd_freepair(now_to_next);
|
||||
}
|
||||
|
||||
int
|
||||
bdd_dict::register_proposition(const ltl::formula* f, const void* for_me)
|
||||
{
|
||||
int num;
|
||||
// Do not build a variable that already exists.
|
||||
fv_map::iterator sii = var_map.find(f);
|
||||
if (sii != var_map.end())
|
||||
{
|
||||
num = sii->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = clone(f);
|
||||
num = allocate_variables(1);
|
||||
var_map[f] = num;
|
||||
var_formula_map[num] = f;
|
||||
}
|
||||
var_refs[num].insert(for_me);
|
||||
return num;
|
||||
}
|
||||
|
||||
int
|
||||
bdd_dict::register_state(const ltl::formula* f, const void* for_me)
|
||||
{
|
||||
int num;
|
||||
// Do not build a state that already exists.
|
||||
fv_map::iterator sii = now_map.find(f);
|
||||
if (sii != now_map.end())
|
||||
{
|
||||
num = sii->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = ltl::clone(f);
|
||||
num = allocate_variables(2);
|
||||
now_map[f] = num;
|
||||
now_formula_map[num] = f;
|
||||
// Record that num+1 should be renamed as num when
|
||||
// the next state becomes current.
|
||||
bdd_setpair(next_to_now, num + 1, num);
|
||||
bdd_setpair(now_to_next, num, num + 1);
|
||||
}
|
||||
var_refs[num].insert(for_me);
|
||||
return num;
|
||||
}
|
||||
|
||||
int
|
||||
bdd_dict::register_accepting_variable(const ltl::formula* f,
|
||||
const void* for_me)
|
||||
{
|
||||
int num;
|
||||
// Do not build an accepting variable that already exists.
|
||||
fv_map::iterator sii = acc_map.find(f);
|
||||
if (sii != acc_map.end())
|
||||
{
|
||||
num = sii->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = clone(f);
|
||||
num = allocate_variables(1);
|
||||
acc_map[f] = num;
|
||||
acc_formula_map[num] = f;
|
||||
}
|
||||
var_refs[num].insert(for_me);
|
||||
return num;
|
||||
}
|
||||
|
||||
void
|
||||
bdd_dict::register_all_variables_of(const void* from_other,
|
||||
const void* for_me)
|
||||
{
|
||||
vr_map::iterator i;
|
||||
for (i = var_refs.begin(); i != var_refs.end(); ++i)
|
||||
{
|
||||
ref_set& s = i->second;
|
||||
if (s.find(from_other) != s.end())
|
||||
s.insert(for_me);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bdd_dict::unregister_all_my_variables(const void* me)
|
||||
{
|
||||
vr_map::iterator i;
|
||||
for (i = var_refs.begin(); i != var_refs.end();)
|
||||
{
|
||||
// Increment i++ now, we will possibly erase
|
||||
// the current node (which would invalidate the iterator).
|
||||
vr_map::iterator cur = i++;
|
||||
|
||||
ref_set& s = cur->second;
|
||||
ref_set::iterator si = s.find(me);
|
||||
if (si == s.end())
|
||||
continue;
|
||||
s.erase(si);
|
||||
if (! s.empty())
|
||||
continue;
|
||||
// ME was the last user of this variable.
|
||||
// Let's free it. First, we need to find
|
||||
// if this is a Now, a Var, or an Acc variable.
|
||||
int var = cur->first;
|
||||
int n = 1;
|
||||
const ltl::formula* f;
|
||||
vf_map::iterator vi = var_formula_map.find(var);
|
||||
if (vi != var_formula_map.end())
|
||||
{
|
||||
f = vi->second;
|
||||
var_map.erase(f);
|
||||
var_formula_map.erase(vi);
|
||||
}
|
||||
else
|
||||
{
|
||||
vi = now_formula_map.find(var);
|
||||
if (vi != now_formula_map.end())
|
||||
{
|
||||
f = vi->second;
|
||||
now_map.erase(f);
|
||||
now_formula_map.erase(vi);
|
||||
n = 2;
|
||||
bdd_setpair(next_to_now, var + 1, var + 1);
|
||||
bdd_setpair(now_to_next, var, var);
|
||||
}
|
||||
else
|
||||
{
|
||||
vi = acc_formula_map.find(var);
|
||||
f = vi->second;
|
||||
assert(vi != now_formula_map.end());
|
||||
acc_map.erase(f);
|
||||
acc_formula_map.erase(vi);
|
||||
}
|
||||
}
|
||||
// Actually release the associated BDD variables, and the
|
||||
// formula itself.
|
||||
release_variables(var, n);
|
||||
ltl::destroy(f);
|
||||
var_refs.erase(cur);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
bdd_dict::is_registered(const ltl::formula* f, const void* by_me)
|
||||
{
|
||||
int var;
|
||||
fv_map::iterator fi = var_map.find(f);
|
||||
if (fi != var_map.end())
|
||||
{
|
||||
var = fi->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
fi = now_map.find(f);
|
||||
if (fi != now_map.end())
|
||||
{
|
||||
var = fi->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
fi = acc_map.find(f);
|
||||
if (fi == acc_map.end())
|
||||
return false;
|
||||
var = fi->second;
|
||||
}
|
||||
}
|
||||
ref_set& s = var_refs[var];
|
||||
return s.find(by_me) != s.end();
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
bdd_dict::dump(std::ostream& os) const
|
||||
{
|
||||
fv_map::const_iterator fi;
|
||||
os << "Atomic Propositions:" << std::endl;
|
||||
for (fi = var_map.begin(); fi != var_map.end(); ++fi)
|
||||
{
|
||||
os << " " << fi->second << " (x"
|
||||
<< var_refs.find(fi->second)->second.size() << "): ";
|
||||
to_string(fi->first, os) << std::endl;
|
||||
}
|
||||
os << "States:" << std::endl;
|
||||
for (fi = now_map.begin(); fi != now_map.end(); ++fi)
|
||||
{
|
||||
int refs = var_refs.find(fi->second)->second.size();
|
||||
os << " " << fi->second << " (x" << refs << "): Now[";
|
||||
to_string(fi->first, os) << "]" << std::endl;
|
||||
os << " " << fi->second + 1 << " (x" << refs << "): Next[";
|
||||
to_string(fi->first, os) << "]" << std::endl;
|
||||
}
|
||||
os << "Accepting Conditions:" << std::endl;
|
||||
for (fi = acc_map.begin(); fi != acc_map.end(); ++fi)
|
||||
{
|
||||
os << " " << fi->second << " (x"
|
||||
<< var_refs.find(fi->second)->second.size() << "): Acc[";
|
||||
to_string(fi->first, os) << "]" << std::endl;
|
||||
}
|
||||
os << "Free list:" << std::endl;
|
||||
free_list_type::const_iterator i;
|
||||
for (i = free_list.begin(); i != free_list.end(); ++i)
|
||||
os << " (" << i->first << ", " << i->second << ")";
|
||||
os << std::endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
void
|
||||
bdd_dict::assert_emptiness() const
|
||||
{
|
||||
bool fail = false;
|
||||
if (var_map.empty()
|
||||
&& now_map.empty()
|
||||
&& acc_map.empty())
|
||||
{
|
||||
if (! var_formula_map.empty())
|
||||
{
|
||||
std::cerr << "var_map is empty but var_formula_map is not"
|
||||
<< std::endl;
|
||||
fail = true;
|
||||
}
|
||||
if (! now_formula_map.empty())
|
||||
{
|
||||
std::cerr << "now_map is empty but now_formula_map is not"
|
||||
<< std::endl;
|
||||
fail = true;
|
||||
}
|
||||
if (! acc_formula_map.empty())
|
||||
{
|
||||
std::cerr << "acc_map is empty but acc_formula_map is not"
|
||||
<< std::endl;
|
||||
fail = true;
|
||||
}
|
||||
if (! var_refs.empty())
|
||||
{
|
||||
std::cerr << "maps are empty but var_refs is not" << std::endl;
|
||||
fail = true;
|
||||
vr_map::const_iterator i;
|
||||
for (i = var_refs.begin(); i != var_refs.end(); ++i)
|
||||
std::cerr << " " << i->first << ":" << i->second.size();
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
if (! fail)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "some maps are not empty" << std::endl;
|
||||
}
|
||||
dump(std::cerr);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue