graph: store the source indices in the transition vector
... and use it to sort transitions. * src/graph/graph.hh: Adjust storage of source index. Provide remove_dead_transitions_(), sort_transitions_() and chain_transitions_() methods. * src/tgba/tgbagraph.cc (merge_transitions): Rewrite using above methods. * src/tgba/tgbagraph.hh: Add a comparison operator for transitions. * src/tgbatest/degenlskip.test, src/tgbatest/det.test, src/tgbatest/ltl2ta.test, src/tgbatest/neverclaimread.test, src/tgbatest/readsave.test: Adjust expected transition order in test cases.
This commit is contained in:
parent
80ce0e2129
commit
0db0eca14e
8 changed files with 201 additions and 80 deletions
|
|
@ -25,41 +25,62 @@ namespace spot
|
|||
|
||||
void tgba_digraph::merge_transitions()
|
||||
{
|
||||
// Map a pair (dest state, acc) to the first transition seen
|
||||
// with such characteristic.
|
||||
typedef std::pair<graph_t::state, acc_cond::mark_t> key_t;
|
||||
std::unordered_map<key_t, graph_t::transition, pair_hash> trmap;
|
||||
for (auto& s: g_.states())
|
||||
g_.remove_dead_transitions_();
|
||||
|
||||
typedef graph_t::trans_storage_t tr_t;
|
||||
g_.sort_transitions_([](const tr_t& lhs, const tr_t& rhs)
|
||||
{
|
||||
if (lhs.src < rhs.src)
|
||||
return true;
|
||||
if (lhs.src > rhs.src)
|
||||
return false;
|
||||
if (lhs.dst < rhs.dst)
|
||||
return true;
|
||||
if (lhs.dst > rhs.dst)
|
||||
return false;
|
||||
return lhs.acc < rhs.acc;
|
||||
// Do not sort on conditions, we'll merge
|
||||
// them.
|
||||
});
|
||||
|
||||
auto& trans = this->transitions();
|
||||
unsigned tend = trans.size();
|
||||
unsigned out = 0;
|
||||
unsigned in = 1;
|
||||
// Skip any leading false transition.
|
||||
while (in < tend && trans[in].cond == bddfalse)
|
||||
++in;
|
||||
if (in < tend)
|
||||
{
|
||||
// Get a clear map for each state.
|
||||
trmap.clear();
|
||||
|
||||
auto t = g_.out_iteraser(s);
|
||||
while (t)
|
||||
++out;
|
||||
if (out != in)
|
||||
trans[out] = trans[in];
|
||||
for (++in; in < tend; ++in)
|
||||
{
|
||||
// Simply skip false transitions.
|
||||
if (t->cond == bddfalse)
|
||||
if (trans[in].cond == bddfalse) // Unusable transition
|
||||
continue;
|
||||
// Merge transitions with the same source, destination, and
|
||||
// acceptance. (We test the source last, because this is the
|
||||
// most likely test to be true as transitions are ordered by
|
||||
// sources and then destinations.)
|
||||
if (trans[out].dst == trans[in].dst
|
||||
&& trans[out].acc == trans[in].acc
|
||||
&& trans[out].src == trans[in].src)
|
||||
{
|
||||
t.erase();
|
||||
continue;
|
||||
}
|
||||
|
||||
key_t k(t->dst, t->acc);
|
||||
auto p = trmap.emplace(k, t.trans());
|
||||
if (!p.second)
|
||||
{
|
||||
// A previous transitions exists for k. Merge the
|
||||
// condition, and schedule the transition for removal.
|
||||
g_.trans_data(p.first->second).cond |= t->cond;
|
||||
t.erase();
|
||||
trans[out].cond |= trans[in].cond;
|
||||
}
|
||||
else
|
||||
{
|
||||
++t;
|
||||
++out;
|
||||
if (in != out)
|
||||
trans[out] = trans[in];
|
||||
}
|
||||
}
|
||||
}
|
||||
g_.defrag();
|
||||
if (++out != tend)
|
||||
trans.resize(out);
|
||||
|
||||
g_.chain_transitions_();
|
||||
}
|
||||
|
||||
void tgba_digraph::purge_unreachable_states()
|
||||
|
|
|
|||
|
|
@ -87,6 +87,15 @@ namespace spot
|
|||
: cond(cond), acc(acc)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const tgba_graph_trans_data& other) const
|
||||
{
|
||||
if (cond.id() < other.cond.id())
|
||||
return true;
|
||||
if (cond.id() > other.cond.id())
|
||||
return false;
|
||||
return acc < other.acc;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue