* src/tgbaalgos/gtec/ce.cc (couvreur99_check_result::accepting_run,
couvreur99_check_result::accepting_cycle): Rewrite the BFSs using the bfs_steps class.
This commit is contained in:
parent
2b74398a62
commit
c1fd4d1138
2 changed files with 80 additions and 160 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
2004-11-24 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
2004-11-24 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
||||||
|
|
||||||
|
* src/tgbaalgos/gtec/ce.cc (couvreur99_check_result::accepting_run,
|
||||||
|
couvreur99_check_result::accepting_cycle): Rewrite the BFSs using
|
||||||
|
the bfs_steps class.
|
||||||
|
|
||||||
* src/tgbaalgos/bfssteps.hh, src/tgbaalgos/bfssteps.cc: New files.
|
* src/tgbaalgos/bfssteps.hh, src/tgbaalgos/bfssteps.cc: New files.
|
||||||
* src/tgbaalgos/Makefile.am (tgbaalgos_HEADERS,
|
* src/tgbaalgos/Makefile.am (tgbaalgos_HEADERS,
|
||||||
libtgbaalgos_la_SOURCES): Add them.
|
libtgbaalgos_la_SOURCES): Add them.
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@
|
||||||
// 02111-1307, USA.
|
// 02111-1307, USA.
|
||||||
|
|
||||||
#include "ce.hh"
|
#include "ce.hh"
|
||||||
#include "tgba/bddprint.hh"
|
#include "tgbaalgos/bfssteps.hh"
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -75,115 +74,63 @@ namespace spot
|
||||||
numbered_state_heap::state_index_p spi =
|
numbered_state_heap::state_index_p spi =
|
||||||
ecs_->h->index(ecs_->aut->get_init_state());
|
ecs_->h->index(ecs_->aut->get_init_state());
|
||||||
assert(spi.first);
|
assert(spi.first);
|
||||||
// This incomplete starting step will be overwritten later.
|
|
||||||
tgba_run::step s = { spi.first, bddtrue, bddfalse };
|
|
||||||
run_->prefix.push_front(s);
|
|
||||||
|
|
||||||
// We build a path trough each SCC in the stack. For the
|
// We build a path trough each SCC in the stack. For the
|
||||||
// first SCC, the starting state is the initial state of the
|
// first SCC, the starting state is the initial state of the
|
||||||
// automaton. The destination state is the closest state
|
// automaton. The destination state is the closest state
|
||||||
// from the next SCC. This destination state becomes the
|
// from the next SCC. This destination state becomes the
|
||||||
// starting state when building a path through the next SCC.
|
// starting state when building a path through the next SCC.
|
||||||
|
const state* start = spi.first;
|
||||||
for (int k = 0; k < comp_size - 1; ++k)
|
for (int k = 0; k < comp_size - 1; ++k)
|
||||||
{
|
{
|
||||||
// FIFO for the breadth-first search.
|
|
||||||
// (we are looking for the closest state in the next SCC.)
|
|
||||||
std::deque<const state*> todo;
|
|
||||||
|
|
||||||
// Record the father of each state, while performing the BFS.
|
struct scc_bfs: bfs_steps
|
||||||
typedef std::map<const state*, tgba_run::step,
|
{
|
||||||
state_ptr_less_than> father_map;
|
explicit_connected_component** scc;
|
||||||
father_map father;
|
int k;
|
||||||
|
bool in_next;
|
||||||
// Initial state of the BFS.
|
scc_bfs(const tgba* a, explicit_connected_component** scc, int k)
|
||||||
const state* start = run_->prefix.back().s;
|
: bfs_steps(a), scc(scc), k(k)
|
||||||
todo.push_back(start);
|
|
||||||
|
|
||||||
while (!todo.empty())
|
|
||||||
{
|
{
|
||||||
const state* src = todo.front();
|
|
||||||
todo.pop_front();
|
|
||||||
tgba_succ_iterator* i = ecs_->aut->succ_iter(src);
|
|
||||||
|
|
||||||
for (i->first(); !i->done(); i->next())
|
|
||||||
{
|
|
||||||
const state* dest = i->current_state();
|
|
||||||
|
|
||||||
// Are we leaving this SCC?
|
|
||||||
const state* h_dest = scc[k]->has_state(dest);
|
|
||||||
if (!h_dest)
|
|
||||||
{
|
|
||||||
// If we have found a state in the next SCC.
|
|
||||||
// Unwind the path and populate RUN_->PREFIX.
|
|
||||||
h_dest = scc[k+1]->has_state(dest);
|
|
||||||
if (h_dest)
|
|
||||||
{
|
|
||||||
tgba_run::steps seq;
|
|
||||||
|
|
||||||
// The condition and acceptance conditions
|
|
||||||
// for the transition leaving H_DEST will
|
|
||||||
// be overwritten later when we know them.
|
|
||||||
|
|
||||||
tgba_run::step s = { h_dest, bddtrue, bddfalse };
|
|
||||||
seq.push_front(s);
|
|
||||||
|
|
||||||
// Now unwind our track until we reach START.
|
|
||||||
tgba_run::step t =
|
|
||||||
{ src,
|
|
||||||
i->current_condition(),
|
|
||||||
i->current_acceptance_conditions() };
|
|
||||||
while (t.s->compare(start))
|
|
||||||
{
|
|
||||||
seq.push_front(t);
|
|
||||||
t = father[t.s];
|
|
||||||
}
|
|
||||||
assert(!run_->prefix.empty());
|
|
||||||
// Overwrite the incomplete starting step.
|
|
||||||
run_->prefix.back() = t;
|
|
||||||
|
|
||||||
// Append SEQ to RUN_->PREFIX.
|
|
||||||
run_->prefix.splice(run_->prefix.end(), seq);
|
|
||||||
|
|
||||||
// Exit this BFS for this SCC.
|
|
||||||
todo.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Restrict the BFS to state inside the SCC.
|
|
||||||
delete dest;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (father.find(h_dest) == father.end())
|
|
||||||
{
|
|
||||||
todo.push_back(h_dest);
|
|
||||||
tgba_run::step s = { src,
|
|
||||||
i->current_condition(),
|
|
||||||
i->current_acceptance_conditions() };
|
|
||||||
father[h_dest] = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual const state*
|
||||||
|
filter(const state* s)
|
||||||
|
{
|
||||||
|
const state* h_s = scc[k]->has_state(s);
|
||||||
|
if (!h_s)
|
||||||
|
{
|
||||||
|
h_s = scc[k+1]->has_state(s);
|
||||||
|
in_next = true;
|
||||||
|
if (!h_s)
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
in_next = false;
|
||||||
|
}
|
||||||
|
return h_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
match(tgba_run::step&, const state*)
|
||||||
|
{
|
||||||
|
return in_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} b(ecs_->aut, scc, k);
|
||||||
|
|
||||||
|
start = b.search(start, run_->prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
accepting_cycle(scc[comp_size - 1], run_->prefix.back().s,
|
accepting_cycle(scc[comp_size - 1], start,
|
||||||
scc[comp_size - 1]->condition);
|
scc[comp_size - 1]->condition);
|
||||||
run_->prefix.pop_back(); // this state belongs to the cycle.
|
|
||||||
|
|
||||||
for (int j = comp_size - 1; 0 <= j; --j)
|
for (int j = comp_size - 1; 0 <= j; --j)
|
||||||
delete scc[j];
|
delete scc[j];
|
||||||
delete[] scc;
|
delete[] scc;
|
||||||
|
|
||||||
// Clone every state in the run before returning it. (We didn't
|
|
||||||
// do that before in the algorithm, because it's easier to follow
|
|
||||||
// if every state manipulated is the instance in the hash table.)
|
|
||||||
for (tgba_run::steps::iterator i = run_->prefix.begin();
|
|
||||||
i != run_->prefix.end(); ++i)
|
|
||||||
i->s = i->s->clone();
|
|
||||||
for (tgba_run::steps::iterator i = run_->cycle.begin();
|
|
||||||
i != run_->cycle.end(); ++i)
|
|
||||||
i->s = i->s->clone();
|
|
||||||
|
|
||||||
return run_;
|
return run_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,76 +165,45 @@ namespace spot
|
||||||
const state* substart = start;
|
const state* substart = start;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Records backlinks to parent state during the BFS.
|
struct scc_bfs: bfs_steps
|
||||||
// (This also stores the propositions of this link.)
|
{
|
||||||
std::map<const state*, tgba_run::step, state_ptr_less_than> father;
|
const explicit_connected_component* scc;
|
||||||
|
bool in_next;
|
||||||
// BFS queue.
|
bdd& acc_to_traverse;
|
||||||
std::deque<const state*> todo;
|
const state* start;
|
||||||
|
scc_bfs(const tgba* a, const explicit_connected_component* scc,
|
||||||
// Initial state.
|
bdd& acc_to_traverse, const state* start)
|
||||||
todo.push_back(substart);
|
: bfs_steps(a), scc(scc), acc_to_traverse(acc_to_traverse),
|
||||||
|
start(start)
|
||||||
while (!todo.empty())
|
|
||||||
{
|
{
|
||||||
const state* src = todo.front();
|
|
||||||
todo.pop_front();
|
|
||||||
tgba_succ_iterator* i = ecs_->aut->succ_iter(src);
|
|
||||||
for (i->first(); !i->done(); i->next())
|
|
||||||
{
|
|
||||||
const state* dest = i->current_state();
|
|
||||||
|
|
||||||
// Do not escape this SCC
|
|
||||||
const state* h_dest = scc->has_state(dest);
|
|
||||||
if (!h_dest)
|
|
||||||
{
|
|
||||||
delete dest;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bdd cond = i->current_condition();
|
|
||||||
bdd acc = i->current_acceptance_conditions();
|
|
||||||
tgba_run::step s = { src, cond, acc };
|
|
||||||
|
|
||||||
// If this new step diminish the number of acceptance
|
|
||||||
// conditions, record the path so far and start a new
|
|
||||||
// BFS for the remaining acceptance conditions.
|
|
||||||
//
|
|
||||||
// If we have already collected all acceptance conditions,
|
|
||||||
// we stop if we cycle back to the start of the cycle.
|
|
||||||
bdd less_acc = acc_to_traverse - acc;
|
|
||||||
if (less_acc != acc_to_traverse
|
|
||||||
|| (acc_to_traverse == bddfalse
|
|
||||||
&& h_dest == start))
|
|
||||||
{
|
|
||||||
acc_to_traverse = less_acc;
|
|
||||||
|
|
||||||
tgba_run::steps p;
|
|
||||||
|
|
||||||
while (s.s != substart)
|
|
||||||
{
|
|
||||||
p.push_front(s);
|
|
||||||
s = father[s.s];
|
|
||||||
}
|
|
||||||
p.push_front(s);
|
|
||||||
run_->cycle.splice(run_->cycle.end(), p);
|
|
||||||
|
|
||||||
// Exit this BFS, and start a new one at h_dest.
|
|
||||||
todo.clear();
|
|
||||||
substart = h_dest;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common case: record backlinks and continue BFS
|
|
||||||
// for unvisited states.
|
|
||||||
if (father.find(h_dest) == father.end())
|
|
||||||
{
|
|
||||||
todo.push_back(h_dest);
|
|
||||||
father[h_dest] = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual const state*
|
||||||
|
filter(const state* s)
|
||||||
|
{
|
||||||
|
const state* h_s = scc->has_state(s);
|
||||||
|
if (!h_s)
|
||||||
|
delete s;
|
||||||
|
return h_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
match(tgba_run::step& st, const state* s)
|
||||||
|
{
|
||||||
|
bdd less_acc = acc_to_traverse - st.acc;
|
||||||
|
if (less_acc != acc_to_traverse
|
||||||
|
|| (acc_to_traverse == bddfalse
|
||||||
|
&& s == start))
|
||||||
|
{
|
||||||
|
acc_to_traverse = less_acc;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} b(ecs_->aut, scc, acc_to_traverse, start);
|
||||||
|
|
||||||
|
substart = b.search(substart, run_->cycle);
|
||||||
}
|
}
|
||||||
while (acc_to_traverse != bddfalse || substart != start);
|
while (acc_to_traverse != bddfalse || substart != start);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue