* src/misc/optionmap.cc, src/misc/optionmap.hh (option_map): New class.

* src/misc/Makefile.am: Add it.
* src/tgbaalgos/emptiness.cc, src/tgbaalgos/emptiness.hh: Add option
facilities to the classes emptiness_check and emptiness_result
* src/tgbaalgos/magic.cc, src/tgbaalgos/magic.hh,
src/tgbaalgos/se05.cc, src/tgbaalgos/se05.hh: Compute optionnaly
accepting runs from stack.
* src/tgbatest/randtgba.cc: Make this option public.
This commit is contained in:
Denis Poitrenaud 2005-02-07 15:18:41 +00:00
parent e812e1926f
commit 661dee8633
13 changed files with 578 additions and 95 deletions

View file

@ -35,6 +35,7 @@ misc_HEADERS = \
ltstr.hh \
minato.hh \
modgray.hh \
optionmap.hh \
random.hh \
timer.hh \
version.hh
@ -47,6 +48,7 @@ libmisc_la_SOURCES = \
freelist.cc \
minato.cc \
modgray.cc \
optionmap.cc \
random.cc \
timer.cc \
version.cc

102
src/misc/optionmap.cc Normal file
View file

@ -0,0 +1,102 @@
// Copyright (C) 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Spot; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#include <cassert>
#include <cstring>
#include <iostream>
#include "optionmap.hh"
namespace spot
{
namespace {
bool
to_int(const char* s, int &i)
{
char* endptr;
int res = strtol(s, &endptr, 10);
if (*endptr)
{
std::cerr << "Failed to parse `" << s << "' as an integer."
<< std::endl;
return false;
}
i = res;
return true;
}
};
const char* option_map::parse_options(char* options)
{
char* opt = strtok(options, "\t, ;");
while (opt)
{
char* equal;
if ((equal = strchr(opt, '=')) != 0)
{
*equal = 0;
int val;
if (!to_int(equal+1, val))
return opt;
options_[opt] = val;
}
else
// default value if declared
options_[opt] = 1;
opt = strtok(0, "\t, ;");
}
return 0;
}
int option_map::get(const char* option) const
{
std::map<std::string, int>::const_iterator it = options_.find(option);
if (it == options_.end())
// default value if not declared
return 0;
else
return it->second;
}
int option_map::operator[](const char* option) const
{
return get(option);
}
int option_map::set(const char* option, int val)
{
int old = get(option);
options_[option] = val;
return old;
}
int& option_map::operator[](const char* option)
{
return options_[option];
}
std::ostream& operator<<(std::ostream& os, const option_map& m)
{
for (std::map<std::string, int>::const_iterator it = m.options_.begin();
it != m.options_.end(); ++it)
os << "\"" << it->first << "\" = " << it->second << std::endl;
return os;
}
};

74
src/misc/optionmap.hh Normal file
View file

@ -0,0 +1,74 @@
// Copyright (C) 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Spot; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#ifndef SPOT_MISC_OPTION_MAP_HH
# define SPOT_MISC_OPTION_MAP_HH
#include <string>
#include <map>
#include <iosfwd>
namespace spot
{
/// \brief Manage a map of options.
/// \ingroup misc_tools
/// Each option is defined by a string and is associated to an integer value.
class option_map
{
public:
/// \brief Add the parsed options to the map.
///
/// \a options are separated by a space, comma, semicolon or tabulation and
/// can be optionnaly followed by an integer value (preceded by an equal
/// sign). If not specified, the default value is 1.
///
/// \return A non-null pointer to the option for which an expected integer
/// value cannot be parsed.
const char* parse_options(char* options);
/// \brief Get the value of \a option.
///
/// \return The value associated to \a option if it exists, 0 otherwise.
int get(const char* option) const;
/// \brief Get the value of \a option.
///
/// \return The value associated to \a option if it exists, 0 otherwise.
int operator[](const char* option) const;
/// \brief Set the value of \a option to \a val.
///
/// \return The current value associated to \a option if declared,
/// 0 otherwise.
int set(const char* option, int val);
/// \brief Get a reference to the current value of \a option.
int& operator[](const char* option);
/// \brief Print the option_map \a m.
friend std::ostream& operator<<(std::ostream& os, const option_map& m);
private:
std::map<std::string, int> options_;
};
};
#endif

View file

@ -27,7 +27,6 @@
namespace spot
{
tgba_run::~tgba_run()
{
for (steps::const_iterator i = prefix.begin(); i != prefix.end(); ++i)

View file

@ -22,9 +22,11 @@
#ifndef SPOT_TGBAALGOS_EMPTINESS_HH
# define SPOT_TGBAALGOS_EMPTINESS_HH
#include <map>
#include <list>
#include <iosfwd>
#include <bdd.h>
#include "misc/optionmap.hh"
#include "tgba/state.hh"
#include "emptiness_stats.hh"
@ -74,8 +76,13 @@ namespace spot
class emptiness_check_result
{
public:
emptiness_check_result(const tgba* a)
: a_(a)
emptiness_check_result(const tgba* a, option_map o = option_map())
: a_(a), o_(o)
{
}
virtual
~emptiness_check_result()
{
}
@ -100,19 +107,43 @@ namespace spot
return a_;
}
/// Return the options parametrizing how the accepting run is computed.
const option_map&
options() const
{
return o_;
}
/// Modify the options parametrizing how the accepting run is computed.
const char*
parse_options(char* options)
{
option_map old(o_);
const char* s = o_.parse_options(options);
options_updated(old);
return s;
}
/// Return statistics, if available.
virtual const unsigned_statistics* statistics() const;
protected:
/// React when options are modified.
virtual void options_updated(const option_map& old)
{
(void)old;
}
const tgba* a_; ///< The automaton.
option_map o_; ///< The options
};
/// Common interface to emptiness check algorithms.
class emptiness_check
{
public:
emptiness_check(const tgba* a)
: a_(a)
emptiness_check(const tgba* a, option_map o = option_map())
: a_(a), o_(o)
{
}
virtual ~emptiness_check();
@ -124,6 +155,23 @@ namespace spot
return a_;
}
/// Return the options parametrizing how the emptiness check is realized.
const option_map&
options() const
{
return o_;
}
/// Modify the options parametrizing how the accepting run is realized.
const char*
parse_options(char* options)
{
option_map old(o_);
const char* s = o_.parse_options(options);
options_updated(old);
return s;
}
/// \brief Check whether the automaton contain an accepting run.
///
/// Return 0 if the automaton accept no run. Return an instance
@ -142,8 +190,15 @@ namespace spot
/// Print statistics, if any.
virtual std::ostream& print_stats(std::ostream& os) const;
/// React when options are modified.
virtual void options_updated(const option_map& old)
{
(void)old;
}
protected:
const tgba* a_; ///< The automaton.
option_map o_; ///< The options
};
/// @}

View file

@ -53,8 +53,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, size_t size)
: emptiness_check(a),
magic_search(const tgba *a, size_t size, option_map o = option_map())
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
{
@ -96,17 +96,17 @@ namespace spot
h.add_new_state(s0, BLUE);
push(st_blue, s0, bddfalse, bddfalse);
if (dfs_blue())
return new ndfs_result<magic_search<heap>, heap>(*this);
return new magic_search_result(*this, options());
}
else
{
h.pop_notify(st_red.front().s);
pop(st_red);
if (!st_red.empty() && dfs_red())
return new ndfs_result<magic_search<heap>, heap>(*this);
return new magic_search_result(*this, options());
else
if (dfs_blue())
return new ndfs_result<magic_search<heap>, heap>(*this);
return new magic_search_result(*this, options());
}
return 0;
}
@ -314,6 +314,108 @@ namespace spot
return false;
}
class result_from_stack: public emptiness_check_result,
public acss_statistics
{
public:
result_from_stack(magic_search& ms)
: emptiness_check_result(ms.automaton()), ms_(ms)
{
}
virtual tgba_run* accepting_run()
{
assert(!ms_.st_blue.empty());
assert(!ms_.st_red.empty());
tgba_run* run = new tgba_run;
typename stack_type::const_reverse_iterator i, j, end;
tgba_run::steps* l;
l = &run->prefix;
i = ms_.st_blue.rbegin();
end = ms_.st_blue.rend(); --end;
j = i; ++j;
for (; i != end; ++i, ++j)
{
tgba_run::step s = { i->s->clone(), j->label, j->acc };
l->push_back(s);
}
l = &run->cycle;
j = ms_.st_red.rbegin();
tgba_run::step s = { i->s->clone(), j->label, j->acc };
l->push_back(s);
i = j; ++j;
end = ms_.st_red.rend(); --end;
for (; i != end; ++i, ++j)
{
tgba_run::step s = { i->s->clone(), j->label, j->acc };
l->push_back(s);
}
return run;
}
unsigned acss_states() const
{
return 0;
}
private:
magic_search& ms_;
};
# define FROM_STACK "ar:from_stack"
class magic_search_result: public emptiness_check_result
{
public:
magic_search_result(magic_search& m, option_map o = option_map())
: emptiness_check_result(m.automaton(), o), ms(m)
{
if (options()[FROM_STACK])
computer = new result_from_stack(ms);
else
computer = new ndfs_result<magic_search<heap>, heap>(ms);
}
virtual void options_updated(const option_map& old)
{
if (old[FROM_STACK] && !options()[FROM_STACK])
{
delete computer;
computer = new ndfs_result<magic_search<heap>, heap>(ms);
}
else if (!old[FROM_STACK] && options()[FROM_STACK])
{
delete computer;
computer = new result_from_stack(ms);
}
}
virtual ~magic_search_result()
{
delete computer;
}
virtual tgba_run* accepting_run()
{
return computer->accepting_run();
}
virtual const unsigned_statistics* statistics() const
{
return computer->statistics();
}
private:
emptiness_check_result* computer;
magic_search& ms;
};
};
class explicit_magic_search_heap
@ -471,15 +573,15 @@ namespace spot
} // anonymous
emptiness_check* explicit_magic_search(const tgba *a)
emptiness_check* explicit_magic_search(const tgba *a, option_map o)
{
return new magic_search<explicit_magic_search_heap>(a, 0);
return new magic_search<explicit_magic_search_heap>(a, 0, o);
}
emptiness_check* bit_state_hashing_magic_search(
const tgba *a, size_t size)
emptiness_check* bit_state_hashing_magic_search(const tgba *a, size_t size,
option_map o)
{
return new magic_search<bsh_magic_search_heap>(a, size);
return new magic_search<bsh_magic_search_heap>(a, size, o);
}
}

View file

@ -23,6 +23,7 @@
# define SPOT_TGBAALGOS_MAGIC_HH
#include <cstddef>
#include "misc/optionmap.hh"
namespace spot
{
@ -93,7 +94,8 @@ namespace spot
/// }
/// \endverbatim
///
emptiness_check* explicit_magic_search(const tgba *a);
emptiness_check* explicit_magic_search(const tgba *a,
option_map o = option_map());
/// \brief Returns an emptiness checker on the spot::tgba automaton \a a.
///
@ -113,13 +115,17 @@ namespace spot
/// }
/// \endverbatim
///
/// Consequently, the detection of an acceptence cycle is not ensured. The
/// implemented algorithm is the same as the one of
/// Consequently, the detection of an acceptence cycle is not ensured.
///
/// The size of the heap is limited to \n size bytes.
///
/// The implemented algorithm is the same as the one of
/// spot::explicit_magic_search.
///
/// \sa spot::explicit_magic_search
///
emptiness_check* bit_state_hashing_magic_search(const tgba *a, size_t size);
emptiness_check* bit_state_hashing_magic_search(const tgba *a, size_t size,
option_map o = option_map());
/// @}
}

View file

@ -37,8 +37,6 @@
#include "se05.hh"
#include "ndfs_result.hxx"
/// FIXME: make compiling depedent the taking into account of weights.
namespace spot
{
namespace
@ -55,9 +53,8 @@ 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, size_t size)
: emptiness_check(a),
ec_statistics(),
se05_search(const tgba *a, size_t size, option_map o = option_map())
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
{
@ -99,17 +96,17 @@ namespace spot
h.add_new_state(s0, CYAN);
push(st_blue, s0, bddfalse, bddfalse);
if (dfs_blue())
return new ndfs_result<se05_search<heap>, heap>(*this);
return new se05_result(*this, options());
}
else
{
h.pop_notify(st_red.front().s);
pop(st_red);
if (!st_red.empty() && dfs_red())
return new ndfs_result<se05_search<heap>, heap>(*this);
return new se05_result(*this, options());
else
if (dfs_blue())
return new ndfs_result<se05_search<heap>, heap>(*this);
return new se05_result(*this, options());
}
return 0;
}
@ -322,6 +319,114 @@ namespace spot
return false;
}
class result_from_stack: public emptiness_check_result,
public acss_statistics
{
public:
result_from_stack(se05_search& ms)
: emptiness_check_result(ms.automaton()), ms_(ms)
{
}
virtual tgba_run* accepting_run()
{
assert(!ms_.st_blue.empty());
assert(!ms_.st_red.empty());
tgba_run* run = new tgba_run;
typename stack_type::const_reverse_iterator i, j, end;
tgba_run::steps* l;
const state* target = ms_.st_red.front().s;
l = &run->prefix;
i = ms_.st_blue.rbegin();
end = ms_.st_blue.rend(); --end;
j = i; ++j;
for (; i != end; ++i, ++j)
{
if (l == &run->prefix && i->s->compare(target) == 0)
l = &run->cycle;
tgba_run::step s = { i->s->clone(), j->label, j->acc };
l->push_back(s);
}
if (l == &run->prefix && i->s->compare(target) == 0)
l = &run->cycle;
assert(l == &run->cycle);
j = ms_.st_red.rbegin();
tgba_run::step s = { i->s->clone(), j->label, j->acc };
l->push_back(s);
i = j; ++j;
end = ms_.st_red.rend(); --end;
for (; i != end; ++i, ++j)
{
tgba_run::step s = { i->s->clone(), j->label, j->acc };
l->push_back(s);
}
return run;
}
unsigned acss_states() const
{
return 0;
}
private:
se05_search& ms_;
};
# define FROM_STACK "ar:from_stack"
class se05_result: public emptiness_check_result
{
public:
se05_result(se05_search& m, option_map o = option_map())
: emptiness_check_result(m.automaton(), o), ms(m)
{
if (options()[FROM_STACK])
computer = new result_from_stack(ms);
else
computer = new ndfs_result<se05_search<heap>, heap>(ms);
}
virtual void options_updated(const option_map& old)
{
if (old[FROM_STACK] && !options()[FROM_STACK])
{
delete computer;
computer = new ndfs_result<se05_search<heap>, heap>(ms);
}
else if (!old[FROM_STACK] && options()[FROM_STACK])
{
delete computer;
computer = new result_from_stack(ms);
}
}
virtual ~se05_result()
{
delete computer;
}
virtual tgba_run* accepting_run()
{
return computer->accepting_run();
}
virtual const unsigned_statistics* statistics() const
{
return computer->statistics();
}
private:
emptiness_check_result* computer;
se05_search& ms;
};
};
class explicit_se05_search_heap
@ -559,14 +664,15 @@ namespace spot
} // anonymous
emptiness_check* explicit_se05_search(const tgba *a)
emptiness_check* explicit_se05_search(const tgba *a, option_map o)
{
return new se05_search<explicit_se05_search_heap>(a, 0);
return new se05_search<explicit_se05_search_heap>(a, 0, o);
}
emptiness_check* bit_state_hashing_se05_search(const tgba *a, size_t size)
emptiness_check* bit_state_hashing_se05_search(const tgba *a, size_t size,
option_map o)
{
return new se05_search<bsh_se05_search_heap>(a, size);
return new se05_search<bsh_se05_search_heap>(a, size, o);
}
}

View file

@ -23,6 +23,7 @@
# define SPOT_TGBAALGOS_SE05_HH
#include <cstddef>
#include "misc/optionmap.hh"
namespace spot
{
@ -100,8 +101,8 @@ namespace spot
///
/// \sa spot::explicit_magic_search
///
emptiness_check* explicit_se05_search(const tgba *a);
emptiness_check* explicit_se05_search(const tgba *a,
option_map o = option_map());
/// \brief Returns an emptiness checker on the spot::tgba automaton \a a.
///
/// \pre The automaton \a a must have at most one accepting condition (i.e.
@ -120,13 +121,17 @@ namespace spot
/// }
/// \endverbatim
///
/// Consequently, the detection of an acceptence cycle is not ensured. The
/// implemented algorithm is the same as the one of
/// Consequently, the detection of an acceptence cycle is not ensured.
///
/// The size of the heap is limited to \n size bytes.
///
/// The implemented algorithm is the same as the one of
/// spot::explicit_se05_search.
///
/// \sa spot::explicit_se05_search
///
emptiness_check* bit_state_hashing_se05_search(const tgba *a, size_t size);
emptiness_check* bit_state_hashing_se05_search(const tgba *a, size_t size,
option_map o = option_map());
/// @}
}

View file

@ -44,6 +44,7 @@
#include "tgbaalgos/dotty.hh"
#include "tgbaparse/public.hh"
#include "misc/random.hh"
#include "misc/optionmap.hh"
#include "tgba/tgbatba.hh"
#include "tgba/tgbaproduct.hh"
#include "misc/timer.hh"
@ -61,6 +62,7 @@
#include "tgbaalgos/tau03opt.hh"
#include "tgbaalgos/replayrun.hh"
spot::option_map options;
spot::emptiness_check*
couvreur99_cons(const spot::tgba* a)
@ -98,16 +100,28 @@ couvreur99_rem_shy_minus_cons(const spot::tgba* a)
return new spot::couvreur99_check_shy(a, true, false);
}
spot::emptiness_check*
ms_cons(const spot::tgba* a)
{
return spot::explicit_magic_search(a, options);
}
spot::emptiness_check*
se05_cons(const spot::tgba* a)
{
return spot::explicit_se05_search(a, options);
}
spot::emptiness_check*
bsh_ms_cons(const spot::tgba* a)
{
return spot::bit_state_hashing_magic_search(a, 4096);
return spot::bit_state_hashing_magic_search(a, 4096, options);
}
spot::emptiness_check*
bsh_se05_cons(const spot::tgba* a)
{
return spot::bit_state_hashing_se05_search(a, 4096);
return spot::bit_state_hashing_se05_search(a, 4096, options);
}
struct ec_algo
@ -127,10 +141,10 @@ ec_algo ec_algos[] =
{ "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", ms_cons, 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", se05_cons, 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 },
@ -196,8 +210,10 @@ syntax(char* prog)
<< " -O ALGO run Only ALGO" << std::endl
<< " -R N repeat each emptiness-check and accepting run "
<< "computation N times" << std::endl
<< " -r compute and replay acceptance runs (implies -e)"
<< " -r compute and replay accepting runs (implies -e)"
<< std::endl
<< " ar:MODE select the mode MODE for accepting runs computation "
<< "(implies -r)" << std::endl
<< std::endl
<< "Where:" << std::endl
<< " F are floats between 0.0 and 1.0 inclusive" << std::endl
@ -945,6 +961,15 @@ main(int argc, char** argv)
opt_n_acc = to_int_nonneg(argv[++argn], "-a");
opt_a = to_float_nonneg(argv[++argn], "-a");
}
else if (!strncmp(argv[argn], "ar:", 3))
{
if (options.parse_options(argv[argn]))
{
std::cerr << "Failed to parse " << argv[argn] << std::endl;
exit(2);
}
}
else if (!strcmp(argv[argn], "-d"))
{
if (argc < argn + 2)