Commit ba5bddec authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

degen: use the initial state heuristic when entering SCCs

* src/tgbaalgos/degen.cc: Implement it.
* src/tgbatest/degenid.test: New test cases.
parent 3eb993e2
......@@ -155,6 +155,50 @@ namespace spot
}
};
// Check whether a state has an accepting self-loop, with a catch.
class has_acc_loop
{
const tgba* a_;
typedef Sgi::hash_map<const state*, bool,
state_ptr_hash, state_ptr_equal> cache_t;
cache_t cache_;
unicity_table uniq_;
public:
has_acc_loop(const tgba* a, unicity_table& uniq):
a_(a),
uniq_(uniq)
{
}
bool check(const state* s)
{
std::pair<cache_t::iterator, bool> p =
cache_.insert(std::make_pair(s, false));
if (p.second)
{
bdd all = a_->all_acceptance_conditions();
tgba_succ_iterator* it = a_->succ_iter(s);
for (it->first(); !it->done(); it->next())
{
// Look only for transitions that are accepting.
if (all != it->current_acceptance_conditions())
continue;
// Look only for self-loops.
const state* dest = uniq_(it->current_state());
if (dest == s)
{
p.first->second = true;
break;
}
}
delete it;
}
return p.first->second;
}
};
// Order of accepting sets (for one SCC)
class acc_order
{
......@@ -287,6 +331,9 @@ namespace spot
// from the input automaton.
unicity_table uniq;
// Accepting loop checker, for some heuristics.
has_acc_loop acc_loop(a, uniq);
// These maps make it possible to convert degen_state to number
// and vice-versa.
ds2num_map ds2num;
......@@ -305,7 +352,7 @@ namespace spot
// Compute SCCs in order to use any optimization.
scc_map m(a);
if (use_cust_acc_orders || use_lvl_cache || use_z_lvl)
if (use_scc)
m.build_map();
queue_t todo;
......@@ -315,25 +362,8 @@ namespace spot
// As an heuristic, if the initial state at least one accepting
// self-loop, start the degeneralization on the accepting level.
{
bdd all = a->all_acceptance_conditions();
tgba_succ_iterator* it = a->succ_iter(s0);
for (it->first(); !it->done(); it->next())
{
// Look only for transitions that are accepting.
if (all != it->current_acceptance_conditions())
continue;
// Look only for self-loops.
const state* dest = uniq(it->current_state());
if (dest == s0)
{
// The initial state has an accepting self-loop.
s.second = order.size();
break;
}
}
delete it;
}
if (acc_loop.check(s0))
s.second = order.size();
// Otherwise, check for acceptance conditions common to all
// outgoing transitions, and assume we have already seen these and
// start on the associated level.
......@@ -394,7 +424,6 @@ namespace spot
if (names.find(d.first) == names.end())
names[d.first] = uniq.size();
#endif
// Check whether the target SCC is accepting
bool is_scc_acc;
int scc;
......@@ -483,11 +512,6 @@ namespace spot
// }
if (is_scc_acc)
{
acc |= otheracc;
// If use_z_lvl is on, start with level zero 0 when
// swhitching SCCs
unsigned next = (!use_z_lvl || s_scc == scc) ? slevel : 0;
// If lvl_cache is used and switching SCCs, use level from cache
if (use_lvl_cache && s_scc != scc
&& lvl_cache.find(d.first) != lvl_cache.end())
......@@ -496,20 +520,45 @@ namespace spot
}
else
{
// Complete (or replace) the acceptance sets of
// this link with the acceptance sets common to
// all transitions leaving the destination state.
if (s_scc == scc)
acc |= otheracc;
else
acc = otheracc;
// If use_z_lvl is on, start with level zero 0 when
// swhitching SCCs
unsigned next = (!use_z_lvl || s_scc == scc) ? slevel : 0;
// If using custom acc orders, get next level for this scc
if (use_cust_acc_orders)
d.second = orders.next_level(scc, next, acc);
{
d.second = orders.next_level(scc, next, acc);
}
// Else compute level according the global acc order
else
{
// Consider both the current acceptance sets, and the
// acceptance sets common to the outgoing transitions of
// the destination state.
while (next < order.size()
&& bdd_implies(order[next], acc))
++next;
d.second = next;
// As a heuristic, if we enter the SCC on a
// state that has at least one accepting
// self-loop, start the degeneralization on
// the accepting level.
if (s_scc != scc && acc_loop.check(d.first))
{
d.second = order.size();
}
else
{
// Consider both the current acceptance
// sets, and the acceptance sets common to
// the outgoing transitions of the
// destination state.
while (next < order.size()
&& bdd_implies(order[next], acc))
++next;
d.second = next;
}
}
}
}
......
......@@ -65,3 +65,41 @@ EOF
run 0 ../ltl2tgba -ks -X -DS bug > out
grep 'states: 6' out
# This 8-state degeneralized automaton used
# to be "degeneralized" to a 9-state BA...
cat > bug2 <<EOF
acc = "1";
"1", "2", "1",;
"2", "3", "1", "1";
"3", "3", "a & !b",;
"3", "4", "a & b",;
"3", "5", "!a & !b",;
"3", "6", "b & !a",;
"4", "3", "a", "1";
"4", "5", "!a", "1";
"5", "3", "a & !b",;
"5", "4", "a & b",;
"5", "6", "b & !a",;
"5", "7", "!a & !b",;
"6", "3", "a & !b", "1";
"6", "4", "a & b", "1";
"6", "6", "b & !a", "1";
"6", "7", "!a & !b", "1";
"7", "3", "a & !b",;
"7", "4", "a & b",;
"7", "8", "b & !a",;
"7", "7", "!a & !b",;
"8", "4", "a",;
"8", "8", "!a",;
EOF
run 0 ../ltl2tgba -ks -X -DS bug2 >out
grep 'states: 8' out
# This automaton should have a 3-state BA, but it's really
# easy to obtain a 4-state BA when tweaking the degeneralization
# to ignore arc entering an SCC.
test 3 = "`../../bin/ltl2tgba -B 'G(a|G(b|Fc))' --stats=%s`"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment