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:
Alexandre Duret-Lutz 2024-03-24 20:59:52 +01:00
parent 26a62c8b68
commit 7ee2d9995f
6 changed files with 2259 additions and 26 deletions

5
NEWS
View file

@ -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:

View file

@ -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 },

View file

@ -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.

View file

@ -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
}; };

View file

@ -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