* 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:
parent
ca6084160e
commit
3ea9771942
7 changed files with 395 additions and 74 deletions
|
|
@ -19,6 +19,7 @@
|
|||
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include "misc/hash.hh"
|
||||
#include <list>
|
||||
|
|
@ -42,8 +43,8 @@ namespace spot
|
|||
///
|
||||
/// \pre The automaton \a a must have at most one accepting
|
||||
/// condition (i.e. it is a TBA).
|
||||
magic_search(const tgba *a)
|
||||
: a(a), all_cond(a->all_acceptance_conditions())
|
||||
magic_search(const tgba *a, size_t size)
|
||||
: h(size), a(a), all_cond(a->all_acceptance_conditions())
|
||||
{
|
||||
assert(a->number_of_acceptance_conditions() <= 1);
|
||||
}
|
||||
|
|
@ -165,7 +166,7 @@ namespace spot
|
|||
/// The automata to check.
|
||||
const tgba* a;
|
||||
|
||||
/// The automata to check.
|
||||
/// The unique accepting condition of the automaton \a a.
|
||||
bdd all_cond;
|
||||
|
||||
bool dfs_blue()
|
||||
|
|
@ -181,7 +182,7 @@ namespace spot
|
|||
bdd acc = f.it->current_acceptance_conditions();
|
||||
f.it->next();
|
||||
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)
|
||||
{
|
||||
++nbn;
|
||||
|
|
@ -202,6 +203,8 @@ namespace spot
|
|||
if (dfs_red())
|
||||
return true;
|
||||
}
|
||||
else
|
||||
h.pop_notify(s_prime);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -213,7 +216,7 @@ namespace spot
|
|||
delete f.it;
|
||||
st_blue.pop_front();
|
||||
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
|
||||
&& !st_blue.empty())
|
||||
// the test 'c.get() == BLUE' is added to limit
|
||||
|
|
@ -251,10 +254,10 @@ namespace spot
|
|||
bdd acc = f.it->current_acceptance_conditions();
|
||||
f.it->next();
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
++nbn;
|
||||
|
|
@ -270,6 +273,8 @@ namespace spot
|
|||
if (target->compare(s_prime) == 0)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
h.pop_notify(s_prime);
|
||||
}
|
||||
}
|
||||
else // Backtrack
|
||||
|
|
@ -342,16 +347,16 @@ namespace spot
|
|||
color_ref(color* c) :p(c)
|
||||
{
|
||||
}
|
||||
int get() const
|
||||
color get() const
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
void set(color c)
|
||||
{
|
||||
assert(!is_null());
|
||||
assert(!is_white());
|
||||
*p=c;
|
||||
}
|
||||
bool is_null() const
|
||||
bool is_white() const
|
||||
{
|
||||
return p==0;
|
||||
}
|
||||
|
|
@ -359,7 +364,7 @@ namespace spot
|
|||
color *p;
|
||||
};
|
||||
|
||||
explicit_magic_search_heap()
|
||||
explicit_magic_search_heap(size_t)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -405,11 +410,78 @@ namespace spot
|
|||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,19 +27,19 @@
|
|||
|
||||
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.
|
||||
/// it is a TBA).
|
||||
///
|
||||
/// 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
|
||||
/// paths. The method visits only a finite set of accepting paths.
|
||||
///
|
||||
/// The implemented algorithm is the following.
|
||||
/// paths. The implemented algorithm is the following.
|
||||
///
|
||||
/// \verbatim
|
||||
/// procedure nested_dfs ()
|
||||
/// procedure check ()
|
||||
/// begin
|
||||
/// call dfs_blue(s0);
|
||||
/// end;
|
||||
|
|
@ -72,8 +72,8 @@ namespace spot
|
|||
/// end;
|
||||
/// \endverbatim
|
||||
///
|
||||
/// It is an adaptation to TBA of the Magic Search algorithm
|
||||
/// which deals with accepting states and is presented in
|
||||
/// This algorithm is an adaptation to TBA of the one
|
||||
/// (which deals with accepting states) presented in
|
||||
///
|
||||
/// \verbatim
|
||||
/// Article{ courcoubertis.92.fmsd,
|
||||
|
|
@ -87,20 +87,35 @@ namespace spot
|
|||
/// volume = {1}
|
||||
/// }
|
||||
/// \endverbatim
|
||||
///
|
||||
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.
|
||||
/// 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.
|
||||
/// it is a TBA).
|
||||
///
|
||||
/// 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
|
||||
/// paths. The method visits only a finite set of accepting paths.
|
||||
/// paths. The implemented algorithm is the following:
|
||||
///
|
||||
/// The implemented algorithm is the following:
|
||||
///
|
||||
/// procedure nested_dfs ()
|
||||
/// \verbatim
|
||||
/// procedure check ()
|
||||
/// begin
|
||||
/// weight = 0;
|
||||
/// call dfs_blue(s0);
|
||||
|
|
@ -143,8 +158,9 @@ namespace spot
|
|||
/// end if;
|
||||
/// end for;
|
||||
/// 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
|
||||
/// \verbatim
|
||||
/// InProceedings{ schwoon.05.tacas,
|
||||
|
|
@ -159,12 +175,27 @@ namespace spot
|
|||
/// }
|
||||
/// \endverbatim
|
||||
///
|
||||
/// the extention consists in the introduction of a weight associated
|
||||
/// to each state in the blue stack. The weight represents the number of
|
||||
/// accepting arcs traversed to reach it from the initial state.
|
||||
/// The extention consists in the introduction of a weight associated
|
||||
/// to each state in the blue stack (the cyan states). The weight of a
|
||||
/// 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);
|
||||
|
||||
/// \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
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ namespace spot
|
|||
///
|
||||
/// \pre The automaton \a a must have at most one accepting
|
||||
/// condition (i.e. it is a TBA).
|
||||
se05_search(const tgba *a)
|
||||
: current_weight(0), a(a), all_cond(a->all_acceptance_conditions())
|
||||
se05_search(const tgba *a, size_t size)
|
||||
: current_weight(0), h(size),
|
||||
a(a), all_cond(a->all_acceptance_conditions())
|
||||
{
|
||||
assert(a->number_of_acceptance_conditions() <= 1);
|
||||
}
|
||||
|
|
@ -82,7 +83,7 @@ namespace spot
|
|||
assert(st_blue.empty());
|
||||
const state* s0 = a->get_init_state();
|
||||
++nbn;
|
||||
h.add_new_state(s0, CYAN);
|
||||
h.add_new_state(s0, CYAN, current_weight);
|
||||
push(st_blue, s0, bddfalse, bddfalse);
|
||||
if (dfs_blue())
|
||||
return new result(*this);
|
||||
|
|
@ -182,7 +183,7 @@ namespace spot
|
|||
bdd acc = f.it->current_acceptance_conditions();
|
||||
f.it->next();
|
||||
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)
|
||||
{
|
||||
if (acc == all_cond)
|
||||
|
|
@ -211,6 +212,8 @@ namespace spot
|
|||
if (dfs_red())
|
||||
return true;
|
||||
}
|
||||
else
|
||||
h.pop_notify(s_prime);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -224,7 +227,7 @@ namespace spot
|
|||
if (f_dest.acc == all_cond)
|
||||
--current_weight;
|
||||
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
|
||||
&& !st_blue.empty())
|
||||
// the test 'c.get() == BLUE' is added to limit
|
||||
|
|
@ -262,10 +265,10 @@ namespace spot
|
|||
bdd acc = f.it->current_acceptance_conditions();
|
||||
f.it->next();
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
++nbn;
|
||||
|
|
@ -285,6 +288,8 @@ namespace spot
|
|||
c.set(RED);
|
||||
push(st_red, s_prime, label, acc);
|
||||
}
|
||||
else
|
||||
h.pop_notify(s_prime);
|
||||
}
|
||||
}
|
||||
else // Backtrack
|
||||
|
|
@ -372,10 +377,10 @@ namespace spot
|
|||
: is_cyan(false), weight(0), ph(0), phc(0), ps(0), pc(c)
|
||||
{
|
||||
}
|
||||
int get() const
|
||||
color get() const
|
||||
{
|
||||
if (is_cyan)
|
||||
return CYAN; // the color cyan is fixed to 0
|
||||
return CYAN;
|
||||
return *pc;
|
||||
}
|
||||
int get_weight() const
|
||||
|
|
@ -385,10 +390,12 @@ namespace spot
|
|||
}
|
||||
void set(color c)
|
||||
{
|
||||
assert(!is_null());
|
||||
assert(!is_white());
|
||||
if (is_cyan)
|
||||
{
|
||||
phc->erase(ps);
|
||||
int i = phc->erase(ps);
|
||||
assert(i==1);
|
||||
(void)i;
|
||||
ph->insert(std::make_pair(ps, c));
|
||||
}
|
||||
else
|
||||
|
|
@ -396,7 +403,7 @@ namespace spot
|
|||
*pc=c;
|
||||
}
|
||||
}
|
||||
bool is_null() const
|
||||
bool is_white() const
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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(c!=CYAN || w>=0);
|
||||
if (c == CYAN)
|
||||
hc.insert(std::make_pair(s, w));
|
||||
else
|
||||
|
|
@ -469,7 +477,111 @@ namespace spot
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -477,7 +589,12 @@ namespace spot
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue