gen: hide ks_cobuchi(), introduce aut_pattern()
* spot/gen/automata.hh, spot/gen/automata.cc: Hide ks_cobuchi() behind introduce aut_pattern(), as we have already done for the formulas. * bin/genaut.cc: Simplify using this interface. * python/spot/gen.i: Introduce aut_patterns(). * tests/python/gen.ipynb, tests/python/gen.py: Adjust.
This commit is contained in:
parent
ca7f72bb4b
commit
11ca2803c9
6 changed files with 216 additions and 122 deletions
|
|
@ -17,75 +17,114 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <spot/twa/twagraph.hh>
|
||||
#include <spot/gen/automata.hh>
|
||||
#include <spot/twa/formula2bdd.hh>
|
||||
#include <spot/tl/parse.hh>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace gen
|
||||
{
|
||||
|
||||
twa_graph_ptr
|
||||
ks_cobuchi(unsigned n)
|
||||
namespace
|
||||
{
|
||||
if (n == 0)
|
||||
throw std::runtime_error("ks_cobuchi() expects a positive argument");
|
||||
// the alphabet has four letters:
|
||||
// i, s (for sigma), p (for pi), h (for hash)
|
||||
// we encode this four letters alphabet thanks to two AP a and b
|
||||
// the exact encoding is not important
|
||||
// each letter is a permutation of the set {1..2n}
|
||||
// s = (1 2 .. 2n) the rotation
|
||||
// p = (1 2) the swap of the first two elements
|
||||
// i is the identity
|
||||
// d is the identity on {2..2n} but is undefined on 1
|
||||
static twa_graph_ptr
|
||||
ks_cobuchi(unsigned n)
|
||||
{
|
||||
if (n == 0)
|
||||
throw std::runtime_error("ks_cobuchi expects a positive argument");
|
||||
// the alphabet has four letters:
|
||||
// i, s (for sigma), p (for pi), h (for hash)
|
||||
// we encode this four letters alphabet thanks to two AP a and b
|
||||
// the exact encoding is not important
|
||||
// each letter is a permutation of the set {1..2n}
|
||||
// s = (1 2 .. 2n) the rotation
|
||||
// p = (1 2) the swap of the first two elements
|
||||
// i is the identity
|
||||
// d is the identity on {2..2n} but is undefined on 1
|
||||
|
||||
// the automaton has 2n+1 states, numbered from 0 to 2n
|
||||
// 0 is the initial state and the only non-deterministic state
|
||||
// the automaton has 2n+1 states, numbered from 0 to 2n
|
||||
// 0 is the initial state and the only non-deterministic state
|
||||
|
||||
auto dict = make_bdd_dict();
|
||||
auto aut = make_twa_graph(dict);
|
||||
auto dict = make_bdd_dict();
|
||||
auto aut = make_twa_graph(dict);
|
||||
|
||||
// register aps
|
||||
aut->register_ap("a");
|
||||
aut->register_ap("b");
|
||||
// register aps
|
||||
bdd a = bdd_ithvar(aut->register_ap("a"));
|
||||
bdd b = bdd_ithvar(aut->register_ap("b"));
|
||||
|
||||
// retrieve the four letters, and name them
|
||||
bdd i = formula_to_bdd(parse_formula("a&&b"), dict, aut);
|
||||
bdd s = formula_to_bdd(parse_formula("a&&!b"), dict, aut);
|
||||
bdd p = formula_to_bdd(parse_formula("!a&&b"), dict, aut);
|
||||
bdd h = formula_to_bdd(parse_formula("!a&&!b"), dict, aut);
|
||||
// name the four letters
|
||||
bdd i = a & b;
|
||||
bdd s = a & (!b);
|
||||
bdd p = (!a) & b;
|
||||
bdd h = (!a) & (!b);
|
||||
|
||||
// actually build the automaton
|
||||
aut->new_states(2*n+1);
|
||||
aut->set_init_state(0);
|
||||
aut->set_acceptance(1, acc_cond::acc_code::cobuchi());
|
||||
// actually build the automaton
|
||||
aut->new_states(2*n+1);
|
||||
aut->set_init_state(0);
|
||||
aut->set_acceptance(1, acc_cond::acc_code::cobuchi());
|
||||
|
||||
// from 0, we can non-deterministically jump to any state (except 0) with
|
||||
// any letter.
|
||||
for (unsigned q = 1; q <= 2*n; ++q)
|
||||
aut->new_edge(0, q, bddtrue, {0});
|
||||
// i is the identity
|
||||
for (unsigned q = 1; q <= 2*n; ++q)
|
||||
aut->new_edge(q, q, i);
|
||||
// p swaps 1 and 2, and leaves all other states invariant
|
||||
aut->new_edge(1, 2, p);
|
||||
aut->new_edge(2, 1, p);
|
||||
for (unsigned q = 3; q <= 2*n; ++q)
|
||||
aut->new_edge(q, q, p);
|
||||
// s does to next state (mod 2*n, 0 excluded)
|
||||
aut->new_edge(2*n, 1, s);
|
||||
for (unsigned q = 1; q < 2*n; ++q)
|
||||
aut->new_edge(q, q+1, s);
|
||||
// h is the same as i, except on 1 where it goes back to the initial state
|
||||
aut->new_edge(1, 0, h);
|
||||
for (unsigned q = 2; q <= 2*n; ++q)
|
||||
aut->new_edge(q, q, h);
|
||||
// from 0, we can non-deterministically jump to any state
|
||||
// (except 0) with any letter.
|
||||
for (unsigned q = 1; q <= 2*n; ++q)
|
||||
aut->new_edge(0, q, bddtrue, {0});
|
||||
// i is the identity
|
||||
for (unsigned q = 1; q <= 2*n; ++q)
|
||||
aut->new_edge(q, q, i);
|
||||
// p swaps 1 and 2, and leaves all other states invariant
|
||||
aut->new_edge(1, 2, p);
|
||||
aut->new_edge(2, 1, p);
|
||||
for (unsigned q = 3; q <= 2*n; ++q)
|
||||
aut->new_edge(q, q, p);
|
||||
// s does to next state (mod 2*n, 0 excluded)
|
||||
aut->new_edge(2*n, 1, s);
|
||||
for (unsigned q = 1; q < 2*n; ++q)
|
||||
aut->new_edge(q, q+1, s);
|
||||
// h is the same as i, except on 1 where it goes back to the
|
||||
// initial state
|
||||
aut->new_edge(1, 0, h);
|
||||
for (unsigned q = 2; q <= 2*n; ++q)
|
||||
aut->new_edge(q, q, h);
|
||||
|
||||
aut->merge_edges();
|
||||
aut->prop_state_acc(true);
|
||||
return aut;
|
||||
aut->merge_edges();
|
||||
aut->prop_state_acc(true);
|
||||
return aut;
|
||||
}
|
||||
}
|
||||
|
||||
twa_graph_ptr aut_pattern(aut_pattern_id pattern, int n)
|
||||
{
|
||||
if (n < 0)
|
||||
{
|
||||
std::ostringstream err;
|
||||
err << "pattern argument for " << aut_pattern_name(pattern)
|
||||
<< " should be positive";
|
||||
throw std::runtime_error(err.str());
|
||||
}
|
||||
|
||||
switch (pattern)
|
||||
{
|
||||
// Keep this alphabetically-ordered!
|
||||
case AUT_KS_COBUCHI:
|
||||
return ks_cobuchi(n);
|
||||
case AUT_END:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("unsupported pattern");
|
||||
}
|
||||
|
||||
const char* aut_pattern_name(aut_pattern_id pattern)
|
||||
{
|
||||
static const char* const class_name[] =
|
||||
{
|
||||
"ks-cobuchi",
|
||||
};
|
||||
// Make sure we do not forget to update the above table every
|
||||
// time a new pattern is added.
|
||||
static_assert(sizeof(class_name)/sizeof(*class_name)
|
||||
== AUT_END - AUT_BEGIN, "size mismatch");
|
||||
if (pattern < AUT_BEGIN || pattern >= AUT_END)
|
||||
throw std::runtime_error("unsupported pattern");
|
||||
return class_name[pattern - AUT_BEGIN];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,31 +19,48 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <spot/twa/twagraph.hh>
|
||||
#include <spot/misc/common.hh>
|
||||
#include <spot/twa/fwd.hh>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace gen
|
||||
{
|
||||
/// \brief A family of co-Büchi automata.
|
||||
enum aut_pattern_id {
|
||||
AUT_BEGIN = 256,
|
||||
/// \brief A family of co-Büchi automata.
|
||||
///
|
||||
/// ks_cobuchi(n) is a co-Büchi automaton of size 2n+1 that is
|
||||
/// good-for-games and that has no equivalent deterministic co-Büchi
|
||||
/// automaton with less than 2^n / (2n+1) states.
|
||||
/// For details and other classes, see:
|
||||
///
|
||||
/// @InProceedings{kuperberg2015determinisation,
|
||||
/// author={Kuperberg, Denis and Skrzypczak, Micha{\l}},
|
||||
/// title={On Determinisation of Good-for-Games Automata},
|
||||
/// booktitle={International Colloquium on Automata, Languages, and
|
||||
/// Programming},
|
||||
/// pages={299--310},
|
||||
/// year={2015},
|
||||
/// organization={Springer}
|
||||
/// }
|
||||
///
|
||||
/// Only defined for n>0
|
||||
AUT_KS_COBUCHI = AUT_BEGIN,
|
||||
AUT_END
|
||||
};
|
||||
|
||||
/// \brief generate an automaton from a known pattern
|
||||
///
|
||||
/// ks_cobuchi(n) is a co-Büchi automaton of size 2n+1 that is
|
||||
/// good-for-games and that has no equivalent deterministic co-Büchi
|
||||
/// automaton with less than 2^n / (2n+1) states.
|
||||
/// For details and other classes, see:
|
||||
/// The pattern is specified using one value from the aut_pattern_id
|
||||
/// enum. See the man page of the `genaut` binary for a
|
||||
/// description of those patterns, and bibliographic references.
|
||||
SPOT_API twa_graph_ptr aut_pattern(aut_pattern_id pattern, int n);
|
||||
|
||||
/// \brief convert an aut_pattern_it value into a name
|
||||
///
|
||||
/// @InProceedings{kuperberg2015determinisation,
|
||||
/// author={Kuperberg, Denis and Skrzypczak, Micha{\l}},
|
||||
/// title={On Determinisation of Good-for-Games Automata},
|
||||
/// booktitle={International Colloquium on Automata, Languages, and
|
||||
/// Programming},
|
||||
/// pages={299--310},
|
||||
/// year={2015},
|
||||
/// organization={Springer}
|
||||
/// }
|
||||
///
|
||||
/// \pre n>0
|
||||
SPOT_API twa_graph_ptr
|
||||
ks_cobuchi(unsigned n);
|
||||
/// The returned name is suitable to be used as an option
|
||||
/// key for the genaut binary.
|
||||
SPOT_API const char* aut_pattern_name(aut_pattern_id pattern);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue