* src/tgbaalgos/emptinesscheck.cc (emptiness_check::h_filt,
emptiness_check::~emptiness_check) New methods. (emptiness_check::check): Release all iterators in todo on exit. (emptiness_check::counter_example): Rewrite the BFS logic. * src/tgbaalgos/emptinesscheck.hh (emptiness_check::h_filt, emptiness_check::~emptiness_check): New methods.
This commit is contained in:
parent
0ae540ac2a
commit
dd720e9785
3 changed files with 110 additions and 78 deletions
|
|
@ -1,5 +1,12 @@
|
||||||
2003-10-27 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
2003-10-27 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
||||||
|
|
||||||
|
* src/tgbaalgos/emptinesscheck.cc (emptiness_check::h_filt,
|
||||||
|
emptiness_check::~emptiness_check) New methods.
|
||||||
|
(emptiness_check::check): Release all iterators in todo on exit.
|
||||||
|
(emptiness_check::counter_example): Rewrite the BFS logic.
|
||||||
|
* src/tgbaalgos/emptinesscheck.hh (emptiness_check::h_filt,
|
||||||
|
emptiness_check::~emptiness_check): New methods.
|
||||||
|
|
||||||
* src/tgba/tgbatba.cc
|
* src/tgba/tgbatba.cc
|
||||||
(tgba_tba_proxy_succ_iterator::~tgba_tba_proxy_succ_iterator):
|
(tgba_tba_proxy_succ_iterator::~tgba_tba_proxy_succ_iterator):
|
||||||
Delete the proxied iterator.
|
Delete the proxied iterator.
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,29 @@ namespace spot
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emptiness_check::~emptiness_check()
|
||||||
|
{
|
||||||
|
// Free keys in H.
|
||||||
|
hash_type::iterator i = h.begin();
|
||||||
|
while (i != h.end())
|
||||||
|
{
|
||||||
|
// Advance the iterator before deleting the key.
|
||||||
|
const state* s = i->first;
|
||||||
|
++i;
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const state*
|
||||||
|
emptiness_check::h_filt(const state* s) const
|
||||||
|
{
|
||||||
|
hash_type::const_iterator i = h.find(s);
|
||||||
|
assert(i != h.end());
|
||||||
|
if (s != i->first)
|
||||||
|
delete s;
|
||||||
|
return i->first;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
emptiness_check::remove_component(const state* from)
|
emptiness_check::remove_component(const state* from)
|
||||||
{
|
{
|
||||||
|
|
@ -200,8 +223,16 @@ namespace spot
|
||||||
root.top().condition |= acc;
|
root.top().condition |= acc;
|
||||||
|
|
||||||
if (root.top().condition == aut_->all_accepting_conditions())
|
if (root.top().condition == aut_->all_accepting_conditions())
|
||||||
// We have found an accepting SCC.
|
{
|
||||||
return false;
|
// We have found an accepting SCC.
|
||||||
|
// Release all iterators in TODO.
|
||||||
|
while (!todo.empty())
|
||||||
|
{
|
||||||
|
delete todo.top().second;
|
||||||
|
todo.pop();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// This automaton recognize no word.
|
// This automaton recognize no word.
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -254,6 +285,7 @@ namespace spot
|
||||||
emptiness_check::counter_example()
|
emptiness_check::counter_example()
|
||||||
{
|
{
|
||||||
assert(!root.empty());
|
assert(!root.empty());
|
||||||
|
assert(suffix.empty());
|
||||||
|
|
||||||
int comp_size = root.size();
|
int comp_size = root.size();
|
||||||
// Transform the stack of connected component into an array.
|
// Transform the stack of connected component into an array.
|
||||||
|
|
@ -282,102 +314,87 @@ namespace spot
|
||||||
scc[j - 1].state_set.insert(i->first);
|
scc[j - 1].state_set.insert(i->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
// seqs[i] is a sequence between SCC i and SCC i+1.
|
suffix.push_front(h_filt(aut_->get_init_state()));
|
||||||
state_sequence* seqs = new state_sequence[comp_size - 1];
|
|
||||||
// FIFO for the breadth-first search.
|
|
||||||
std::deque<pair_state_iter> todo;
|
|
||||||
|
|
||||||
// Record the father of each state, while performing the BFS.
|
// We build a path trough each SCC in the stack. For the
|
||||||
typedef std::map<const state*, const state*,
|
// first SCC, the starting state is the initial state of the
|
||||||
state_ptr_less_than> father_map;
|
// automaton. The destination state is the closest state
|
||||||
father_map father;
|
// from the next SCC. This destination state becomes the
|
||||||
|
// starting state when building a path though the next SCC.
|
||||||
state_sequence seq;
|
for (int k = 0; k < comp_size - 1; ++k)
|
||||||
|
|
||||||
state* start_state = aut_->get_init_state();
|
|
||||||
if (comp_size != 1)
|
|
||||||
{
|
{
|
||||||
tgba_succ_iterator* i = aut_->succ_iter(start_state);
|
// FIFO for the breadth-first search.
|
||||||
todo.push_back(pair_state_iter(start_state, i));
|
// (we are looking for the closest state in the next SCC.)
|
||||||
|
std::deque<pair_state_iter> todo;
|
||||||
|
|
||||||
for (int k = 0; k < comp_size - 1; ++k)
|
// Record the father of each state, while performing the BFS.
|
||||||
|
typedef std::map<const state*, const state*,
|
||||||
|
state_ptr_less_than> father_map;
|
||||||
|
father_map father;
|
||||||
|
|
||||||
|
// Initial state of the BFS.
|
||||||
|
const state* start = suffix.back();
|
||||||
|
{
|
||||||
|
tgba_succ_iterator* i = aut_->succ_iter(start);
|
||||||
|
todo.push_back(pair_state_iter(start, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!todo.empty())
|
||||||
{
|
{
|
||||||
// We build a path trought all SCC in the stack: a
|
const state* src = todo.front().first;
|
||||||
// possible prefix for a counter example.
|
tgba_succ_iterator* i = todo.front().second;
|
||||||
while (!todo.empty())
|
todo.pop_front();
|
||||||
{
|
|
||||||
pair_state_iter started_from = todo.front();
|
|
||||||
todo.pop_front();
|
|
||||||
|
|
||||||
for (started_from.second->first();
|
for (i->first(); !i->done(); i->next())
|
||||||
!started_from.second->done();
|
{
|
||||||
started_from.second->next())
|
const state* dest = i->current_state();
|
||||||
|
|
||||||
|
// Are we leaving this SCC?
|
||||||
|
if (!scc[k].has_state(dest))
|
||||||
{
|
{
|
||||||
const state* curr_state =
|
// If we have found a state in the next SCC.
|
||||||
started_from.second->current_state();
|
// Unwind the path and populate SUFFIX.
|
||||||
if (scc[k+1].has_state(curr_state))
|
if (scc[k+1].has_state(dest))
|
||||||
{
|
{
|
||||||
const state* curr_father = started_from.first;
|
state_sequence seq;
|
||||||
seq.push_front(curr_state);
|
|
||||||
seq.push_front(curr_father);
|
seq.push_front(h_filt(dest));
|
||||||
hash_type::iterator i_2 = h.find(curr_father);
|
while (src->compare(start))
|
||||||
assert(i_2 != h.end());
|
|
||||||
while (scc[k].index < i_2->second)
|
|
||||||
{
|
{
|
||||||
assert(i_2->second != 1);
|
seq.push_front(src);
|
||||||
assert(father.find(curr_father) != father.end());
|
src = father[src];
|
||||||
const state* f = father[curr_father];
|
}
|
||||||
seq.push_front(f);
|
// Append SEQ to SUFFIX.
|
||||||
curr_father = f;
|
suffix.splice(suffix.end(), seq);
|
||||||
i_2 = h.find(curr_father);
|
// Exit this BFS for this SCC.
|
||||||
assert(i_2 != h.end());
|
while (!todo.empty())
|
||||||
|
{
|
||||||
|
delete todo.front().second;
|
||||||
|
todo.pop_front();
|
||||||
}
|
}
|
||||||
seqs[k] = seq;
|
|
||||||
seq.clear();
|
|
||||||
todo.clear();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
// Restrict the BFS to state inside the SCC.
|
||||||
{
|
delete dest;
|
||||||
if (scc[k].has_state(curr_state))
|
continue;
|
||||||
{
|
}
|
||||||
father_map::iterator i_path =
|
|
||||||
father.find(curr_state);
|
|
||||||
hash_type::iterator i_seen = h.find(curr_state);
|
|
||||||
|
|
||||||
if (i_seen != h.end()
|
dest = h_filt(dest);
|
||||||
&& i_seen->second > 0
|
if (father.find(dest) == father.end())
|
||||||
&& i_path == father.end())
|
{
|
||||||
{
|
todo.push_back(pair_state_iter(dest,
|
||||||
todo.
|
aut_->succ_iter(dest)));
|
||||||
push_back(pair_state_iter(curr_state,
|
father[dest] = src;
|
||||||
aut_->succ_iter(curr_state)));
|
|
||||||
father[curr_state] = started_from.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(!seqs[k].empty());
|
delete i;
|
||||||
todo.
|
|
||||||
push_back(pair_state_iter(seqs[k].back(),
|
|
||||||
aut_->succ_iter(seqs[k].back())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
suffix.push_front(start_state);
|
|
||||||
}
|
|
||||||
for (int n_ = 0; n_ < comp_size - 1; ++n_)
|
|
||||||
for (state_sequence::iterator it = seqs[n_].begin();
|
|
||||||
it != seqs[n_].end(); ++it)
|
|
||||||
suffix.push_back(*it);
|
|
||||||
suffix.unique();
|
|
||||||
accepting_path(scc[comp_size - 1], suffix.back(),
|
accepting_path(scc[comp_size - 1], suffix.back(),
|
||||||
scc[comp_size - 1].condition);
|
scc[comp_size - 1].condition);
|
||||||
|
|
||||||
delete[] scc;
|
delete[] scc;
|
||||||
delete[] seqs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ namespace spot
|
||||||
typedef std::list<state_proposition> cycle_path;
|
typedef std::list<state_proposition> cycle_path;
|
||||||
public:
|
public:
|
||||||
emptiness_check(const tgba* a);
|
emptiness_check(const tgba* a);
|
||||||
|
~emptiness_check();
|
||||||
|
|
||||||
/// This function returns true if the automata's language is empty,
|
/// This function returns true if the automata's language is empty,
|
||||||
/// and builds a stack of SCC.
|
/// and builds a stack of SCC.
|
||||||
|
|
@ -81,6 +82,13 @@ namespace spot
|
||||||
state_ptr_hash, state_ptr_equal> hash_type;
|
state_ptr_hash, state_ptr_equal> hash_type;
|
||||||
hash_type h; ///< Map of visited states.
|
hash_type h; ///< Map of visited states.
|
||||||
|
|
||||||
|
/// \brief Return a state which is equal to \a s, but is in \c h,
|
||||||
|
/// and free \a s if it is different. Doing so simplify memory
|
||||||
|
/// management, because we don't have to track which state need
|
||||||
|
/// to be kept or deallocated: all key in \c h should last for
|
||||||
|
/// the whole life of the emptiness_check.
|
||||||
|
const state* h_filt(const state* s) const;
|
||||||
|
|
||||||
/// \brief Remove a strongly component from the hash.
|
/// \brief Remove a strongly component from the hash.
|
||||||
///
|
///
|
||||||
/// This function remove all accessible state from a given
|
/// This function remove all accessible state from a given
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue