acd: add ORDER_HEURISTIC for state-based ACD-transform
* spot/twaalgos/zlktree.cc, spot/twaalgos/zlktree.hh: Add the acd_options::ORDER_HEURISTIC and use it by default in acd_transform_sbacc(). * spot/misc/bitvect.hh (bitvect::count, bitvect::add_common): New methods. * tests/python/zlktree.ipynb: Adjust examples and discuss this heuristic.
This commit is contained in:
parent
70ede35702
commit
fea0be96c1
4 changed files with 1655 additions and 554 deletions
|
|
@ -255,6 +255,16 @@ namespace spot
|
|||
return *this;
|
||||
}
|
||||
|
||||
bitvect& add_common(const bitvect& other1, const bitvect& other2)
|
||||
{
|
||||
SPOT_ASSERT(other1.size_ <= size_ && other2.size_ <= size_);
|
||||
unsigned m = std::min(other2.block_count_,
|
||||
std::min(other1.block_count_, block_count_));
|
||||
for (size_t i = 0; i < m; ++i)
|
||||
storage_[i] |= other1.storage_[i] & other2.storage_[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool intersects(const bitvect& other)
|
||||
{
|
||||
SPOT_ASSERT(other.size_ <= size_);
|
||||
|
|
@ -302,6 +312,32 @@ namespace spot
|
|||
== (storage_[i] & mask));
|
||||
}
|
||||
|
||||
unsigned count() const
|
||||
{
|
||||
size_t i;
|
||||
const size_t bpb = 8 * sizeof(bitvect::block_t);
|
||||
size_t rest = size() % bpb;
|
||||
size_t c = 0;
|
||||
for (i = 0; i < block_count_; ++i)
|
||||
{
|
||||
block_t v = storage_[i];
|
||||
if ((i == block_count_ - 1) && rest)
|
||||
// The last block might not be fully used, scan only the
|
||||
// relevant portion.
|
||||
v &= (1UL << rest) - 1;
|
||||
#ifdef __GNUC__
|
||||
c += __builtin_popcountl(v);
|
||||
#else
|
||||
while (v)
|
||||
{
|
||||
++c;
|
||||
v &= v - 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
bool operator==(const bitvect& other) const
|
||||
{
|
||||
if (other.size_ != size_)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "config.h"
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
#include <spot/twaalgos/zlktree.hh>
|
||||
#include <spot/twaalgos/genem.hh>
|
||||
#include <spot/misc/escape.hh>
|
||||
|
|
@ -439,6 +440,15 @@ namespace spot
|
|||
};
|
||||
std::vector<size_model> out;
|
||||
|
||||
std::unique_ptr<bitvect> seen_src;
|
||||
std::unique_ptr<bitvect> seen_dst;
|
||||
std::unique_ptr<bitvect> seen_dup;
|
||||
if (!!(opt_ & acd_options::ORDER_HEURISTIC))
|
||||
{
|
||||
seen_src.reset(make_bitvect(nstates));
|
||||
seen_dst.reset(make_bitvect(nstates));
|
||||
seen_dup.reset(make_bitvect(nstates));
|
||||
}
|
||||
// This loop is a BFS over the increasing set of nodes.
|
||||
for (unsigned node = 0; node < nodes_.size(); ++node)
|
||||
{
|
||||
|
|
@ -483,9 +493,55 @@ namespace spot
|
|||
accepting_node ? negacc : posacc,
|
||||
nodes_[node].edges, callback);
|
||||
|
||||
if (!!(opt_ & acd_options::ORDER_HEURISTIC))
|
||||
{
|
||||
// Find states that appear in multiple children
|
||||
seen_dup->clear_all(); // duplicate states
|
||||
seen_src->clear_all(); // union of all children states
|
||||
for (auto& [sz, bv]: out)
|
||||
{
|
||||
seen_dst->clear_all(); // local states of the node
|
||||
bv->foreach_set_index([&aut, &seen_dst](unsigned e)
|
||||
{
|
||||
seen_dst->set(aut->edge_storage(e).src);
|
||||
});
|
||||
seen_dup->add_common(*seen_src, *seen_dst);
|
||||
*seen_src |= *seen_dst;
|
||||
}
|
||||
// Now the union in seen_src is not useful anymore. Process
|
||||
// each node again, but consider only the states that are in
|
||||
// seen_dup.
|
||||
for (auto& [sz, bv]: out)
|
||||
{
|
||||
seen_src->clear_all(); // local source of the node
|
||||
bv->foreach_set_index([&aut, &seen_src, &seen_dup](unsigned e)
|
||||
{
|
||||
unsigned idx = aut->edge_storage(e).src;
|
||||
if (seen_dup->get(idx))
|
||||
seen_src->set(idx); // store duplicates
|
||||
});
|
||||
seen_dst->clear_all();
|
||||
// Count the number of states reached by leaving this node.
|
||||
seen_src->foreach_set_index([&aut, bv=bv.get(),
|
||||
&seen_dst](unsigned s)
|
||||
{
|
||||
for (auto& e: aut->out(s))
|
||||
if (!bv->get(aut->edge_number(e)))
|
||||
seen_dst->set(e.dst);
|
||||
});
|
||||
sz = seen_dst->count();
|
||||
}
|
||||
// reorder by decreasing number of new states reached
|
||||
std::stable_sort(out.begin(), out.end(),
|
||||
[&](auto& p1, auto& p2) {
|
||||
return p1.size > p2.size;
|
||||
});
|
||||
}
|
||||
|
||||
unsigned before_size = nodes_.size();
|
||||
for (const auto& [sz, bv]: out)
|
||||
{
|
||||
(void)sz;
|
||||
unsigned vnum = trees_[scc].num_nodes++;
|
||||
allocate_vectors_maybe(vnum);
|
||||
nodes_.emplace_back(edge_vector(vnum), state_vector(vnum));
|
||||
|
|
@ -877,12 +933,13 @@ namespace spot
|
|||
// ACD, to
|
||||
template<bool sbacc>
|
||||
twa_graph_ptr
|
||||
acd_transform_(const const_twa_graph_ptr& a, bool colored)
|
||||
acd_transform_(const const_twa_graph_ptr& a, bool colored,
|
||||
acd_options options = acd_options::NONE)
|
||||
{
|
||||
auto res = make_twa_graph(a->get_dict());
|
||||
res->copy_ap_of(a);
|
||||
scc_info si(a, scc_info_options::TRACK_STATES);
|
||||
acd theacd(si);
|
||||
acd theacd(si, options);
|
||||
|
||||
// If we desire non-colored output, we can omit the maximal
|
||||
// color of each SCC if it has the same parity as max_level.
|
||||
|
|
@ -1022,9 +1079,12 @@ namespace spot
|
|||
}
|
||||
|
||||
twa_graph_ptr
|
||||
acd_transform_sbacc(const const_twa_graph_ptr& a, bool colored)
|
||||
acd_transform_sbacc(const const_twa_graph_ptr& a, bool colored,
|
||||
bool order_heuristic)
|
||||
{
|
||||
return acd_transform_<true>(a, colored);
|
||||
return acd_transform_<true>(a, colored, order_heuristic
|
||||
? acd_options::ORDER_HEURISTIC
|
||||
: acd_options::NONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,6 +167,11 @@ namespace spot
|
|||
/// shape that is tested. When that happens, node_count() is set
|
||||
/// to 0.
|
||||
ABORT_WRONG_SHAPE = 4,
|
||||
/// Order the children of a node by decreasing size of the number
|
||||
/// of states they would introduce if that child appears as the
|
||||
/// last child of an "ACD" round in the state-based version of the
|
||||
/// ACD output.
|
||||
ORDER_HEURISTIC = 8,
|
||||
};
|
||||
|
||||
#ifndef SWIG
|
||||
|
|
@ -407,13 +412,15 @@ namespace spot
|
|||
/// optimal transition-based output (optimal in the sense of least
|
||||
/// number of duplicated states), while the acd_tansform_sbacc() variant
|
||||
/// produces state-based output from transition-based input and without
|
||||
/// any optimality claim.
|
||||
/// any optimality claim. The \a order_heuristics argument, enabled
|
||||
/// by default activates the ORDER_HEURISTICS option of the ACD.
|
||||
/// @{
|
||||
SPOT_API
|
||||
twa_graph_ptr acd_transform(const const_twa_graph_ptr& aut,
|
||||
bool colored = false);
|
||||
SPOT_API
|
||||
twa_graph_ptr acd_transform_sbacc(const const_twa_graph_ptr& aut,
|
||||
bool colored = false);
|
||||
bool colored = false,
|
||||
bool order_heuristic = true);
|
||||
/// @}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue