* src/tgbaalgos/magic.cc: Add a bit state hashing version.

* src/tgbaalgos/se05.cc: Add a bit state hashing version.
* src/tgbaalgos/magic.hh: Make them public.
* src/tgbatest/ltl2tgba.cc: Add the two new emptiness checks.
* src/tgbatest/emptchk.test: Incorporate tests of src/tgbatest/dfs.test.
* src/tgbatest/dfs.test: Introduce new characteristic explicit tests.
This commit is contained in:
Denis Poitrenaud 2004-11-15 12:16:59 +00:00
parent ca6084160e
commit 3ea9771942
7 changed files with 395 additions and 74 deletions

View file

@ -1,3 +1,12 @@
2004-11-15 Poitrenaud Denis <denis@src.lip6.fr>
* src/tgbaalgos/magic.cc: Add a bit state hashing version.
* src/tgbaalgos/se05.cc: Add a bit state hashing version.
* src/tgbaalgos/magic.hh: Make them public.
* src/tgbatest/ltl2tgba.cc: Add the two new emptiness checks.
* src/tgbatest/emptchk.test: Incorporate tests of src/tgbatest/dfs.test.
* src/tgbatest/dfs.test: Introduce new characteristic explicit tests.
2004-11-14 Alexandre Duret-Lutz <adl@src.lip6.fr> 2004-11-14 Alexandre Duret-Lutz <adl@src.lip6.fr>
* wrap/python/cgi/ltl2tgba.in: Add options to check the produced * wrap/python/cgi/ltl2tgba.in: Add options to check the produced

View file

@ -19,6 +19,7 @@
// 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.
#include <cstring>
#include <iostream> #include <iostream>
#include "misc/hash.hh" #include "misc/hash.hh"
#include <list> #include <list>
@ -42,8 +43,8 @@ namespace spot
/// ///
/// \pre The automaton \a a must have at most one accepting /// \pre The automaton \a a must have at most one accepting
/// condition (i.e. it is a TBA). /// condition (i.e. it is a TBA).
magic_search(const tgba *a) magic_search(const tgba *a, size_t size)
: a(a), all_cond(a->all_acceptance_conditions()) : h(size), a(a), all_cond(a->all_acceptance_conditions())
{ {
assert(a->number_of_acceptance_conditions() <= 1); assert(a->number_of_acceptance_conditions() <= 1);
} }
@ -165,7 +166,7 @@ namespace spot
/// The automata to check. /// The automata to check.
const tgba* a; const tgba* a;
/// The automata to check. /// The unique accepting condition of the automaton \a a.
bdd all_cond; bdd all_cond;
bool dfs_blue() bool dfs_blue()
@ -181,7 +182,7 @@ namespace spot
bdd acc = f.it->current_acceptance_conditions(); bdd acc = f.it->current_acceptance_conditions();
f.it->next(); f.it->next();
typename heap::color_ref c = h.get_color_ref(s_prime); typename heap::color_ref c = h.get_color_ref(s_prime);
if (c.is_null()) if (c.is_white())
// Go down the edge (f.s, <label, acc>, s_prime) // Go down the edge (f.s, <label, acc>, s_prime)
{ {
++nbn; ++nbn;
@ -202,6 +203,8 @@ namespace spot
if (dfs_red()) if (dfs_red())
return true; return true;
} }
else
h.pop_notify(s_prime);
} }
} }
else else
@ -213,7 +216,7 @@ namespace spot
delete f.it; delete f.it;
st_blue.pop_front(); st_blue.pop_front();
typename heap::color_ref c = h.get_color_ref(f_dest.s); typename heap::color_ref c = h.get_color_ref(f_dest.s);
assert(!c.is_null()); assert(!c.is_white());
if (c.get() == BLUE && f_dest.acc == all_cond if (c.get() == BLUE && f_dest.acc == all_cond
&& !st_blue.empty()) && !st_blue.empty())
// the test 'c.get() == BLUE' is added to limit // the test 'c.get() == BLUE' is added to limit
@ -251,10 +254,10 @@ namespace spot
bdd acc = f.it->current_acceptance_conditions(); bdd acc = f.it->current_acceptance_conditions();
f.it->next(); f.it->next();
typename heap::color_ref c = h.get_color_ref(s_prime); typename heap::color_ref c = h.get_color_ref(s_prime);
if (c.is_null()) if (c.is_white())
// Notice that this case is taken into account only to // Notice that this case is taken into account only to
// support successive calls to the check method. Without // support successive calls to the check method. Without
// this functionnality, one can check assert(c.is_null()). // this functionnality, one can check assert(c.is_white()).
// Go down the edge (f.s, <label, acc>, s_prime) // Go down the edge (f.s, <label, acc>, s_prime)
{ {
++nbn; ++nbn;
@ -270,6 +273,8 @@ namespace spot
if (target->compare(s_prime) == 0) if (target->compare(s_prime) == 0)
return true; return true;
} }
else
h.pop_notify(s_prime);
} }
} }
else // Backtrack else // Backtrack
@ -342,16 +347,16 @@ namespace spot
color_ref(color* c) :p(c) color_ref(color* c) :p(c)
{ {
} }
int get() const color get() const
{ {
return *p; return *p;
} }
void set(color c) void set(color c)
{ {
assert(!is_null()); assert(!is_white());
*p=c; *p=c;
} }
bool is_null() const bool is_white() const
{ {
return p==0; return p==0;
} }
@ -359,7 +364,7 @@ namespace spot
color *p; color *p;
}; };
explicit_magic_search_heap() explicit_magic_search_heap(size_t)
{ {
} }
@ -405,11 +410,78 @@ namespace spot
hash_type h; hash_type h;
}; };
class bsh_magic_search_heap
{
public:
class color_ref
{
public:
color_ref(unsigned char *b, unsigned char o): base(b), offset(o*2)
{
}
color get() const
{
return color(((*base) >> offset) & 3U);
}
void set(color c)
{
*base = (*base & ~(3U << offset)) | (c << offset);
}
bool is_white() const
{
return get()==WHITE;
}
private:
unsigned char *base;
unsigned char offset;
};
bsh_magic_search_heap(size_t s)
{
size = s;
h = new unsigned char[size];
memset(h, WHITE, size);
}
~bsh_magic_search_heap()
{
delete[] h;
}
color_ref get_color_ref(const state*& s)
{
size_t ha = s->hash();
return color_ref(&(h[ha%size]), ha%4);
}
void add_new_state(const state* s, color c)
{
color_ref cr(get_color_ref(s));
assert(cr.is_white());
cr.set(c);
}
void pop_notify(const state* s)
{
delete s;
}
private:
size_t size;
unsigned char* h;
};
} // anonymous } // anonymous
emptiness_check* explicit_magic_search(const tgba *a) emptiness_check* explicit_magic_search(const tgba *a)
{ {
return new magic_search<explicit_magic_search_heap>(a); return new magic_search<explicit_magic_search_heap>(a, 0);
}
emptiness_check* bit_state_hashing_magic_search(
const tgba *a, size_t size)
{
return new magic_search<bsh_magic_search_heap>(a, size);
} }
} }

View file

@ -27,19 +27,19 @@
namespace spot namespace spot
{ {
/// \brief Returns an emptiness check on the spot::tgba automaton \a a. /// \brief Returns an emptiness checker on the spot::tgba automaton \a a.
/// During the visit of \a a, the returned checker stores explicitely all
/// the traversed states.
/// ///
/// \pre The automaton \a a must have at most one accepting condition (i.e. /// \pre The automaton \a a must have at most one accepting condition (i.e.
/// it is a TBA). /// it is a TBA).
/// ///
/// The method \a check() of the returned checker can be called several times /// The method \a check() of the returned checker can be called several times
/// (until it returns a null pointer) to enumerate all the visited accepting /// (until it returns a null pointer) to enumerate all the visited accepting
/// paths. The method visits only a finite set of accepting paths. /// paths. The implemented algorithm is the following.
///
/// The implemented algorithm is the following.
/// ///
/// \verbatim /// \verbatim
/// procedure nested_dfs () /// procedure check ()
/// begin /// begin
/// call dfs_blue(s0); /// call dfs_blue(s0);
/// end; /// end;
@ -72,8 +72,8 @@ namespace spot
/// end; /// end;
/// \endverbatim /// \endverbatim
/// ///
/// It is an adaptation to TBA of the Magic Search algorithm /// This algorithm is an adaptation to TBA of the one
/// which deals with accepting states and is presented in /// (which deals with accepting states) presented in
/// ///
/// \verbatim /// \verbatim
/// Article{ courcoubertis.92.fmsd, /// Article{ courcoubertis.92.fmsd,
@ -87,20 +87,35 @@ namespace spot
/// volume = {1} /// volume = {1}
/// } /// }
/// \endverbatim /// \endverbatim
///
emptiness_check* explicit_magic_search(const tgba *a); emptiness_check* explicit_magic_search(const tgba *a);
/// \brief Returns an emptiness checker on the spot::tgba automaton \a a.
/// During the visit of \a a, the returned checker does not store explicitely
/// the traversed states but uses the bit state hashing technic. However, the
/// implemented algorithm is the same as the one of
/// spot::explicit_magic_search.
///
/// \pre The automaton \a a must have at most one accepting condition (i.e.
/// it is a TBA).
///
/// \sa spot::explicit_magic_search
///
emptiness_check* bit_state_hashing_magic_search(const tgba *a, size_t size);
/// \brief Returns an emptiness check on the spot::tgba automaton \a a. /// \brief Returns an emptiness check on the spot::tgba automaton \a a.
/// During the visit of \a a, the returned checker stores explicitely all
/// the traversed states.
/// ///
/// \pre The automaton \a a must have at most one accepting condition (i.e. /// \pre The automaton \a a must have at most one accepting condition (i.e.
/// it is a TBA). /// it is a TBA).
/// ///
/// The method \a check() of the returned checker can be called several times /// The method \a check() of the returned checker can be called several times
/// (until it returns a null pointer) to enumerate all the visited accepting /// (until it returns a null pointer) to enumerate all the visited accepting
/// paths. The method visits only a finite set of accepting paths. /// paths. The implemented algorithm is the following:
/// ///
/// The implemented algorithm is the following: /// \verbatim
/// /// procedure check ()
/// procedure nested_dfs ()
/// begin /// begin
/// weight = 0; /// weight = 0;
/// call dfs_blue(s0); /// call dfs_blue(s0);
@ -143,8 +158,9 @@ namespace spot
/// end if; /// end if;
/// end for; /// end for;
/// end; /// end;
/// \endverbatim
/// ///
/// It is an adaptation to TBA and an extension of the one /// It is an adaptation to TBA (and a slight extension) of the one
/// presented in /// presented in
/// \verbatim /// \verbatim
/// InProceedings{ schwoon.05.tacas, /// InProceedings{ schwoon.05.tacas,
@ -159,12 +175,27 @@ namespace spot
/// } /// }
/// \endverbatim /// \endverbatim
/// ///
/// the extention consists in the introduction of a weight associated /// The extention consists in the introduction of a weight associated
/// to each state in the blue stack. The weight represents the number of /// to each state in the blue stack (the cyan states). The weight of a
/// accepting arcs traversed to reach it from the initial state. /// cyan state corresponds to the number of accepting arcs traversed to reach
/// it from the initial state. Weights are used to detect accepting cycle in
/// the blue dfs.
/// ///
emptiness_check* explicit_se05_search(const tgba *a); emptiness_check* explicit_se05_search(const tgba *a);
/// \brief Returns an emptiness checker on the spot::tgba automaton \a a.
/// During the visit of \a a, the returned checker does not store explicitely
/// the traversed states but uses the bit state hashing technic. However, the
/// implemented algorithm is the same as the one of
/// spot::explicit_se05_search.
///
/// \pre The automaton \a a must have at most one accepting condition (i.e.
/// it is a TBA).
///
/// \sa spot::explicit_se05_search
///
emptiness_check* bit_state_hashing_se05_search(const tgba *a, size_t size);
} }
#endif // SPOT_TGBAALGOS_MAGIC_HH #endif // SPOT_TGBAALGOS_MAGIC_HH

View file

@ -42,8 +42,9 @@ namespace spot
/// ///
/// \pre The automaton \a a must have at most one accepting /// \pre The automaton \a a must have at most one accepting
/// condition (i.e. it is a TBA). /// condition (i.e. it is a TBA).
se05_search(const tgba *a) se05_search(const tgba *a, size_t size)
: current_weight(0), a(a), all_cond(a->all_acceptance_conditions()) : current_weight(0), h(size),
a(a), all_cond(a->all_acceptance_conditions())
{ {
assert(a->number_of_acceptance_conditions() <= 1); assert(a->number_of_acceptance_conditions() <= 1);
} }
@ -82,7 +83,7 @@ namespace spot
assert(st_blue.empty()); assert(st_blue.empty());
const state* s0 = a->get_init_state(); const state* s0 = a->get_init_state();
++nbn; ++nbn;
h.add_new_state(s0, CYAN); h.add_new_state(s0, CYAN, current_weight);
push(st_blue, s0, bddfalse, bddfalse); push(st_blue, s0, bddfalse, bddfalse);
if (dfs_blue()) if (dfs_blue())
return new result(*this); return new result(*this);
@ -182,7 +183,7 @@ namespace spot
bdd acc = f.it->current_acceptance_conditions(); bdd acc = f.it->current_acceptance_conditions();
f.it->next(); f.it->next();
typename heap::color_ref c = h.get_color_ref(s_prime); typename heap::color_ref c = h.get_color_ref(s_prime);
if (c.is_null()) if (c.is_white())
// Go down the edge (f.s, <label, acc>, s_prime) // Go down the edge (f.s, <label, acc>, s_prime)
{ {
if (acc == all_cond) if (acc == all_cond)
@ -211,6 +212,8 @@ namespace spot
if (dfs_red()) if (dfs_red())
return true; return true;
} }
else
h.pop_notify(s_prime);
} }
} }
else else
@ -224,7 +227,7 @@ namespace spot
if (f_dest.acc == all_cond) if (f_dest.acc == all_cond)
--current_weight; --current_weight;
typename heap::color_ref c = h.get_color_ref(f_dest.s); typename heap::color_ref c = h.get_color_ref(f_dest.s);
assert(!c.is_null()); assert(!c.is_white());
if (c.get() == BLUE && f_dest.acc == all_cond if (c.get() == BLUE && f_dest.acc == all_cond
&& !st_blue.empty()) && !st_blue.empty())
// the test 'c.get() == BLUE' is added to limit // the test 'c.get() == BLUE' is added to limit
@ -262,10 +265,10 @@ namespace spot
bdd acc = f.it->current_acceptance_conditions(); bdd acc = f.it->current_acceptance_conditions();
f.it->next(); f.it->next();
typename heap::color_ref c = h.get_color_ref(s_prime); typename heap::color_ref c = h.get_color_ref(s_prime);
if (c.is_null()) if (c.is_white())
// Notice that this case is taken into account only to // Notice that this case is taken into account only to
// support successive calls to the check method. Without // support successive calls to the check method. Without
// this functionnality => assert(c.is_null()) // this functionnality => assert(c.is_white())
// Go down the edge (f.s, <label, acc>, s_prime) // Go down the edge (f.s, <label, acc>, s_prime)
{ {
++nbn; ++nbn;
@ -285,6 +288,8 @@ namespace spot
c.set(RED); c.set(RED);
push(st_red, s_prime, label, acc); push(st_red, s_prime, label, acc);
} }
else
h.pop_notify(s_prime);
} }
} }
else // Backtrack else // Backtrack
@ -372,10 +377,10 @@ namespace spot
: is_cyan(false), weight(0), ph(0), phc(0), ps(0), pc(c) : is_cyan(false), weight(0), ph(0), phc(0), ps(0), pc(c)
{ {
} }
int get() const color get() const
{ {
if (is_cyan) if (is_cyan)
return CYAN; // the color cyan is fixed to 0 return CYAN;
return *pc; return *pc;
} }
int get_weight() const int get_weight() const
@ -385,10 +390,12 @@ namespace spot
} }
void set(color c) void set(color c)
{ {
assert(!is_null()); assert(!is_white());
if (is_cyan) if (is_cyan)
{ {
phc->erase(ps); int i = phc->erase(ps);
assert(i==1);
(void)i;
ph->insert(std::make_pair(ps, c)); ph->insert(std::make_pair(ps, c));
} }
else else
@ -396,7 +403,7 @@ namespace spot
*pc=c; *pc=c;
} }
} }
bool is_null() const bool is_white() const
{ {
return !is_cyan && pc==0; return !is_cyan && pc==0;
} }
@ -409,7 +416,7 @@ namespace spot
color *pc; // point to the color of a state stored in main hash table color *pc; // point to the color of a state stored in main hash table
}; };
explicit_se05_search_heap() explicit_se05_search_heap(size_t)
{ {
} }
@ -454,9 +461,10 @@ namespace spot
return color_ref(&h, &hc, ic->first, ic->second); // cyan state return color_ref(&h, &hc, ic->first, ic->second); // cyan state
} }
void add_new_state(const state* s, color c, int w=0) void add_new_state(const state* s, color c, int w=-1)
{ {
assert(hc.find(s)==hc.end() && h.find(s)==h.end()); assert(hc.find(s)==hc.end() && h.find(s)==h.end());
assert(c!=CYAN || w>=0);
if (c == CYAN) if (c == CYAN)
hc.insert(std::make_pair(s, w)); hc.insert(std::make_pair(s, w));
else else
@ -469,7 +477,111 @@ namespace spot
private: private:
hash_type h; hash_type h; // associate to each blue and red state its color
hcyan_type hc; // associate to each cyan state its weight
};
class bsh_se05_search_heap
{
private:
typedef Sgi::hash_map<const state*, int,
state_ptr_hash, state_ptr_equal> hcyan_type;
public:
class color_ref
{
public:
color_ref(hcyan_type* h, const state* st, int w,
unsigned char *base, unsigned char offset)
: is_cyan(true), weight(w), phc(h), ps(st), b(base), o(offset*2)
{
}
color_ref(unsigned char *base, unsigned char offset)
: is_cyan(false), weight(0), phc(0), ps(0), b(base), o(offset*2)
{
}
color get() const
{
if (is_cyan)
return CYAN;
return color(((*b) >> o) & 3U);
}
int get_weight() const
{
assert(is_cyan);
return weight;
}
void set(color c)
{
if (is_cyan && c!=CYAN)
{
int i = phc->erase(ps);
assert(i==1);
(void)i;
}
*b = (*b & ~(3U << o)) | (c << o);
}
bool is_white() const
{
return !is_cyan && get()==WHITE;
}
const unsigned char* base() const
{
return b;
}
unsigned char offset() const
{
return o;
}
private:
bool is_cyan;
int weight;
hcyan_type* phc;
const state* ps;
unsigned char *b;
unsigned char o;
};
bsh_se05_search_heap(size_t s) : size(s)
{
h = new unsigned char[size];
memset(h, WHITE, size);
}
~bsh_se05_search_heap()
{
delete[] h;
}
color_ref get_color_ref(const state*& s)
{
size_t ha = s->hash();
hcyan_type::iterator ic = hc.find(s);
if (ic!=hc.end())
return color_ref(&hc, ic->first, ic->second, &h[ha%size], ha%4);
return color_ref(&h[ha%size], ha%4);
}
void add_new_state(const state* s, color c, int w=-1)
{
assert(c!=CYAN || w>=0);
assert(get_color_ref(s).is_white());
if (c==CYAN)
hc.insert(std::make_pair(s, w));
else
{
color_ref cr(get_color_ref(s));
cr.set(c);
}
}
void pop_notify(const state* s)
{
delete s;
}
private:
size_t size;
unsigned char* h;
hcyan_type hc; hcyan_type hc;
}; };
@ -477,7 +589,12 @@ namespace spot
emptiness_check* explicit_se05_search(const tgba *a) emptiness_check* explicit_se05_search(const tgba *a)
{ {
return new se05_search<explicit_se05_search_heap>(a); return new se05_search<explicit_se05_search_heap>(a, 0);
}
emptiness_check* bit_state_hashing_se05_search(const tgba *a, size_t size)
{
return new se05_search<bsh_se05_search_heap>(a, size);
} }
} }

View file

@ -25,6 +25,14 @@
set -e set -e
# All examples are TBA (i.e. they have a unique
# accepting condition). Accepting arcs are
# represented by double arrows.
#
# s1=>s2->s3->(large composant from s4 to s9)
# ^ |
# |_______|
cat >blue_counter <<'EOF' cat >blue_counter <<'EOF'
acc = a; acc = a;
s1, s2,, a; s1, s2,, a;
@ -72,6 +80,11 @@ EOF
run 0 ./ltl2tgba -emagic_search -X blue_counter run 0 ./ltl2tgba -emagic_search -X blue_counter
run 0 ./ltl2tgba -ese05_search -X blue_counter run 0 ./ltl2tgba -ese05_search -X blue_counter
# s1->s2->s3->(large composant from s4 to s9)
# ^ ||
# ||______||
# ||______||
cat >blue_last <<'EOF' cat >blue_last <<'EOF'
acc = a; acc = a;
s1, s2,,; s1, s2,,;
@ -119,6 +132,14 @@ EOF
run 0 ./ltl2tgba -emagic_search -X blue_last run 0 ./ltl2tgba -emagic_search -X blue_last
run 0 ./ltl2tgba -ese05_search -X blue_last run 0 ./ltl2tgba -ese05_search -X blue_last
# _______
# | |
# | v
# s1->s2->s3->(large composant from s4 to s9)
# || ^
# ||______||
# ||______||
cat >red <<'EOF' cat >red <<'EOF'
acc = a; acc = a;
s1, s2,,; s1, s2,,;

View file

@ -43,8 +43,12 @@ expect_ce()
expect_ce_do -ecouvreur99_shy -f -D "$1" expect_ce_do -ecouvreur99_shy -f -D "$1"
expect_ce_do -emagic_search "$1" expect_ce_do -emagic_search "$1"
expect_ce_do -emagic_search -f "$1" expect_ce_do -emagic_search -f "$1"
run 0 ./ltl2tgba -ebsh_magic_search "$1"
run 0 ./ltl2tgba -ebsh_magic_search -f "$1"
run 0 ./ltl2tgba -ese05_search "$1" run 0 ./ltl2tgba -ese05_search "$1"
run 0 ./ltl2tgba -ese05_search -f "$1" run 0 ./ltl2tgba -ese05_search -f "$1"
run 0 ./ltl2tgba -ebsh_se05_search "$1"
run 0 ./ltl2tgba -ebsh_se05_search -f "$1"
# Expect multiple accepting runs # Expect multiple accepting runs
test `./ltl2tgba -emagic_search_repeated "$1" | grep Prefix: | wc -l` -ge $2 test `./ltl2tgba -emagic_search_repeated "$1" | grep Prefix: | wc -l` -ge $2
test `./ltl2tgba -ese05_search_repeated "$1" | grep Prefix: | wc -l` -ge $2 test `./ltl2tgba -ese05_search_repeated "$1" | grep Prefix: | wc -l` -ge $2
@ -62,8 +66,12 @@ expect_no()
run 0 ./ltl2tgba -Ecouvreur99_shy -f -D "$1" run 0 ./ltl2tgba -Ecouvreur99_shy -f -D "$1"
run 0 ./ltl2tgba -Emagic_search "$1" run 0 ./ltl2tgba -Emagic_search "$1"
run 0 ./ltl2tgba -Emagic_search -f "$1" run 0 ./ltl2tgba -Emagic_search -f "$1"
run 0 ./ltl2tgba -Ebsh_magic_search "$1"
run 0 ./ltl2tgba -Ebsh_magic_search -f "$1"
run 0 ./ltl2tgba -Ese05_search "$1" run 0 ./ltl2tgba -Ese05_search "$1"
run 0 ./ltl2tgba -Ese05_search -f "$1" run 0 ./ltl2tgba -Ese05_search -f "$1"
run 0 ./ltl2tgba -Ebsh_se05_search "$1"
run 0 ./ltl2tgba -Ebsh_se05_search -f "$1"
test `./ltl2tgba -emagic_search_repeated "!($1)" | test `./ltl2tgba -emagic_search_repeated "!($1)" |
grep Prefix: | wc -l` -ge $2 grep Prefix: | wc -l` -ge $2
test `./ltl2tgba -ese05_search_repeated "!($1)" | test `./ltl2tgba -ese05_search_repeated "!($1)" |

View file

@ -115,8 +115,16 @@ syntax(char* prog)
<< " couvreur99_shy" << std::endl << " couvreur99_shy" << std::endl
<< " magic_search" << std::endl << " magic_search" << std::endl
<< " magic_search_repeated" << std::endl << " magic_search_repeated" << std::endl
<< " bsh_magic_search[(heap size in Mo - 10Mo by default)]"
<< std::endl
<< " bsh_magic_search_repeated[(heap size in MB - 10MB"
<< " by default)]" << std::endl
<< " se05_search" << std::endl << " se05_search" << std::endl
<< " se05_search_repeated" << std::endl; << " se05_search_repeated" << std::endl
<< " bsh_se05_search[(heap size in MB - 10MB by default)]"
<< std::endl
<< " bsh_se05_search_repeated[(heap size in MB - 10MB"
<< " by default)]" << std::endl;
exit(2); exit(2);
} }
@ -134,9 +142,11 @@ main(int argc, char** argv)
int output = 0; int output = 0;
int formula_index = 0; int formula_index = 0;
std::string echeck_algo; std::string echeck_algo;
enum { None, Couvreur, Couvreur2, MagicSearch, Se04Search } echeck = None; enum { None, Couvreur, Couvreur2, MagicSearch, Se05Search } echeck = None;
enum { NoneDup, BFS, DFS } dupexp = NoneDup; enum { NoneDup, BFS, DFS } dupexp = NoneDup;
bool magic_many = false; bool magic_many = false;
bool bit_state_hashing = false;
int heap_size = 10*1024*1024;
bool expect_counter_example = false; bool expect_counter_example = false;
bool from_file = false; bool from_file = false;
int reduc_aut = spot::Reduce_None; int reduc_aut = spot::Reduce_None;
@ -174,23 +184,33 @@ main(int argc, char** argv)
degeneralize_opt = true; degeneralize_opt = true;
} }
else if (!strncmp(argv[formula_index], "-e", 2)) else if (!strncmp(argv[formula_index], "-e", 2))
{ {
if (argv[formula_index][2] != 0) if (argv[formula_index][2] != 0)
echeck_algo = argv[formula_index] + 2; {
else char *p = strchr(argv[formula_index], '(');
echeck_algo = "couvreur99"; if (p && sscanf(p+1, "%d)", &heap_size) == 1)
expect_counter_example = true; *p = '\0';
output = -1; echeck_algo = argv[formula_index] + 2;
} }
else
echeck_algo = "couvreur99";
expect_counter_example = true;
output = -1;
}
else if (!strncmp(argv[formula_index], "-E", 2)) else if (!strncmp(argv[formula_index], "-E", 2))
{ {
if (argv[formula_index][2] != 0) if (argv[formula_index][2] != 0)
echeck_algo = argv[formula_index] + 2; {
else char *p = strchr(argv[formula_index], '(');
echeck_algo = "couvreur99"; if (p && sscanf(p+1, "%d)", &heap_size) == 1)
expect_counter_example = false; *p = '\0';
output = -1; echeck_algo = argv[formula_index] + 2;
} }
else
echeck_algo = "couvreur99";
expect_counter_example = false;
output = -1;
}
else if (!strcmp(argv[formula_index], "-f")) else if (!strcmp(argv[formula_index], "-f"))
{ {
fm_opt = true; fm_opt = true;
@ -344,17 +364,43 @@ main(int argc, char** argv)
degeneralize_opt = true; degeneralize_opt = true;
magic_many = true; magic_many = true;
} }
else if (echeck_algo == "bsh_magic_search")
{
echeck = MagicSearch;
degeneralize_opt = true;
bit_state_hashing = true;
}
else if (echeck_algo == "bsh_magic_search_repeated")
{
echeck = MagicSearch;
degeneralize_opt = true;
bit_state_hashing = true;
magic_many = true;
}
else if (echeck_algo == "se05_search") else if (echeck_algo == "se05_search")
{ {
echeck = Se04Search; echeck = Se05Search;
degeneralize_opt = true; degeneralize_opt = true;
} }
else if (echeck_algo == "se05_search_repeated") else if (echeck_algo == "se05_search_repeated")
{ {
echeck = Se04Search; echeck = Se05Search;
degeneralize_opt = true; degeneralize_opt = true;
magic_many = true; magic_many = true;
} }
else if (echeck_algo == "bsh_se05_search")
{
echeck = Se05Search;
degeneralize_opt = true;
bit_state_hashing = true;
}
else if (echeck_algo == "bsh_se05_search_repeated")
{
echeck = Se05Search;
degeneralize_opt = true;
bit_state_hashing = true;
magic_many = true;
}
else else
{ {
std::cerr << "unknown emptiness-check: " << echeck_algo << std::endl; std::cerr << "unknown emptiness-check: " << echeck_algo << std::endl;
@ -575,15 +621,22 @@ main(int argc, char** argv)
ec = new spot::couvreur99_check_shy(a); ec = new spot::couvreur99_check_shy(a);
break; break;
case MagicSearch: case MagicSearch:
ec_a = degeneralized; ec_a = degeneralized;
ec = spot::explicit_magic_search(degeneralized); if (bit_state_hashing)
break; ec = spot::bit_state_hashing_magic_search(
degeneralized, heap_size);
else
ec = spot::explicit_magic_search(degeneralized);
break;
case Se04Search: case Se05Search:
ec_a = degeneralized; ec_a = degeneralized;
ec = spot::explicit_se05_search(degeneralized); if (bit_state_hashing)
break; ec = spot::bit_state_hashing_se05_search(degeneralized, heap_size);
else
ec = spot::explicit_se05_search(degeneralized);
break;
} }
if (ec) if (ec)
@ -593,13 +646,23 @@ main(int argc, char** argv)
spot::emptiness_check_result* res = ec->check(); spot::emptiness_check_result* res = ec->check();
if (!graph_run_opt) if (!graph_run_opt)
ec->print_stats(std::cout); ec->print_stats(std::cout);
if (expect_counter_example != !!res) if (expect_counter_example != !!res &&
(!bit_state_hashing || !expect_counter_example))
exit_code = 1; exit_code = 1;
if (!res) if (!res)
{ {
std::cout << "no accepting run found" << std::endl; std::cout << "no accepting run found";
break; if (bit_state_hashing && expect_counter_example)
{
std::cout << " even if expected" << std::endl;
std::cout << "this is maybe due to the use of the bit "
<< "state hashing technic" << std::endl;
std::cout << "you can try to increase the heap size "
<< "or use an explicit storage" << std::endl;
}
std::cout << std::endl;
break;
} }
else else
{ {