remove_alternation: use edge_separator
* spot/twaalgos/split.cc, spot/twaalgos/split.hh (edge_separator::add_to_basis): Add a variant that is limited in the number of labels it adds. * spot/twaalgos/alternation.cc: Use it. Also add a cache of separated edges, as in the split.
This commit is contained in:
parent
3bcffa2fcd
commit
c220107eb4
3 changed files with 82 additions and 33 deletions
|
|
@ -21,6 +21,8 @@
|
|||
#include <sstream>
|
||||
#include <spot/twaalgos/alternation.hh>
|
||||
#include <spot/twaalgos/sccinfo.hh>
|
||||
#include <spot/twaalgos/split.hh>
|
||||
#include <spot/priv/robin_hood.hh>
|
||||
#include <spot/misc/minato.hh>
|
||||
#include <spot/misc/bddlt.hh>
|
||||
|
||||
|
|
@ -389,37 +391,12 @@ namespace spot
|
|||
bool will_use_labels = n_ap > 5;
|
||||
if (will_use_labels)
|
||||
{
|
||||
std::set<bdd, bdd_less_than> all_labels;
|
||||
edge_separator es;
|
||||
// Gather all labels, but stop if we see too many.
|
||||
// The threshold below is arbitrary.
|
||||
unsigned max_labels = 100 * n_ap;
|
||||
for (auto& e: aut_->edges())
|
||||
{
|
||||
if (all_labels.insert(e.cond).second)
|
||||
if (all_labels.size() > max_labels)
|
||||
{
|
||||
will_use_labels = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
will_use_labels = es.add_to_basis(aut_, 256 * n_ap);
|
||||
if (will_use_labels)
|
||||
{
|
||||
separated_labels.reserve(all_labels.size());
|
||||
separated_labels.push_back(bddtrue);
|
||||
for (auto& lab: all_labels)
|
||||
{
|
||||
// Do not use a range-based or iterator-based for loop
|
||||
// here, as push_back invalidates the end iterator.
|
||||
for (unsigned cur = 0, sz = separated_labels.size();
|
||||
cur < sz; ++cur)
|
||||
if (bdd common = separated_labels[cur] & lab;
|
||||
common != bddfalse && common != separated_labels[cur])
|
||||
{
|
||||
separated_labels[cur] -= lab;
|
||||
separated_labels.push_back(common);
|
||||
}
|
||||
}
|
||||
}
|
||||
separated_labels = es.basis();
|
||||
}
|
||||
|
||||
// We for easier computation of outgoing sets, we will
|
||||
|
|
@ -490,6 +467,19 @@ namespace spot
|
|||
|
||||
acc_cond::mark_t all_marks = res->acc().all_sets();
|
||||
|
||||
// We use a cache to avoid the costly loop around
|
||||
// separated_labels.
|
||||
//
|
||||
// Cache entries have the form (bdd, [begin, end]) where bdd
|
||||
// what should be split, and begin/end denotes a range of
|
||||
// existing transition numbers that cover the split.
|
||||
//
|
||||
// std::pair causes some noexcept warnings when used in
|
||||
// robin_hood::unordered_map with GCC 9.4. Use robin_hood::pair
|
||||
// instead.
|
||||
typedef robin_hood::pair<unsigned, unsigned> cached_t;
|
||||
robin_hood::unordered_map<bdd, cached_t, bdd_hash> split_cond;
|
||||
|
||||
state_set v;
|
||||
while (!todo.empty())
|
||||
{
|
||||
|
|
@ -547,12 +537,41 @@ namespace spot
|
|||
};
|
||||
|
||||
if (!will_use_labels)
|
||||
// Loop over all possible valuations atomic properties.
|
||||
for (bdd oneletter: minterms_of(all_letters, ap))
|
||||
create_edges(oneletter, bdd_restrict(bs, oneletter));
|
||||
{
|
||||
// Loop over all possible valuations of atomic properties.
|
||||
for (bdd oneletter: minterms_of(all_letters, ap))
|
||||
create_edges(oneletter, bdd_restrict(bs, oneletter));
|
||||
}
|
||||
else
|
||||
for (bdd label: separated_labels)
|
||||
create_edges(label, bdd_relprod(label, bs, res->ap_vars()));
|
||||
{
|
||||
auto& [begin, end] = split_cond[all_letters];
|
||||
if (begin == end)
|
||||
{
|
||||
begin = res->num_edges() + 1;
|
||||
for (bdd label: separated_labels)
|
||||
create_edges(label, bdd_relprod(label, bs,
|
||||
res->ap_vars()));
|
||||
end = res->num_edges() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have already split all_letters once, so we
|
||||
// can simply reuse the set of labels we used
|
||||
// then, avoiding the iteration on
|
||||
// separated_labels.
|
||||
auto& g = res->get_graph();
|
||||
bdd last = bddfalse;
|
||||
for (unsigned i = begin; i < end; ++i)
|
||||
{
|
||||
bdd label = g.edge_storage(i).cond;
|
||||
if (label == last)
|
||||
continue;
|
||||
last = label;
|
||||
create_edges(label, bdd_relprod(label, bs,
|
||||
res->ap_vars()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res->merge_edges();
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -118,6 +118,23 @@ namespace spot
|
|||
add_to_basis(lab);
|
||||
}
|
||||
|
||||
bool edge_separator::add_to_basis(const const_twa_graph_ptr& aut,
|
||||
unsigned long max_label)
|
||||
{
|
||||
std::set<bdd, bdd_less_than> all_labels;
|
||||
for (auto& e: aut->edges())
|
||||
{
|
||||
if (all_labels.insert(e.cond).second)
|
||||
if (max_label-- == 0)
|
||||
return false;
|
||||
}
|
||||
for (bdd lab: all_labels)
|
||||
add_to_basis(lab);
|
||||
for (formula f: aut->ap())
|
||||
aps_.insert(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
twa_graph_ptr
|
||||
edge_separator::separate_implying(const const_twa_graph_ptr& aut)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -156,9 +156,15 @@ namespace spot
|
|||
/// add_to_basis() and add a new atomic proposition, you should
|
||||
/// remember to register it in the result of separate_implying()
|
||||
/// or separate_compat() yourself.
|
||||
///
|
||||
/// If \a max_label is given, at most \a max_label unique labels
|
||||
/// are added to the basis. False is returned iff the automaton
|
||||
/// used more labels.
|
||||
/// @{
|
||||
void add_to_basis(bdd label);
|
||||
void add_to_basis(const const_twa_graph_ptr& aut);
|
||||
bool add_to_basis(const const_twa_graph_ptr& aut,
|
||||
unsigned long max_label);
|
||||
/// @}
|
||||
/// \brief Separate an automaton
|
||||
///
|
||||
|
|
@ -200,10 +206,17 @@ namespace spot
|
|||
return {basis_, label};
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned basis_size() const
|
||||
{
|
||||
return basis_.size();
|
||||
}
|
||||
|
||||
const std::vector<bdd>& basis() const
|
||||
{
|
||||
return basis_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<bdd> basis_{bddtrue};
|
||||
std::set<formula> aps_;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue