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 <sstream>
|
||||||
#include <spot/twaalgos/alternation.hh>
|
#include <spot/twaalgos/alternation.hh>
|
||||||
#include <spot/twaalgos/sccinfo.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/minato.hh>
|
||||||
#include <spot/misc/bddlt.hh>
|
#include <spot/misc/bddlt.hh>
|
||||||
|
|
||||||
|
|
@ -389,37 +391,12 @@ namespace spot
|
||||||
bool will_use_labels = n_ap > 5;
|
bool will_use_labels = n_ap > 5;
|
||||||
if (will_use_labels)
|
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.
|
// Gather all labels, but stop if we see too many.
|
||||||
// The threshold below is arbitrary.
|
// The threshold below is arbitrary.
|
||||||
unsigned max_labels = 100 * n_ap;
|
will_use_labels = es.add_to_basis(aut_, 256 * 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (will_use_labels)
|
if (will_use_labels)
|
||||||
{
|
separated_labels = es.basis();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We for easier computation of outgoing sets, we will
|
// 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();
|
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;
|
state_set v;
|
||||||
while (!todo.empty())
|
while (!todo.empty())
|
||||||
{
|
{
|
||||||
|
|
@ -547,12 +537,41 @@ namespace spot
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!will_use_labels)
|
if (!will_use_labels)
|
||||||
// Loop over all possible valuations atomic properties.
|
{
|
||||||
for (bdd oneletter: minterms_of(all_letters, ap))
|
// Loop over all possible valuations of atomic properties.
|
||||||
create_edges(oneletter, bdd_restrict(bs, oneletter));
|
for (bdd oneletter: minterms_of(all_letters, ap))
|
||||||
|
create_edges(oneletter, bdd_restrict(bs, oneletter));
|
||||||
|
}
|
||||||
else
|
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();
|
res->merge_edges();
|
||||||
return res;
|
return res;
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,23 @@ namespace spot
|
||||||
add_to_basis(lab);
|
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
|
twa_graph_ptr
|
||||||
edge_separator::separate_implying(const const_twa_graph_ptr& aut)
|
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
|
/// add_to_basis() and add a new atomic proposition, you should
|
||||||
/// remember to register it in the result of separate_implying()
|
/// remember to register it in the result of separate_implying()
|
||||||
/// or separate_compat() yourself.
|
/// 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(bdd label);
|
||||||
void add_to_basis(const const_twa_graph_ptr& aut);
|
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
|
/// \brief Separate an automaton
|
||||||
///
|
///
|
||||||
|
|
@ -200,10 +206,17 @@ namespace spot
|
||||||
return {basis_, label};
|
return {basis_, label};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned basis_size() const
|
unsigned basis_size() const
|
||||||
{
|
{
|
||||||
return basis_.size();
|
return basis_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<bdd>& basis() const
|
||||||
|
{
|
||||||
|
return basis_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<bdd> basis_{bddtrue};
|
std::vector<bdd> basis_{bddtrue};
|
||||||
std::set<formula> aps_;
|
std::set<formula> aps_;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue