degen: use the initial state heuristic when entering SCCs
* src/tgbaalgos/degen.cc: Implement it. * src/tgbatest/degenid.test: New test cases.
This commit is contained in:
parent
3eb993e224
commit
ba5bddec78
2 changed files with 122 additions and 35 deletions
|
|
@ -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)
|
// Order of accepting sets (for one SCC)
|
||||||
class acc_order
|
class acc_order
|
||||||
{
|
{
|
||||||
|
|
@ -287,6 +331,9 @@ namespace spot
|
||||||
// from the input automaton.
|
// from the input automaton.
|
||||||
unicity_table uniq;
|
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
|
// These maps make it possible to convert degen_state to number
|
||||||
// and vice-versa.
|
// and vice-versa.
|
||||||
ds2num_map ds2num;
|
ds2num_map ds2num;
|
||||||
|
|
@ -305,7 +352,7 @@ namespace spot
|
||||||
|
|
||||||
// Compute SCCs in order to use any optimization.
|
// Compute SCCs in order to use any optimization.
|
||||||
scc_map m(a);
|
scc_map m(a);
|
||||||
if (use_cust_acc_orders || use_lvl_cache || use_z_lvl)
|
if (use_scc)
|
||||||
m.build_map();
|
m.build_map();
|
||||||
|
|
||||||
queue_t todo;
|
queue_t todo;
|
||||||
|
|
@ -315,25 +362,8 @@ namespace spot
|
||||||
|
|
||||||
// As an heuristic, if the initial state at least one accepting
|
// As an heuristic, if the initial state at least one accepting
|
||||||
// self-loop, start the degeneralization on the accepting level.
|
// self-loop, start the degeneralization on the accepting level.
|
||||||
{
|
if (acc_loop.check(s0))
|
||||||
bdd all = a->all_acceptance_conditions();
|
s.second = order.size();
|
||||||
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;
|
|
||||||
}
|
|
||||||
// Otherwise, check for acceptance conditions common to all
|
// Otherwise, check for acceptance conditions common to all
|
||||||
// outgoing transitions, and assume we have already seen these and
|
// outgoing transitions, and assume we have already seen these and
|
||||||
// start on the associated level.
|
// start on the associated level.
|
||||||
|
|
@ -394,7 +424,6 @@ namespace spot
|
||||||
if (names.find(d.first) == names.end())
|
if (names.find(d.first) == names.end())
|
||||||
names[d.first] = uniq.size();
|
names[d.first] = uniq.size();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Check whether the target SCC is accepting
|
// Check whether the target SCC is accepting
|
||||||
bool is_scc_acc;
|
bool is_scc_acc;
|
||||||
int scc;
|
int scc;
|
||||||
|
|
@ -483,11 +512,6 @@ namespace spot
|
||||||
// }
|
// }
|
||||||
if (is_scc_acc)
|
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 lvl_cache is used and switching SCCs, use level from cache
|
||||||
if (use_lvl_cache && s_scc != scc
|
if (use_lvl_cache && s_scc != scc
|
||||||
&& lvl_cache.find(d.first) != lvl_cache.end())
|
&& lvl_cache.find(d.first) != lvl_cache.end())
|
||||||
|
|
@ -496,20 +520,45 @@ namespace spot
|
||||||
}
|
}
|
||||||
else
|
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 using custom acc orders, get next level for this scc
|
||||||
if (use_cust_acc_orders)
|
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 compute level according the global acc order
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Consider both the current acceptance sets, and the
|
// As a heuristic, if we enter the SCC on a
|
||||||
// acceptance sets common to the outgoing transitions of
|
// state that has at least one accepting
|
||||||
// the destination state.
|
// self-loop, start the degeneralization on
|
||||||
while (next < order.size()
|
// the accepting level.
|
||||||
&& bdd_implies(order[next], acc))
|
if (s_scc != scc && acc_loop.check(d.first))
|
||||||
++next;
|
{
|
||||||
|
d.second = order.size();
|
||||||
d.second = next;
|
}
|
||||||
|
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
|
run 0 ../ltl2tgba -ks -X -DS bug > out
|
||||||
grep 'states: 6' 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`"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue