* src/tgbaalgos/gtec/status.hh

(couvreur99_check_status::cycle_seed): New attribute.
* src/tgbaalgos/gtec/gtec.cc (couvreur99_check::check,
couvreur99_check_shy::check): Fill cycle_seed.
* src/tgbaalgos/gtec/ce.hh, src/tgbaalgos/gtec/ce.cc:
(couvreur99_check_result::accepting_run,
couvreur99_check_result::accepting_cycle): Revamp to compute a
cycle from the cycle_start, and then the shortest prefix to this
cycle.
This commit is contained in:
Alexandre Duret-Lutz 2004-12-10 18:33:39 +00:00
parent 27966c28f0
commit abbd0eee07
8 changed files with 154 additions and 139 deletions

View file

@ -1,5 +1,18 @@
2004-12-10 Alexandre Duret-Lutz <adl@src.lip6.fr> 2004-12-10 Alexandre Duret-Lutz <adl@src.lip6.fr>
* src/tgbaalgos/gtec/status.hh
(couvreur99_check_status::cycle_seed): New attribute.
* src/tgbaalgos/gtec/gtec.cc (couvreur99_check::check,
couvreur99_check_shy::check): Fill cycle_seed.
* src/tgbaalgos/gtec/ce.hh, src/tgbaalgos/gtec/ce.cc:
(couvreur99_check_result::accepting_run,
couvreur99_check_result::accepting_cycle): Revamp to compute a
cycle from the cycle_start, and then the shortest prefix to this
cycle.
* iface/gspn/ltlgspn.cc, iface/gspn/ssp.hh, iface/gspn/ssp.cc: Disable
the functions that were using the interface I have just broken.
* src/tgbaalgos/gtec/nsheap.hh (numbered_state_heap::find): Clarify * src/tgbaalgos/gtec/nsheap.hh (numbered_state_heap::find): Clarify
comment. comment.

View file

@ -263,7 +263,11 @@ main(int argc, char **argv)
ce = new spot::couvreur99_check_result(ecs); ce = new spot::couvreur99_check_result(ecs);
break; break;
default: default:
ce = spot::counter_example_ssp(ecs); // ce = spot::counter_example_ssp(ecs);
std::cerr
<< "counter_example_ssp() is no longer supported"
<< std::endl;
exit(1);
} }
#endif #endif
spot::tgba_run* run = ce->accepting_run(); spot::tgba_run* run = ce->accepting_run();

View file

@ -1003,6 +1003,10 @@ namespace spot
return new couvreur99_check_shy_ssp(ssp_automata); return new couvreur99_check_shy_ssp(ssp_automata);
} }
#if 0
// I rewrote couvreur99_check_result today, and it no longer use
// connected_component_ssp_factory. So this cannot work anymore.
// -- adl 2004-12-10.
couvreur99_check_result* couvreur99_check_result*
counter_example_ssp(const couvreur99_check_status* status) counter_example_ssp(const couvreur99_check_status* status)
{ {
@ -1010,4 +1014,5 @@ namespace spot
couvreur99_check_result(status, couvreur99_check_result(status,
connected_component_ssp_factory::instance()); connected_component_ssp_factory::instance());
} }
#endif
} }

View file

@ -55,9 +55,13 @@ namespace spot
couvreur99_check* couvreur99_check_ssp_shy_semi(const tgba* ssp_automata); couvreur99_check* couvreur99_check_ssp_shy_semi(const tgba* ssp_automata);
couvreur99_check* couvreur99_check_ssp_shy(const tgba* ssp_automata); couvreur99_check* couvreur99_check_ssp_shy(const tgba* ssp_automata);
couvreur99_check_result*
counter_example_ssp(const couvreur99_check_status* status);
/// @} /// @}
// I rewrote couvreur99_check_result today, and it no longer use
// connected_component_ssp_factory. So this cannot work anymore.
// -- adl 2004-12-10.
// couvreur99_check_result*
// counter_example_ssp(const couvreur99_check_status* status);
} }
#endif // SPOT_IFACE_GSPN_SSP_GSPN_SSP_HH #endif // SPOT_IFACE_GSPN_SSP_GSPN_SSP_HH

View file

@ -24,10 +24,56 @@
namespace spot namespace spot
{ {
namespace
{
typedef Sgi::hash_set<const state*,
state_ptr_hash, state_ptr_equal> state_set;
class shortest_path: public bfs_steps
{
public:
shortest_path(const state_set* t, const couvreur99_check_status* ecs)
: bfs_steps(ecs->aut), target(t), ecs(ecs)
{
}
const state*
search(const state* start, tgba_run::steps& l)
{
return this->bfs_steps::search(filter(start), l);
}
const state*
filter(const state* s)
{
numbered_state_heap::state_index_p sip = ecs->h->find(s);
// Ignore unknown states ...
if (!sip.first)
{
delete s;
return 0;
}
// ... as well as dead states.
if (*sip.second == -1)
return 0;
return sip.first;
}
bool
match(tgba_run::step&, const state* dest)
{
return target->find(dest) != target->end();
}
private:
state_set seen;
const state_set* target;
const couvreur99_check_status* ecs;
};
}
couvreur99_check_result::couvreur99_check_result couvreur99_check_result::couvreur99_check_result
(const couvreur99_check_status* ecs, (const couvreur99_check_status* ecs)
const explicit_connected_component_factory* eccf) : emptiness_check_result(ecs->aut), ecs_(ecs)
: emptiness_check_result(ecs->aut), ecs_(ecs), eccf_(eccf)
{ {
} }
@ -38,153 +84,93 @@ namespace spot
assert(!ecs_->root.empty()); assert(!ecs_->root.empty());
scc_stack::stack_type root = ecs_->root.s; // Compute an accepting cycle.
int comp_size = root.size(); accepting_cycle();
// Transform the stack of connected component into an array.
explicit_connected_component** scc = // Compute the prefix: it's the shortest path from the initial
new explicit_connected_component*[comp_size]; // state of the automata to any state of the cycle.
for (int j = comp_size - 1; 0 <= j; --j)
// Register all states from the cycle as target of the BFS.
state_set ss;
for (tgba_run::steps::const_iterator i = run_->cycle.begin();
i != run_->cycle.end(); ++i)
ss.insert(i->s);
shortest_path shpath(&ss, ecs_);
const state* prefix_start = ecs_->aut->get_init_state();
// There are two cases: either the initial state is already on
// the cycle, or it is not. If it is, we will have to rotate
// the cycle so it begins on this position. Otherwise we will shift
// the cycle so it begins on the state that follows the prefix.
// cycle_entry_point is that state.
const state* cycle_entry_point;
state_set::const_iterator ps = ss.find(prefix_start);
if (ps != ss.end())
{ {
scc[j] = eccf_->build(); // The initial state is on the cycle.
scc[j]->index = root.top().index; delete prefix_start;
scc[j]->condition = root.top().condition; cycle_entry_point = *ps;
root.pop();
} }
assert(root.empty()); else
// Build the set of states for all SCCs.
numbered_state_heap_const_iterator* i = ecs_->h->iterator();
for (i->first(); !i->done(); i->next())
{ {
int index = i->get_index(); // This initial state is outside the cycle. Compute the prefix.
// Skip states from dead SCCs. cycle_entry_point = shpath.search(prefix_start, run_->prefix);
if (index < 0)
continue;
assert(index != 0);
// Find the SCC this state belongs to.
int j;
for (j = 1; j < comp_size; ++j)
if (index < scc[j]->index)
break;
scc[j - 1]->insert(i->get_state());
}
delete i;
numbered_state_heap::state_index_p spi =
ecs_->h->index(ecs_->aut->get_init_state());
assert(spi.first);
// 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
// from the next SCC. This destination state becomes the
// starting state when building a path through the next SCC.
const state* start = spi.first;
for (int k = 0; k < comp_size - 1; ++k)
{
struct scc_bfs: bfs_steps
{
explicit_connected_component** scc;
int k;
bool in_next;
scc_bfs(const tgba* a, explicit_connected_component** scc, int k)
: bfs_steps(a), scc(scc), k(k)
{
}
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], start, // Locate cycle_entry_point on the cycle.
scc[comp_size - 1]->condition); tgba_run::steps::iterator cycle_ep_it;
for (cycle_ep_it = run_->cycle.begin();
cycle_ep_it != run_->cycle.end()
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
continue;
assert(cycle_ep_it != run_->cycle.end());
for (int j = comp_size - 1; 0 <= j; --j) // Now shift the cycle so it starts on cycle_entry_point.
delete scc[j]; run_->cycle.splice(run_->cycle.end(), run_->cycle,
delete[] scc; run_->cycle.begin(), cycle_ep_it);
run_->cycle.erase(run_->cycle.begin(), cycle_ep_it);
return run_; return run_;
} }
namespace
{
struct triplet
{
const state* s; // Current state.
tgba_succ_iterator* iter; // Iterator to successor of the current state.
bdd acc; // All acceptance conditions traversed by
// the path so far.
triplet (const state* s, tgba_succ_iterator* iter, bdd acc)
: s(s), iter(iter), acc(acc)
{
}
};
}
void void
couvreur99_check_result::accepting_cycle(const explicit_connected_component* couvreur99_check_result::accepting_cycle()
scc,
const state* start, bdd
acc_to_traverse)
{ {
bdd acc_to_traverse = ecs_->aut->all_acceptance_conditions();
// Compute an accepting cycle using successive BFS that are // Compute an accepting cycle using successive BFS that are
// restarted from the point reached after we have discovered a // restarted from the point reached after we have discovered a
// transition with a new acceptance conditions. // transition with a new acceptance conditions.
// //
// This idea is taken from Product<T>::findWitness in LBTT 1.1.2. // This idea is taken from Product<T>::findWitness in LBTT 1.1.2.
const state* substart = start; const state* substart = ecs_->cycle_seed;
do do
{ {
struct scc_bfs: bfs_steps struct scc_bfs: bfs_steps
{ {
const explicit_connected_component* scc; const couvreur99_check_status* ecs;
bool in_next;
bdd& acc_to_traverse; bdd& acc_to_traverse;
const state* start; int scc_root;
scc_bfs(const tgba* a, const explicit_connected_component* scc, scc_bfs(const couvreur99_check_status* ecs,
bdd& acc_to_traverse, const state* start) bdd& acc_to_traverse)
: bfs_steps(a), scc(scc), acc_to_traverse(acc_to_traverse), : bfs_steps(ecs->aut), ecs(ecs), acc_to_traverse(acc_to_traverse),
start(start) scc_root(ecs->root.s.top().index)
{ {
} }
virtual const state* virtual const state*
filter(const state* s) filter(const state* s)
{ {
const state* h_s = scc->has_state(s); numbered_state_heap::state_index_p sip = ecs->h->find(s);
if (!h_s) // Ignore unknown states.
delete s; if (!sip.first)
return h_s; {
delete s;
return 0;
}
// Stay in the final SCC.
if (*sip.second < scc_root)
return 0;
return sip.first;
} }
virtual bool virtual bool
@ -193,7 +179,7 @@ namespace spot
bdd less_acc = acc_to_traverse - st.acc; bdd less_acc = acc_to_traverse - st.acc;
if (less_acc != acc_to_traverse if (less_acc != acc_to_traverse
|| (acc_to_traverse == bddfalse || (acc_to_traverse == bddfalse
&& s == start)) && s == ecs->cycle_seed))
{ {
acc_to_traverse = less_acc; acc_to_traverse = less_acc;
return true; return true;
@ -201,11 +187,11 @@ namespace spot
return false; return false;
} }
} b(ecs_->aut, scc, acc_to_traverse, start); } b(ecs_, acc_to_traverse);
substart = b.search(substart, run_->cycle); substart = b.search(substart, run_->cycle);
} }
while (acc_to_traverse != bddfalse || substart != start); while (acc_to_traverse != bddfalse || substart != ecs_->cycle_seed);
} }
void void

View file

@ -23,7 +23,6 @@
# define SPOT_TGBAALGOS_GTEC_CE_HH # define SPOT_TGBAALGOS_GTEC_CE_HH
#include "status.hh" #include "status.hh"
#include "explscc.hh"
#include "tgbaalgos/emptiness.hh" #include "tgbaalgos/emptiness.hh"
namespace spot namespace spot
@ -32,11 +31,7 @@ namespace spot
class couvreur99_check_result: public emptiness_check_result class couvreur99_check_result: public emptiness_check_result
{ {
public: public:
couvreur99_check_result(const couvreur99_check_status* ecs, couvreur99_check_result(const couvreur99_check_status* ecs);
const explicit_connected_component_factory*
eccf =
connected_component_hash_set_factory::instance());
virtual tgba_run* accepting_run(); virtual tgba_run* accepting_run();
@ -45,12 +40,10 @@ namespace spot
protected: protected:
/// Called by accepting_run() to find a cycle which traverses all /// Called by accepting_run() to find a cycle which traverses all
/// acceptance conditions in the accepted SCC. /// acceptance conditions in the accepted SCC.
void accepting_cycle(const explicit_connected_component* scc, void accepting_cycle();
const state* start, bdd acc_to_traverse);
private: private:
const couvreur99_check_status* ecs_; const couvreur99_check_status* ecs_;
const explicit_connected_component_factory* eccf_;
tgba_run* run_; tgba_run* run_;
}; };
} }

View file

@ -229,6 +229,9 @@ namespace spot
todo.pop(); todo.pop();
dec_depth(); dec_depth();
} }
// Use this state to start the computation of an accepting
// cycle.
ecs_->cycle_seed = spi.first;
set_states(ecs_->states()); set_states(ecs_->states());
return new couvreur99_check_result(ecs_); return new couvreur99_check_result(ecs_);
} }
@ -288,7 +291,8 @@ namespace spot
succ_queue::iterator q = queue.begin(); succ_queue::iterator q = queue.begin();
while (q != queue.end()) while (q != queue.end())
{ {
int* i = find_state(q->s); numbered_state_heap::state_index_p sip = ecs_->h->find(q->s);
int* i = sip.second;
if (!i) if (!i)
{ {
// Skip unknown states. // Skip unknown states.
@ -333,10 +337,15 @@ namespace spot
// merged SCC. // merged SCC.
ecs_->root.top().condition |= acc; ecs_->root.top().condition |= acc;
// Have we found all acceptance conditions?
if (ecs_->root.top().condition if (ecs_->root.top().condition
== ecs_->aut->all_acceptance_conditions()) == ecs_->aut->all_acceptance_conditions())
{ {
/// q->s has already been freed by find_state(). // Use this state to start the computation of an accepting
// cycle.
ecs_->cycle_seed = sip.first;
/// q->s has already been freed by ecs_->h->find.
queue.erase(q); queue.erase(q);
// We have found an accepting SCC. Clean up TODO. // We have found an accepting SCC. Clean up TODO.
// We must delete all states of apparing in TODO // We must delete all states of apparing in TODO

View file

@ -44,6 +44,7 @@ namespace spot
const tgba* aut; const tgba* aut;
scc_stack root; scc_stack root;
numbered_state_heap* h; ///< Heap of visited states. numbered_state_heap* h; ///< Heap of visited states.
const state* cycle_seed;
/// Output statistics about this object. /// Output statistics about this object.
void print_stats(std::ostream& os) const; void print_stats(std::ostream& os) const;