genaut: add two families of cyclic automata
These are meant to test the optimization implemented in issue #568. * spot/gen/automata.hh, spot/gen/automata.cc, bin/genaut.cc: Add support for --cycle-log-nba and --cycle-onehot-nba. * tests/core/genaut.test: Add some tests. * tests/python/gen.ipynb: Illustrate them. * NEWS: Mention them.
This commit is contained in:
parent
26a62c8b68
commit
7ee2d9995f
6 changed files with 2259 additions and 26 deletions
5
NEWS
5
NEWS
|
|
@ -55,6 +55,11 @@ New in spot 2.11.6.dev (not yet released)
|
||||||
patching the game a posteriori is cumbersome if the equivalence
|
patching the game a posteriori is cumbersome if the equivalence
|
||||||
concerns different players).
|
concerns different players).
|
||||||
|
|
||||||
|
- genaut learned two new familes of automata, --cycle-log-nba and
|
||||||
|
--cycle-onehot-nba. They both create a cycle of n^2 states that
|
||||||
|
can be reduced to a cycle of n states using reduction based on
|
||||||
|
direct simulation.
|
||||||
|
|
||||||
Library:
|
Library:
|
||||||
|
|
||||||
- The following new trivial simplifications have been implemented for SEREs:
|
- The following new trivial simplifications have been implemented for SEREs:
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,12 @@ static const argp_option options[] =
|
||||||
{ "cyclist-proof-dba", gen::AUT_CYCLIST_PROOF_DBA, "RANGE", 0,
|
{ "cyclist-proof-dba", gen::AUT_CYCLIST_PROOF_DBA, "RANGE", 0,
|
||||||
"A DBA with N+2 states that should be included "
|
"A DBA with N+2 states that should be included "
|
||||||
"in cyclist-trace-nba=B.", 0},
|
"in cyclist-trace-nba=B.", 0},
|
||||||
|
{ "cycle-log-nba", gen::AUT_CYCLE_LOG_NBA, "RANGE", 0,
|
||||||
|
"A cyclic NBA with N*N states and log(N) atomic propositions, that "
|
||||||
|
"should be simplifiable to a cyclic NBA with N states.", 0 },
|
||||||
|
{ "cycle-onehot-nba", gen::AUT_CYCLE_ONEHOT_NBA, "RANGE", 0,
|
||||||
|
"A cyclic NBA with N*N states and N atomic propositions, that "
|
||||||
|
"should be simplifiable to a cyclic NBA with N states.", 0 },
|
||||||
RANGE_DOC,
|
RANGE_DOC,
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
{ nullptr, 0, nullptr, 0, "Miscellaneous options:", -1 },
|
{ nullptr, 0, nullptr, 0, "Miscellaneous options:", -1 },
|
||||||
|
|
|
||||||
|
|
@ -172,9 +172,10 @@ namespace spot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the smallest integer k such that 2^k ≥ n > 1.
|
||||||
static unsigned ulog2(unsigned n)
|
static unsigned ulog2(unsigned n)
|
||||||
{
|
{
|
||||||
assert(n>0);
|
assert(n>1); // clz() is undefined for n==0
|
||||||
--n;
|
--n;
|
||||||
return CHAR_BIT*sizeof(unsigned) - clz(n);
|
return CHAR_BIT*sizeof(unsigned) - clz(n);
|
||||||
}
|
}
|
||||||
|
|
@ -229,7 +230,7 @@ namespace spot
|
||||||
m = {};
|
m = {};
|
||||||
aut->prop_state_acc(true);
|
aut->prop_state_acc(true);
|
||||||
|
|
||||||
// How many AP to we need to represent n letters
|
// How many AP to we need to represent n+1 letters
|
||||||
unsigned nap = ulog2(n + 1);
|
unsigned nap = ulog2(n + 1);
|
||||||
std::vector<int> apvars(nap);
|
std::vector<int> apvars(nap);
|
||||||
for (unsigned a = 0; a < nap; ++a)
|
for (unsigned a = 0; a < nap; ++a)
|
||||||
|
|
@ -252,6 +253,76 @@ namespace spot
|
||||||
return aut;
|
return aut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static twa_graph_ptr
|
||||||
|
cycle_nba(unsigned n, bool onehot, bdd_dict_ptr dict)
|
||||||
|
{
|
||||||
|
if (n == 0)
|
||||||
|
throw std::runtime_error
|
||||||
|
(onehot
|
||||||
|
? "cycle-onehot-nba expects a positive argument"
|
||||||
|
: "cycle-log-nba expects a positive argument");
|
||||||
|
|
||||||
|
auto aut = make_twa_graph(dict);
|
||||||
|
acc_cond::mark_t isacc = aut->set_buchi();
|
||||||
|
aut->new_states(n * n);
|
||||||
|
aut->set_init_state(0);
|
||||||
|
aut->prop_state_acc(true);
|
||||||
|
aut->prop_weak(n == 1);
|
||||||
|
aut->prop_universal(n == 1);
|
||||||
|
aut->prop_complete(false);
|
||||||
|
|
||||||
|
std::vector<bdd> letters;
|
||||||
|
letters.reserve(n);
|
||||||
|
|
||||||
|
if (!onehot)
|
||||||
|
{
|
||||||
|
// How many AP to we need to represent n letters
|
||||||
|
unsigned nap = n == 1 ? 1 : ulog2(n);
|
||||||
|
std::vector<int> apvars(nap);
|
||||||
|
for (unsigned a = 0; a < nap; ++a)
|
||||||
|
apvars[a] = aut->register_ap("p" + std::to_string(a));
|
||||||
|
|
||||||
|
for (unsigned letter = 0; letter < n; ++letter)
|
||||||
|
{
|
||||||
|
bdd cond = bdd_ibuildcube(letter, nap, apvars.data());
|
||||||
|
letters.push_back(cond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<bdd> apvars(n);
|
||||||
|
bdd allneg = bddtrue;
|
||||||
|
for (unsigned a = 0; a < n; ++a)
|
||||||
|
{
|
||||||
|
int v = aut->register_ap("p" + std::to_string(a));
|
||||||
|
apvars[a] = bdd_ithvar(v);
|
||||||
|
allneg &= bdd_nithvar(v);
|
||||||
|
}
|
||||||
|
for (unsigned a = 0; a < n; ++a)
|
||||||
|
letters.push_back(bdd_exist(allneg, apvars[a]) & apvars[a]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned n2 = n * n;
|
||||||
|
for (unsigned s = 0; s < n; ++s)
|
||||||
|
{
|
||||||
|
bdd label = letters[s];
|
||||||
|
for (unsigned copy = 0; copy < n; ++copy)
|
||||||
|
{
|
||||||
|
unsigned q = s + copy * n;
|
||||||
|
if (s != 0)
|
||||||
|
{
|
||||||
|
aut->new_edge(q, q, bddtrue);
|
||||||
|
aut->new_edge(q, (q + 1) % n2, label);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aut->new_edge(q, (q + 1) % n2, label, isacc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aut;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
twa_graph_ptr aut_pattern(aut_pattern_id pattern, int n, bdd_dict_ptr dict)
|
twa_graph_ptr aut_pattern(aut_pattern_id pattern, int n, bdd_dict_ptr dict)
|
||||||
{
|
{
|
||||||
|
|
@ -278,6 +349,10 @@ namespace spot
|
||||||
return cyclist_trace_or_proof(n, true, dict);
|
return cyclist_trace_or_proof(n, true, dict);
|
||||||
case AUT_CYCLIST_PROOF_DBA:
|
case AUT_CYCLIST_PROOF_DBA:
|
||||||
return cyclist_trace_or_proof(n, false, dict);
|
return cyclist_trace_or_proof(n, false, dict);
|
||||||
|
case AUT_CYCLE_LOG_NBA:
|
||||||
|
return cycle_nba(n, false, dict);
|
||||||
|
case AUT_CYCLE_ONEHOT_NBA:
|
||||||
|
return cycle_nba(n, true, dict);
|
||||||
case AUT_END:
|
case AUT_END:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +369,8 @@ namespace spot
|
||||||
"m-nba",
|
"m-nba",
|
||||||
"cyclist-trace-nba",
|
"cyclist-trace-nba",
|
||||||
"cyclist-proof-dba",
|
"cyclist-proof-dba",
|
||||||
|
"cycle-log-nba",
|
||||||
|
"cycle-onehot-nba",
|
||||||
};
|
};
|
||||||
// Make sure we do not forget to update the above table every
|
// Make sure we do not forget to update the above table every
|
||||||
// time a new pattern is added.
|
// time a new pattern is added.
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,27 @@ namespace spot
|
||||||
/// for a given n contain the automaton generated with
|
/// for a given n contain the automaton generated with
|
||||||
/// AUT_CYCLIST_PROOF_DBA for the same n.
|
/// AUT_CYCLIST_PROOF_DBA for the same n.
|
||||||
AUT_CYCLIST_PROOF_DBA,
|
AUT_CYCLIST_PROOF_DBA,
|
||||||
|
/// \brief cycles of n letters repeated n times
|
||||||
|
///
|
||||||
|
/// This is a Büchi automaton with n^2 states, in which each
|
||||||
|
/// state i has a true self-loop and a successor labeled by the
|
||||||
|
/// (i%n)th letter. Only the states that are multiple of n have
|
||||||
|
/// no self-loop and are accepting.
|
||||||
|
///
|
||||||
|
/// This version uses log(n) atomic propositions to
|
||||||
|
/// encore the n letters as minterms.
|
||||||
|
AUT_CYCLE_LOG_NBA,
|
||||||
|
/// \brief cycles of n letters repeated n times
|
||||||
|
///
|
||||||
|
/// This is a Büchi automaton with n^2 states, in which each
|
||||||
|
/// state i has a true self-loop and a successor labeled by the
|
||||||
|
/// (i%n)th letter. Only the states that are multiple of n have
|
||||||
|
/// no self-loop and are accepting.
|
||||||
|
///
|
||||||
|
/// This version uses one-hot encoding of letters, i.e, n atomic
|
||||||
|
/// propositions are used, but only one is positive (except on
|
||||||
|
/// true self-loops).
|
||||||
|
AUT_CYCLE_ONEHOT_NBA,
|
||||||
AUT_END
|
AUT_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ res=`genaut $opts --stats="--%F=%L"`
|
||||||
test "$opts" = "$res"
|
test "$opts" = "$res"
|
||||||
|
|
||||||
genaut --ks-nca=..3 --l-nba=..3 --l-dsa=..3 --m-nba=..3 \
|
genaut --ks-nca=..3 --l-nba=..3 --l-dsa=..3 --m-nba=..3 \
|
||||||
|
--cycle-log-nba=..3 --cycle-onehot-nba=..3 \
|
||||||
--stats=%s,%e,%t,%c,%g >out
|
--stats=%s,%e,%t,%c,%g >out
|
||||||
cat >expected <<EOF
|
cat >expected <<EOF
|
||||||
3,7,16,1,Fin(0)
|
3,7,16,1,Fin(0)
|
||||||
|
|
@ -43,6 +44,12 @@ cat >expected <<EOF
|
||||||
2,3,4,1,Inf(0)
|
2,3,4,1,Inf(0)
|
||||||
3,6,10,1,Inf(0)
|
3,6,10,1,Inf(0)
|
||||||
4,9,18,1,Inf(0)
|
4,9,18,1,Inf(0)
|
||||||
|
1,1,1,1,Inf(0)
|
||||||
|
4,6,8,1,Inf(0)
|
||||||
|
9,15,33,1,Inf(0)
|
||||||
|
1,1,1,1,Inf(0)
|
||||||
|
4,6,12,1,Inf(0)
|
||||||
|
9,15,57,1,Inf(0)
|
||||||
EOF
|
EOF
|
||||||
diff out expected
|
diff out expected
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue