* src/tgbaalgos/tarjan_on_fly.hh,
src/tgbaalgos/tarjan_on_fly.cc, src/tgbaalgos/nesteddfs.hh, src/tgbaalgos/nesteddfs.cc, src/tgbaalgos/minimalce.hh, src/tgbaalgos/minimalce.cc, src/tgbaalgos/colordfs.hh, src/tgbaalgos/colordfs.cc: four new algorithms for emptyness check. src/tgbaalgos/gtec/ce.hh, src/tgbaalgos/gtec/ce.cc: Adapt the counter exemple for the ce object in minimalce.hh. src/tgbatest/ltl2tgba.cc, src/tgbatest/emptchk.test, src/tgbaalgos/Makefile.am: Add files for emptyness-check. * src/tgbaalgos/reductgba_sim_del.cc: Restrict to degeneralize automata. * src/tgba/tgbareduc.hh: src/tgba/tgbareduc.cc: Merge transition for scc reduce.
This commit is contained in:
parent
3d2135c883
commit
2d1151e018
17 changed files with 2526 additions and 157 deletions
|
|
@ -35,6 +35,8 @@ namespace spot
|
|||
eccf)
|
||||
: ecs_(ecs)
|
||||
{
|
||||
counter_ = new ce::counter_example(ecs->aut);
|
||||
|
||||
assert(!ecs_->root.empty());
|
||||
assert(suffix.empty());
|
||||
|
||||
|
|
@ -76,6 +78,10 @@ namespace spot
|
|||
assert(spi.first);
|
||||
suffix.push_front(spi.first);
|
||||
|
||||
/////
|
||||
counter_->prefix.push_front(ce::state_ce(spi.first->clone(), bddfalse));
|
||||
////
|
||||
|
||||
// We build a path trough each SCC in the stack. For the
|
||||
// first SCC, the starting state is the initial state of the
|
||||
// automaton. The destination state is the closest state
|
||||
|
|
@ -113,21 +119,35 @@ namespace spot
|
|||
const state* h_dest = scc[k]->has_state(dest);
|
||||
if (!h_dest)
|
||||
{
|
||||
// If we have found a state in the next SCC.
|
||||
// If we have found a state in greater SCC which.
|
||||
// Unwind the path and populate SUFFIX.
|
||||
h_dest = scc[k+1]->has_state(dest);
|
||||
if (h_dest)
|
||||
{
|
||||
state_sequence seq;
|
||||
|
||||
///
|
||||
ce::l_state_ce seq_count;
|
||||
///
|
||||
|
||||
seq.push_front(h_dest);
|
||||
while (src->compare(start))
|
||||
{
|
||||
///
|
||||
seq_count.push_front(ce::state_ce(src->clone(), bddfalse));
|
||||
///
|
||||
|
||||
seq.push_front(src);
|
||||
src = father[src];
|
||||
}
|
||||
// Append SEQ to SUFFIX.
|
||||
suffix.splice(suffix.end(), seq);
|
||||
|
||||
///
|
||||
counter_->prefix.splice(counter_->prefix.end(),
|
||||
seq_count);
|
||||
///
|
||||
|
||||
// Exit this BFS for this SCC.
|
||||
while (!todo.empty())
|
||||
{
|
||||
|
|
@ -211,14 +231,27 @@ namespace spot
|
|||
if (h_dest == to)
|
||||
{
|
||||
cycle_path p;
|
||||
|
||||
///
|
||||
ce::l_state_ce p_counter;
|
||||
p_counter.push_front(ce::state_ce(h_dest->clone(), cond));
|
||||
///
|
||||
|
||||
p.push_front(state_proposition(h_dest, cond));
|
||||
while (src != from)
|
||||
{
|
||||
const state_proposition& psi = father[src];
|
||||
///
|
||||
p_counter.push_front(ce::state_ce(src->clone(), psi.second));
|
||||
///
|
||||
p.push_front(state_proposition(src, psi.second));
|
||||
src = psi.first;
|
||||
}
|
||||
period.splice(period.end(), p);
|
||||
///
|
||||
counter_->cycle.splice(counter_->cycle.end(),
|
||||
p_counter);
|
||||
///
|
||||
|
||||
// Exit the BFS, but release all iterators first.
|
||||
while (!todo.empty())
|
||||
|
|
@ -256,6 +289,9 @@ namespace spot
|
|||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
|
||||
void
|
||||
counter_example::accepting_path(const explicit_connected_component* scc,
|
||||
const state* start, bdd acc_to_traverse)
|
||||
|
|
@ -380,7 +416,12 @@ namespace spot
|
|||
// Append our best path to the period.
|
||||
for (cycle_path::iterator it = best_path.begin();
|
||||
it != best_path.end(); ++it)
|
||||
period.push_back(*it);
|
||||
{
|
||||
period.push_back(*it);
|
||||
ce::state_ce ce(it->first, it->second);
|
||||
counter_->cycle.push_back(ce);
|
||||
counter_->cycle.push_back(*it);
|
||||
}
|
||||
|
||||
// Prepare to find another path for the remaining acceptance
|
||||
// conditions.
|
||||
|
|
@ -393,6 +434,153 @@ namespace spot
|
|||
complete_cycle(scc, start, suffix.back());
|
||||
}
|
||||
|
||||
*/
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
counter_example::accepting_path(const explicit_connected_component* scc,
|
||||
const state* start, bdd acc_to_traverse)
|
||||
{
|
||||
// State seen during the DFS.
|
||||
typedef Sgi::hash_set<const state*,
|
||||
state_ptr_hash, state_ptr_equal> set_type;
|
||||
set_type seen;
|
||||
// DFS stack.
|
||||
std::stack<triplet> todo;
|
||||
|
||||
while (acc_to_traverse != bddfalse)
|
||||
{
|
||||
// Initial state.
|
||||
{
|
||||
tgba_succ_iterator* i = ecs_->aut->succ_iter(start);
|
||||
i->first();
|
||||
todo.push(triplet(start, i, bddfalse));
|
||||
seen.insert(start);
|
||||
}
|
||||
|
||||
// The path being explored currently.
|
||||
cycle_path path;
|
||||
// The best path seen so far.
|
||||
cycle_path best_path;
|
||||
// The acceptance conditions traversed by BEST_PATH.
|
||||
bdd best_acc = bddfalse;
|
||||
|
||||
while (!todo.empty())
|
||||
{
|
||||
tgba_succ_iterator* iter = todo.top().iter;
|
||||
const state* s = todo.top().s;
|
||||
|
||||
// Nothing more to explore, backtrack.
|
||||
if (iter->done())
|
||||
{
|
||||
todo.pop();
|
||||
delete iter;
|
||||
seen.erase(s);
|
||||
if (todo.size())
|
||||
{
|
||||
assert(path.size());
|
||||
path.pop_back();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// We must not escape the current SCC.
|
||||
const state* dest = iter->current_state();
|
||||
const state* h_dest = scc->has_state(dest);
|
||||
if (!h_dest)
|
||||
{
|
||||
delete dest;
|
||||
iter->next();
|
||||
continue;
|
||||
}
|
||||
|
||||
bdd acc = iter->current_acceptance_conditions() | todo.top().acc;
|
||||
path.push_back(state_proposition(h_dest,
|
||||
iter->current_condition()));
|
||||
|
||||
// Advance iterator for next step.
|
||||
iter->next();
|
||||
|
||||
if (seen.find(h_dest) == seen.end())
|
||||
{
|
||||
// A new state: continue the DFS.
|
||||
tgba_succ_iterator* di = ecs_->aut->succ_iter(h_dest);
|
||||
di->first();
|
||||
todo.push(triplet(h_dest, di, acc));
|
||||
seen.insert(h_dest);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have completed a full cycle.
|
||||
|
||||
// If we already have a best path, let see if the current
|
||||
// one is better.
|
||||
if (best_path.size())
|
||||
{
|
||||
// When comparing the merits of two paths, only the
|
||||
// acceptance conditions we are trying the traverse
|
||||
// are important.
|
||||
bdd acc_restrict = acc & acc_to_traverse;
|
||||
bdd best_acc_restrict = best_acc & acc_to_traverse;
|
||||
|
||||
// If the best path and the current one traverse the
|
||||
// same acceptance conditions, we keep the shorter
|
||||
// path. Otherwise, we keep the path which has the
|
||||
// more acceptance conditions.
|
||||
if (best_acc_restrict == acc_restrict)
|
||||
{
|
||||
if (best_path.size() <= path.size())
|
||||
goto backtrack_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
// `best_acc_restrict >> acc_restrict' is true
|
||||
// when the set of acceptance conditions of
|
||||
// best_acc_restrict is included in the set of
|
||||
// acceptance conditions of acc_restrict.
|
||||
//
|
||||
// FIXME: It would be better to count the number
|
||||
// of acceptance conditions.
|
||||
if (bddtrue != (best_acc_restrict >> acc_restrict))
|
||||
goto backtrack_path;
|
||||
}
|
||||
}
|
||||
|
||||
// The current path the best one.
|
||||
best_path = path;
|
||||
best_acc = acc;
|
||||
|
||||
backtrack_path:
|
||||
// Continue exploration from parent to find better paths.
|
||||
// (Do not pop PATH if ITER is done, because that will be
|
||||
// done at the top of the loop, among other things.)
|
||||
if (!iter->done())
|
||||
path.pop_back();
|
||||
}
|
||||
|
||||
// Append our best path to the period.
|
||||
for (cycle_path::iterator it = best_path.begin();
|
||||
it != best_path.end(); ++it)
|
||||
{
|
||||
period.push_back(*it);
|
||||
ce::state_ce ce(it->first->clone(), it->second);
|
||||
counter_->cycle.push_back(ce);
|
||||
//counter_->cycle.push_back(*it);
|
||||
}
|
||||
|
||||
// Prepare to find another path for the remaining acceptance
|
||||
// conditions.
|
||||
acc_to_traverse -= best_acc;
|
||||
start = period.back().first;
|
||||
}
|
||||
|
||||
// Complete the path so that it goes back to its beginning,
|
||||
// forming a cycle.
|
||||
complete_cycle(scc, start, suffix.back());
|
||||
}
|
||||
|
||||
/////////////
|
||||
|
||||
std::ostream&
|
||||
counter_example::print_result(std::ostream& os, const tgba* restrict) const
|
||||
{
|
||||
|
|
@ -444,4 +632,10 @@ namespace spot
|
|||
os << period.size() << " states in period" << std::endl;
|
||||
}
|
||||
|
||||
ce::counter_example*
|
||||
counter_example::get_counter_example() const
|
||||
{
|
||||
return counter_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue