This is something Soheib and I worked on back in July, but a

intricate memory corruption bug prevented me to check the patch
in.  It took me two days to realize why find_state() must do a
double loop over the candidates to check for equality before
checking for inclusion(s).

* iface/gspn/ltlgspn.cc: New options, -e45 and -n.
* iface/gspn/ssp.cc, iface/gspn/ssp.hh: Handle these.
* src/tgbaalgos/gtec/gtec.cc (TRACE): Add some debugging traces.
(couvreur99_check_shy::dump_queue): New function.
* src/tgbaalgos/gtec/gtec.hh (couvreur99_check_shy::dump_queue):
New function.
This commit is contained in:
Alexandre Duret-Lutz 2008-01-08 13:42:39 +00:00
parent 8d1b5e40b0
commit cc0ca4ae54
6 changed files with 184 additions and 37 deletions

View file

@ -1,3 +1,18 @@
2008-01-08 Alexandre Duret-Lutz <adl@lrde.epita.fr>
This is something Soheib and I worked on back in July, but a
intricate memory corruption bug prevented me to check the patch
in. It took me two days to realize why find_state() must do a
double loop over the candidates to check for equality before
checking for inclusion(s).
* iface/gspn/ltlgspn.cc: New options, -e45 and -n.
* iface/gspn/ssp.cc, iface/gspn/ssp.hh: Handle these.
* src/tgbaalgos/gtec/gtec.cc (TRACE): Add some debugging traces.
(couvreur99_check_shy::dump_queue): New function.
* src/tgbaalgos/gtec/gtec.hh (couvreur99_check_shy::dump_queue):
New function.
2007-11-29 Alexandre Duret-Lutz <adl@lrde.epita.fr> 2007-11-29 Alexandre Duret-Lutz <adl@lrde.epita.fr>
Keep libtool's files under CVS so that we don't use the broken Keep libtool's files under CVS so that we don't use the broken

View file

@ -1,6 +1,6 @@
// Copyright (C) 2003, 2004, 2006, 2007 Laboratoire d'Informatique de Paris 6 // Copyright (C) 2003, 2004, 2006, 2007, 2008 Laboratoire
// (LIP6), département Systèmes Répartis Coopératifs (SRC), // d'Informatique de Paris 6 (LIP6), département Systèmes Répartis
// Université Pierre et Marie Curie. // Coopératifs (SRC), Université Pierre et Marie Curie.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -73,6 +73,7 @@ syntax(char* prog)
<< " -e4 use semi-d. incl. Couvreur's emptiness-check's " << " -e4 use semi-d. incl. Couvreur's emptiness-check's "
<< "shy variant" << "shy variant"
<< std::endl << std::endl
<< " -e45 mix of -e4 and -e5 " << std::endl
<< " -e5 use d. incl. Couvreur's emptiness-check's shy variant" << " -e5 use d. incl. Couvreur's emptiness-check's shy variant"
<< std::endl << std::endl
<< " -e6 like -e5, but without inclusion checks in the " << " -e6 like -e5, but without inclusion checks in the "
@ -80,6 +81,9 @@ syntax(char* prog)
#endif #endif
<< " -m degeneralize and perform a magic-search" << std::endl << " -m degeneralize and perform a magic-search" << std::endl
<< std::endl << std::endl
#ifdef SSP
<< " -n do not perform any decomposition" << std::endl
#endif
<< " -l use Couvreur's LaCIM algorithm for translation (default)" << " -l use Couvreur's LaCIM algorithm for translation (default)"
<< std::endl << std::endl
<< " -f use Couvreur's FM algorithm for translation" << std::endl << " -f use Couvreur's FM algorithm for translation" << std::endl
@ -111,6 +115,8 @@ main(int argc, char **argv)
bool doublehash = true; bool doublehash = true;
bool stack_inclusion = true; bool stack_inclusion = true;
bool pushfront = false; bool pushfront = false;
bool double_inclusion = false;
bool no_decomp = false;
#endif #endif
std::string dead = "true"; std::string dead = "true";
@ -161,6 +167,11 @@ main(int argc, char **argv)
{ {
check = Couvreur4; check = Couvreur4;
} }
else if (!strcmp(argv[formula_index], "-e45"))
{
check = Couvreur5;
double_inclusion = true;
}
else if (!strcmp(argv[formula_index], "-e5")) else if (!strcmp(argv[formula_index], "-e5"))
{ {
check = Couvreur5; check = Couvreur5;
@ -175,6 +186,12 @@ main(int argc, char **argv)
{ {
check = Magic; check = Magic;
} }
#ifdef SSP
else if (!strcmp(argv[formula_index], "-n"))
{
no_decomp = true;
}
#endif
else if (!strcmp(argv[formula_index], "-l")) else if (!strcmp(argv[formula_index], "-l"))
{ {
trans = Lacim; trans = Lacim;
@ -276,7 +293,9 @@ main(int argc, char **argv)
ec = spot::couvreur99_check_ssp_shy_semi(prod); ec = spot::couvreur99_check_ssp_shy_semi(prod);
break; break;
case Couvreur5: case Couvreur5:
ec = spot::couvreur99_check_ssp_shy(prod, stack_inclusion); ec = spot::couvreur99_check_ssp_shy(prod, stack_inclusion,
double_inclusion,
no_decomp);
break; break;
#endif #endif
default: default:
@ -389,6 +408,7 @@ main(int argc, char **argv)
#else #else
delete model; delete model;
delete control; delete control;
delete ca;
#endif #endif
delete a_f; delete a_f;
delete dict; delete dict;

View file

@ -1,6 +1,6 @@
// Copyright (C) 2003, 2004, 2005, 2006, 2007 Laboratoire d'Informatique de // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Laboratoire
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC), // d'Informatique de Paris 6 (LIP6), département Systèmes Répartis
// Université Pierre et Marie Curie. // Coopératifs (SRC), Université Pierre et Marie Curie.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -240,10 +240,11 @@ namespace spot
virtual state* virtual state*
current_state() const current_state() const
{ {
return state_gspn_ssp* s =
new state_gspn_ssp(successors_[current_succ_].succ_, new state_gspn_ssp(successors_[current_succ_].succ_,
(state_array_[successors_[current_succ_] (state_array_[successors_[current_succ_]
.arc->curr_state])->clone()); .arc->curr_state])->clone());
return s;
} }
virtual bdd virtual bdd
@ -992,13 +993,16 @@ namespace spot
class couvreur99_check_shy_ssp : public couvreur99_check_shy class couvreur99_check_shy_ssp : public couvreur99_check_shy
{ {
public: public:
couvreur99_check_shy_ssp(const tgba* a, bool stack_inclusion) couvreur99_check_shy_ssp(const tgba* a, bool stack_inclusion,
bool double_inclusion, bool no_decomp)
: couvreur99_check_shy(a, : couvreur99_check_shy(a,
option_map(), option_map(),
numbered_state_heap_ssp_factory_semi::instance()), numbered_state_heap_ssp_factory_semi::instance()),
inclusion_count_heap(0), inclusion_count_heap(0),
inclusion_count_stack(0), inclusion_count_stack(0),
stack_inclusion(stack_inclusion) stack_inclusion(stack_inclusion),
double_inclusion(double_inclusion),
no_decomp(no_decomp)
{ {
onepass_ = true; onepass_ = true;
@ -1017,6 +1021,8 @@ namespace spot
unsigned inclusion_count_heap; unsigned inclusion_count_heap;
unsigned inclusion_count_stack; unsigned inclusion_count_stack;
bool stack_inclusion; bool stack_inclusion;
bool double_inclusion;
bool no_decomp;
protected: protected:
unsigned unsigned
@ -1063,6 +1069,7 @@ namespace spot
const state_list& l = k->second; const state_list& l = k->second;
state_list::const_iterator j; state_list::const_iterator j;
// Make a first pass looking for identical states.
for (j = l.begin(); j != l.end(); ++j) for (j = l.begin(); j != l.end(); ++j)
{ {
const state_gspn_ssp* old_state = const state_gspn_ssp* old_state =
@ -1073,7 +1080,18 @@ namespace spot
assert(new_state); assert(new_state);
if (old_state->left() == new_state->left()) if (old_state->left() == new_state->left())
break; goto found_match;
}
// Now, check for inclusions.
for (j = l.begin(); j != l.end(); ++j)
{
const state_gspn_ssp* old_state =
dynamic_cast<const state_gspn_ssp*>(*j);
const state_gspn_ssp* new_state =
dynamic_cast<const state_gspn_ssp*>(s);
assert(old_state);
assert(new_state);
if (old_state->left() && new_state->left()) if (old_state->left() && new_state->left())
{ {
@ -1090,42 +1108,83 @@ namespace spot
} }
else else
{ {
if (stack_inclusion
&& double_inclusion
&& spot_inclusion(new_state->left(),
old_state->left()))
break;
if (stack_inclusion if (stack_inclusion
&& spot_inclusion(old_state->left(), && spot_inclusion(old_state->left(),
new_state->left())) new_state->left()))
{ {
++inclusion_count_stack; ++inclusion_count_stack;
State* succ_tgba_ = 0;
size_t size_tgba_ = 0;
succ_queue& queue = todo.back().q; succ_queue& queue = todo.back().q;
Diff_succ(old_state->left(), new_state->left(),
&succ_tgba_, &size_tgba_);
succ_queue::iterator old; succ_queue::iterator old;
if (pos == queue.end()) if (pos == queue.end())
old = queue.begin(); old = queue.begin();
else else
old = pos;
for (size_t i = 0; i < size_tgba_; i++)
{ {
state_gspn_ssp* s = old = pos;
new state_gspn_ssp // Should not happen, because onepass_ == 1
(succ_tgba_[i], assert(0);
old_state->right()->clone());
queue.push_back(successor(old->acc,
s));
inc_depth();
} }
if (size_tgba_ != 0)
diff_succ_free(succ_tgba_); if (no_decomp)
{
queue.push_back // why not push_front?
(successor(old->acc,
old_state->clone()));
assert(pos == queue.end());
inc_depth();
// If we had not done the first loop
// over the container to check for
// equal states, we would have to do
// one here to make sure that state
// s is not equal to another known
// state. (We risk some intricate
// memory corruption if we don't
// delete "clone states" at this
// point.)
// Since we have that first loop and
// we therefore know that state s is
// genuinely new, position j so that
// we won't delete it.
j = l.end();
}
else
{
State* succ_tgba_ = 0;
size_t size_tgba_ = 0;
Diff_succ(old_state->left(),
new_state->left(),
&succ_tgba_, &size_tgba_);
for (size_t i = 0; i < size_tgba_; i++)
{
state_gspn_ssp* s =
new state_gspn_ssp
(succ_tgba_[i],
old_state->right()->clone());
// why not push_front?
queue.push_back(successor(old->acc, s));
inc_depth();
}
if (size_tgba_ != 0)
diff_succ_free(succ_tgba_);
}
break; break;
} }
} }
} }
} }
found_match:
if (j != l.end()) if (j != l.end())
{ {
if (s != *j) if (s != *j)
@ -1166,6 +1225,7 @@ namespace spot
res.first = k->first; res.first = k->first;
res.second = &k->second; res.second = &k->second;
} }
return res; return res;
} }
}; };
@ -1235,10 +1295,12 @@ namespace spot
} }
couvreur99_check* couvreur99_check*
couvreur99_check_ssp_shy(const tgba* ssp_automata, bool stack_inclusion) couvreur99_check_ssp_shy(const tgba* ssp_automata, bool stack_inclusion,
bool double_inclusion, bool no_decomp)
{ {
assert(dynamic_cast<const tgba_gspn_ssp*>(ssp_automata)); assert(dynamic_cast<const tgba_gspn_ssp*>(ssp_automata));
return new couvreur99_check_shy_ssp(ssp_automata, stack_inclusion); return new couvreur99_check_shy_ssp(ssp_automata, stack_inclusion,
double_inclusion, no_decomp);
} }
#if 0 #if 0

View file

@ -56,7 +56,9 @@ namespace spot
couvreur99_check* couvreur99_check_ssp_semi(const tgba* ssp_automata); couvreur99_check* couvreur99_check_ssp_semi(const tgba* ssp_automata);
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,
bool stack_inclusion = true); bool stack_inclusion = true,
bool double_inclusion = false,
bool no_decomp = false);
/// @} /// @}

View file

@ -1,4 +1,4 @@
// Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique de // Copyright (C) 2003, 2004, 2005, 2006, 2008 Laboratoire d'Informatique de
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC), // Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
// Université Pierre et Marie Curie. // Université Pierre et Marie Curie.
// //
@ -19,6 +19,15 @@
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA. // 02111-1307, USA.
// #define TRACE
#include <iostream>
#ifdef TRACE
#define trace std::cerr
#else
#define trace while (0) std::cerr
#endif
#include "gtec.hh" #include "gtec.hh"
#include "ce.hh" #include "ce.hh"
#include "misc/memusage.hh" #include "misc/memusage.hh"
@ -374,6 +383,27 @@ namespace spot
assert(depth() == 0); assert(depth() == 0);
} }
void
couvreur99_check_shy::dump_queue(std::ostream& os)
{
os << "--- TODO ---" << std::endl;
unsigned pos = 0;
for (todo_list::const_iterator ti = todo.begin(); ti != todo.end(); ++ti)
{
++pos;
os << "#" << pos << " s:" << ti->s << " n:" << ti->n
<< " q:{";
for (succ_queue::const_iterator qi = ti->q.begin(); qi != ti->q.end();)
{
os << qi->s;
++qi;
if (qi != ti->q.end())
os << ", ";
}
os << "}" << std::endl;;
}
}
emptiness_check_result* emptiness_check_result*
couvreur99_check_shy::check() couvreur99_check_shy::check()
{ {
@ -382,6 +412,10 @@ namespace spot
for (;;) for (;;)
{ {
#ifdef TRACE
dump_queue();
#endif
assert(ecs_->root.size() == 1 + arc.size()); assert(ecs_->root.size() == 1 + arc.size());
// Get the successors of the current state. // Get the successors of the current state.
@ -390,6 +424,7 @@ namespace spot
// If there is no more successor, backtrack. // If there is no more successor, backtrack.
if (queue.empty()) if (queue.empty())
{ {
trace << "backtrack" << std::endl;
// We have explored all successors of state CURR. // We have explored all successors of state CURR.
const state* curr = todo.back().s; const state* curr = todo.back().s;
@ -451,18 +486,23 @@ namespace spot
old = pos; old = pos;
successor succ = *old; successor succ = *old;
// Beware: the implementation of find_state in ifage/gspn/ssp.cc // Beware: the implementation of find_state in ifage/gspn/ssp.cc
// uses POS and modify QUEUE. // uses POS and modifies QUEUE.
numbered_state_heap::state_index_p sip = find_state(succ.s); numbered_state_heap::state_index_p sip = find_state(succ.s);
if (pos != queue.end()) if (pos != queue.end())
++pos; ++pos;
int* i = sip.second; int* i = sip.second;
trace << "picked state " << succ.s << std::endl;
if (!i) if (!i)
{ {
// It's a new state. // It's a new state.
// If we are seeking known states, just skip it. // If we are seeking known states, just skip it.
if (pos != queue.end()) if (pos != queue.end())
continue; continue;
trace << "new state" << std::endl;
// Otherwise, number it and stack it so we recurse. // Otherwise, number it and stack it so we recurse.
queue.erase(old); queue.erase(old);
dec_depth(); dec_depth();
@ -480,7 +520,12 @@ namespace spot
// Skip dead states. // Skip dead states.
if (*i == -1) if (*i == -1)
continue; {
trace << "dead state" << std::endl;
continue;
}
trace << "merging..." << std::endl;
// Now this is the most interesting case. We have // Now this is the most interesting case. We have
// reached a state S1 which is already part of a // reached a state S1 which is already part of a
@ -542,7 +587,7 @@ namespace spot
todo_list::reverse_iterator last = prev++; todo_list::reverse_iterator last = prev++;
// If group2 is used we insert the last->q in front // If group2 is used we insert the last->q in front
// of prev->q so that the states in prev->q are checked // of prev->q so that the states in prev->q are checked
// for existence again after we have done with the states // for existence again after we have processed the states
// of last->q. Otherwise we just append to the end. // of last->q. Otherwise we just append to the end.
prev->q.splice(group2_ ? prev->q.begin() : prev->q.end(), prev->q.splice(group2_ ? prev->q.begin() : prev->q.end(),
last->q); last->q);

View file

@ -1,4 +1,4 @@
// Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique de // Copyright (C) 2003, 2004, 2005, 2006, 2008 Laboratoire d'Informatique de
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC), // Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
// Université Pierre et Marie Curie. // Université Pierre et Marie Curie.
// //
@ -238,6 +238,9 @@ namespace spot
void clear_todo(); void clear_todo();
/// Dump the queue for debugging.
void dump_queue(std::ostream& os = std::cerr);
/// Whether successors should be grouped for states in the same SCC. /// Whether successors should be grouped for states in the same SCC.
bool group_; bool group_;
// If the "group2" option is set (it implies "group"), we // If the "group2" option is set (it implies "group"), we