diff --git a/ChangeLog b/ChangeLog index d043e9d13..01a4c04c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-01-28 Alexandre Duret-Lutz + + * src/tgbaalgos/emptiness_stats.hh: Make sure depth() >= 0. + * src/tgbaalgos/gtec/gtec.hh (couvreur99_check, couvreur99_check_shy): + Add the poprem option. + * src/tgbaalgos/gtec/gtec.cc: Implement it. + * src/tgbaalgos/gtec/sccstack.cc, src/tgbaalgos/gtec/sccstack.hh + (scc_stack::rem, scc_stack::clear_rem, + scc_stack::connected_component::rem): New. + * src/tgbatest/ltl2tgba.cc, src/tgbatest/randtgba.cc: Add rem variants. + 2005-01-28 Denis Poitrenaud * src/tgbatest/dfs.test, src/tgbatest/emptchk.test, diff --git a/src/tgbaalgos/emptiness_stats.hh b/src/tgbaalgos/emptiness_stats.hh index 23b85e1e3..185f8c860 100644 --- a/src/tgbaalgos/emptiness_stats.hh +++ b/src/tgbaalgos/emptiness_stats.hh @@ -22,6 +22,8 @@ #ifndef SPOT_TGBAALGOS_EMPTINESS_STATS_HH # define SPOT_TGBAALGOS_EMPTINESS_STATS_HH +#include + namespace spot { @@ -42,7 +44,7 @@ namespace spot } void - set_states(int n) + set_states(unsigned n) { states_ = n; } @@ -60,7 +62,7 @@ namespace spot } void - inc_depth(int n = 1) + inc_depth(unsigned n = 1) { depth_ += n; if (depth_ > max_depth_) @@ -68,8 +70,9 @@ namespace spot } void - dec_depth(int n = 1) + dec_depth(unsigned n = 1) { + assert(depth_ >= n); depth_ -= n; } diff --git a/src/tgbaalgos/gtec/ce.cc b/src/tgbaalgos/gtec/ce.cc index 023c10465..c75e3c41d 100644 --- a/src/tgbaalgos/gtec/ce.cc +++ b/src/tgbaalgos/gtec/ce.cc @@ -86,7 +86,7 @@ namespace spot couvreur99_check_result::acss_states() const { int count = 0; - int scc_root = ecs_->root.s.top().index; + int scc_root = ecs_->root.top().index; numbered_state_heap_const_iterator* i = ecs_->h->iterator(); for (i->first(); !i->done(); i->next()) @@ -184,7 +184,7 @@ namespace spot couvreur99_check_result* r, bdd& acc_to_traverse) : bfs_steps(ecs->aut), ecs(ecs), r(r), acc_to_traverse(acc_to_traverse), - scc_root(ecs->root.s.top().index) + scc_root(ecs->root.top().index) { } @@ -222,6 +222,7 @@ namespace spot } b(ecs_, this, acc_to_traverse); substart = b.search(substart, run_->cycle); + assert(substart); } while (acc_to_traverse != bddfalse || substart != ecs_->cycle_seed); } diff --git a/src/tgbaalgos/gtec/gtec.cc b/src/tgbaalgos/gtec/gtec.cc index 9f40b426f..82d7a6e63 100644 --- a/src/tgbaalgos/gtec/gtec.cc +++ b/src/tgbaalgos/gtec/gtec.cc @@ -30,8 +30,9 @@ namespace spot } couvreur99_check::couvreur99_check(const tgba* a, + bool poprem, const numbered_state_heap_factory* nshf) - : emptiness_check(a) + : emptiness_check(a), poprem_(poprem) { ecs_ = new couvreur99_check_status(a, nshf); } @@ -44,6 +45,23 @@ namespace spot void couvreur99_check::remove_component(const state* from) { + // If rem has been updated, removing states is very easy. + if (poprem_) + { + assert(!ecs_->root.rem().empty()); + dec_depth(ecs_->root.rem().size()); + std::list::iterator i; + for (i = ecs_->root.rem().begin(); i != ecs_->root.rem().end(); ++i) + { + numbered_state_heap::state_index_p spi = ecs_->h->index(*i); + assert(spi.first == *i); + assert(*spi.second != -1); + *spi.second = -1; + } + // ecs_->root.rem().clear(); + return; + } + // Remove from H all states which are reachable from state FROM. // Stack of iterators towards states to remove. @@ -57,7 +75,6 @@ namespace spot assert(spi.first == from); assert(*spi.second != -1); *spi.second = -1; - dec_depth(); // FIXME: check once remove_component() is revamped. tgba_succ_iterator* i = ecs_->aut->succ_iter(from); for (;;) @@ -65,7 +82,7 @@ namespace spot // Remove each destination of this iterator. for (i->first(); !i->done(); i->next()) { - // FIXME: inc_transitions(); + inc_transitions(); state* s = i->current_state(); numbered_state_heap::state_index_p spi = ecs_->h->index(s); @@ -81,7 +98,6 @@ namespace spot if (*spi.second != -1) { *spi.second = -1; - dec_depth(); // FIXME: check after revamping. to_remove.push(ecs_->aut->succ_iter(spi.first)); } } @@ -139,20 +155,28 @@ namespace spot // Backtrack TODO. todo.pop(); - // FIXME: dec_depth(); + dec_depth(); + // If poprem is used, fill rem with any component removed, + // so that remove_component() does not have to traverse + // the SCC again. + numbered_state_heap::state_index_p spi = ecs_->h->index(curr); + assert(spi.first); + if (poprem_) + { + ecs_->root.rem().push_front(spi.first); + inc_depth(); + } // When backtracking the root of an SCC, we must also // remove that SCC from the ARC/ROOT stacks. We must // discard from H all reachable states from this SCC. - numbered_state_heap::state_index_p spi = ecs_->h->index(curr); - assert(spi.first); assert(!ecs_->root.empty()); if (ecs_->root.top().index == *spi.second) { assert(!arc.empty()); arc.pop(); - ecs_->root.pop(); remove_component(curr); + ecs_->root.pop(); } delete succ; @@ -203,12 +227,14 @@ namespace spot // top of ROOT that have an index greater to the one of // the SCC of S2 (called the "threshold"). int threshold = *spi.second; + std::list rem; while (threshold < ecs_->root.top().index) { assert(!ecs_->root.empty()); assert(!arc.empty()); acc |= ecs_->root.top().condition; acc |= arc.top(); + rem.splice(rem.end(), ecs_->root.rem()); ecs_->root.pop(); arc.pop(); } @@ -219,6 +245,7 @@ namespace spot // Accumulate all acceptance conditions into the merged SCC. ecs_->root.top().condition |= acc; + ecs_->root.rem().splice(ecs_->root.rem().end(), rem); if (ecs_->root.top().condition == ecs_->aut->all_acceptance_conditions()) @@ -261,10 +288,11 @@ namespace spot ////////////////////////////////////////////////////////////////////// couvreur99_check_shy::couvreur99_check_shy(const tgba* a, + bool poprem, bool group, const numbered_state_heap_factory* nshf) - : couvreur99_check(a, nshf), num(1), group_(group) + : couvreur99_check(a, poprem, nshf), num(1), group_(group) { // Setup depth-first search from the initial state. todo.push_back(todo_item(0, 0)); @@ -297,8 +325,8 @@ namespace spot dec_depth(todo.back().q.size() + 1); todo.pop_back(); } - // FIXME: enable after revamping remove_component(). - // assert(depth() == 0); + dec_depth(ecs_->root.clear_rem()); + assert(depth() == 0); } emptiness_check_result* @@ -318,18 +346,30 @@ namespace spot // We have explored all successors of state CURR. const state* curr = todo.back().s; int index = todo.back().n; + // Backtrack TODO. todo.pop_back(); - // FIXME: dec_depth(); + dec_depth(); + if (todo.empty()) { // This automaton recognizes no word. set_states(ecs_->states()); - // FIXME: enable after revamping remove_component(). - // assert(depth() == 0); + assert(poprem_ || depth() == 0); return 0; } + // If poprem is used, fill rem with any component removed, + // so that remove_component() does not have to traverse + // the SCC again. + if (poprem_) + { + numbered_state_heap::state_index_p spi = ecs_->h->index(curr); + assert(spi.first); + ecs_->root.rem().push_front(spi.first); + inc_depth(); + } + // When backtracking the root of an SCC, we must also // remove that SCC from the ARC/ROOT stacks. We must // discard from H all reachable states from this SCC. @@ -338,8 +378,8 @@ namespace spot { assert(!arc.empty()); arc.pop(); - ecs_->root.pop(); remove_component(curr); + ecs_->root.pop(); } continue; } @@ -418,12 +458,14 @@ namespace spot // an index greater to the one of the SCC of S2 // (called the "threshold"). int threshold = *i; + std::list rem; while (threshold < ecs_->root.top().index) { assert(!ecs_->root.empty()); assert(!arc.empty()); acc |= ecs_->root.top().condition; acc |= arc.top(); + rem.splice(rem.end(), ecs_->root.rem()); ecs_->root.pop(); arc.pop(); } @@ -435,6 +477,7 @@ namespace spot // Accumulate all acceptance conditions into the // merged SCC. ecs_->root.top().condition |= acc; + ecs_->root.rem().splice(ecs_->root.rem().end(), rem); // Have we found all acceptance conditions? if (ecs_->root.top().condition @@ -453,7 +496,7 @@ namespace spot // Group the pending successors of formed SCC if requested. if (group_) { - assert(todo.back().s != 0); + assert(todo.back().s); while (ecs_->root.top().index < todo.back().n) { todo_list::reverse_iterator prev = todo.rbegin(); @@ -464,8 +507,21 @@ namespace spot merged = true; } prev->q.splice(prev->q.end(), last->q); + + if (poprem_) + { + numbered_state_heap::state_index_p spi = + ecs_->h->index(todo.back().s); + assert(spi.first); + ecs_->root.rem().push_front(spi.first); + // Don't change the stack depth, since + // we are just moving the state from TODO to REM. + } + else + { + dec_depth(); + } todo.pop_back(); - // dec_depth(); } new_queue = &todo.back().q; } diff --git a/src/tgbaalgos/gtec/gtec.hh b/src/tgbaalgos/gtec/gtec.hh index c65435ce6..594296b17 100644 --- a/src/tgbaalgos/gtec/gtec.hh +++ b/src/tgbaalgos/gtec/gtec.hh @@ -1,4 +1,4 @@ -// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6), +// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6), // département Systèmes Répartis Coopératifs (SRC), Université Pierre // et Marie Curie. // @@ -22,6 +22,7 @@ #ifndef SPOT_TGBAALGOS_GTEC_GTEC_HH # define SPOT_TGBAALGOS_GTEC_GTEC_HH +#include #include "status.hh" #include "tgbaalgos/emptiness.hh" #include "tgbaalgos/emptiness_stats.hh" @@ -76,6 +77,7 @@ namespace spot { public: couvreur99_check(const tgba* a, + bool poprem = true, const numbered_state_heap_factory* nshf = numbered_state_heap_hash_map_factory::instance()); virtual ~couvreur99_check(); @@ -103,6 +105,9 @@ namespace spot /// state. In other words, it removes the strongly connected /// component that contains this state. void remove_component(const state* start_delete); + + /// Whether to store the state to be removed. + bool poprem_; }; /// \brief A version of spot::couvreur99_check that tries to visit @@ -118,6 +123,7 @@ namespace spot { public: couvreur99_check_shy(const tgba* a, + bool poprem = true, bool group = true, const numbered_state_heap_factory* nshf = numbered_state_heap_hash_map_factory::instance()); @@ -144,7 +150,6 @@ namespace spot // * todo, the depth-first search stack. This holds pairs of the // form (STATE, SUCCESSORS) where SUCCESSORS is a list of // (ACCEPTANCE_CONDITIONS, STATE) pairs. - typedef std::list succ_queue; struct todo_item diff --git a/src/tgbaalgos/gtec/sccstack.cc b/src/tgbaalgos/gtec/sccstack.cc index 6a26d8a6e..aef399679 100644 --- a/src/tgbaalgos/gtec/sccstack.cc +++ b/src/tgbaalgos/gtec/sccstack.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6), +// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6), // département Systèmes Répartis Coopératifs (SRC), Université Pierre // et Marie Curie. // @@ -32,21 +32,35 @@ namespace spot scc_stack::connected_component& scc_stack::top() { - return s.top(); + return s.front(); + } + + const scc_stack::connected_component& + scc_stack::top() const + { + return s.front(); } void scc_stack::pop() { - s.pop(); + // assert(rem().empty()); + s.pop_front(); } void scc_stack::push(int index) { - s.push(connected_component(index)); + s.push_front(connected_component(index)); } + std::list& + scc_stack::rem() + { + return top().rem; + } + + size_t scc_stack::size() const { @@ -58,4 +72,18 @@ namespace spot { return s.empty(); } + + unsigned + scc_stack::clear_rem() + { + unsigned n = 0; + for (stack_type::iterator i = s.begin(); i != s.end(); ++i) + { + n += i->rem.size(); + i->rem.clear(); + } + return n; + } + + } diff --git a/src/tgbaalgos/gtec/sccstack.hh b/src/tgbaalgos/gtec/sccstack.hh index 1d8708365..56d50c240 100644 --- a/src/tgbaalgos/gtec/sccstack.hh +++ b/src/tgbaalgos/gtec/sccstack.hh @@ -1,4 +1,4 @@ -// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6), +// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6), // département Systèmes Répartis Coopératifs (SRC), Université Pierre // et Marie Curie. // @@ -22,8 +22,9 @@ #ifndef SPOT_TGBAALGOS_GTEC_SCCSTACK_HH # define SPOT_TGBAALGOS_GTEC_SCCSTACK_HH -#include #include +#include +#include namespace spot { @@ -42,6 +43,8 @@ namespace spot /// The bdd condition is the union of all acceptance conditions of /// transitions which connect the states of the connected component. bdd condition; + + std::list rem; }; /// Stack a new SCC with index \a index. @@ -50,16 +53,27 @@ namespace spot /// Access the top SCC. connected_component& top(); + /// Access the top SCC. + const connected_component& top() const; + /// Pop the top SCC. void pop(); /// How many SCC are in stack. size_t size() const; + /// The \c rem member of the top SCC. + std::list& rem(); + + /// Purge all \c rem members. + /// + /// \return the number of elements cleared. + unsigned clear_rem(); + /// Is the stack empty? bool empty() const; - typedef std::stack stack_type; + typedef std::list stack_type; stack_type s; }; } diff --git a/src/tgbatest/ltl2tgba.cc b/src/tgbatest/ltl2tgba.cc index cf6854e71..a71f856b9 100644 --- a/src/tgbatest/ltl2tgba.cc +++ b/src/tgbatest/ltl2tgba.cc @@ -136,6 +136,9 @@ syntax(char* prog) << " Cou99 (the default)" << std::endl << " Cou99_shy-" << std::endl << " Cou99_shy" << std::endl + << " Cou99_rem" << std::endl + << " Cou99_rem_shy-" << std::endl + << " Cou99_rem_shy" << std::endl << " CVWY90" << std::endl << " CVWY90_repeated" << std::endl << " CVWY90_bsh[(heap size in Mo - 10Mo by default)]" @@ -174,6 +177,7 @@ main(int argc, char** argv) Tau03Search, Tau03OptSearch, Gv04 } echeck = None; enum { NoneDup, BFS, DFS } dupexp = NoneDup; bool couv_group = true; + bool poprem = false; bool search_many = false; bool bit_state_hashing = false; int heap_size = 10*1024*1024; @@ -426,6 +430,23 @@ main(int argc, char** argv) echeck = Couvreur2; couv_group = false; } + else if (echeck_algo == "Cou99_rem") + { + echeck = Couvreur; + poprem = true; + } + else if (echeck_algo == "Cou99_rem_shy") + { + echeck = Couvreur2; + couv_group = true; + poprem = true; + } + else if (echeck_algo == "Cou99_rem_shy-") + { + echeck = Couvreur2; + couv_group = false; + poprem = true; + } else if (echeck_algo == "CVWY90") { echeck = MagicSearch; @@ -728,11 +749,11 @@ main(int argc, char** argv) break; case Couvreur: - ec = new spot::couvreur99_check(a); + ec = new spot::couvreur99_check(a, poprem); break; case Couvreur2: - ec = new spot::couvreur99_check_shy(a, couv_group); + ec = new spot::couvreur99_check_shy(a, poprem, couv_group); break; case MagicSearch: diff --git a/src/tgbatest/randtgba.cc b/src/tgbatest/randtgba.cc index 0a6748069..7bd295499 100644 --- a/src/tgbatest/randtgba.cc +++ b/src/tgbatest/randtgba.cc @@ -65,19 +65,37 @@ spot::emptiness_check* couvreur99_cons(const spot::tgba* a) { - return new spot::couvreur99_check(a); + return new spot::couvreur99_check(a, false); } spot::emptiness_check* couvreur99_shy_cons(const spot::tgba* a) { - return new spot::couvreur99_check_shy(a); + return new spot::couvreur99_check_shy(a, false); } spot::emptiness_check* couvreur99_shy_minus_cons(const spot::tgba* a) { - return new spot::couvreur99_check_shy(a, false); + return new spot::couvreur99_check_shy(a, false, false); +} + +spot::emptiness_check* +couvreur99_rem_cons(const spot::tgba* a) +{ + return new spot::couvreur99_check(a, true); +} + +spot::emptiness_check* +couvreur99_rem_shy_cons(const spot::tgba* a) +{ + return new spot::couvreur99_check_shy(a, true); +} + +spot::emptiness_check* +couvreur99_rem_shy_minus_cons(const spot::tgba* a) +{ + return new spot::couvreur99_check_shy(a, true, false); } spot::emptiness_check* @@ -103,16 +121,19 @@ struct ec_algo ec_algo ec_algos[] = { - { "Cou99", couvreur99_cons, 0, -1U, true }, - { "Cou99_shy-", couvreur99_shy_minus_cons, 0, -1U, true }, - { "Cou99_shy", couvreur99_shy_cons, 0, -1U, true }, - { "CVWY90", spot::explicit_magic_search, 0, 1, true }, - { "CVWY90_bsh", bsh_ms_cons, 0, 1, false }, - { "GV04", spot::explicit_gv04_check, 0, 1, true }, - { "SE05", spot::explicit_se05_search, 0, 1, true }, - { "SE05_bsh", bsh_se05_cons, 0, 1, false }, - { "Tau03", spot::explicit_tau03_search, 1, -1U, true }, - { "Tau03_opt", spot::explicit_tau03_opt_search, 0, -1U, true }, + { "Cou99", couvreur99_cons, 0, -1U, true }, + { "Cou99_shy-", couvreur99_shy_minus_cons, 0, -1U, true }, + { "Cou99_shy", couvreur99_shy_cons, 0, -1U, true }, + { "Cou99_rem", couvreur99_rem_cons, 0, -1U, true }, + { "Cou99_rem_shy-", couvreur99_rem_shy_minus_cons, 0, -1U, true }, + { "Cou99_rem_shy", couvreur99_rem_shy_cons, 0, -1U, true }, + { "CVWY90", spot::explicit_magic_search, 0, 1, true }, + { "CVWY90_bsh", bsh_ms_cons, 0, 1, false }, + { "GV04", spot::explicit_gv04_check, 0, 1, true }, + { "SE05", spot::explicit_se05_search, 0, 1, true }, + { "SE05_bsh", bsh_se05_cons, 0, 1, false }, + { "Tau03", spot::explicit_tau03_search, 1, -1U, true }, + { "Tau03_opt", spot::explicit_tau03_opt_search, 0, -1U, true }, }; spot::emptiness_check*