randaut: better generation of acceptance conditions
* src/bin/randaut.cc: Replace the --acc-type and --acc-sets options by a more general --acceptance option, that take either an acceptance formula, or an acceptance name parametred by ranges. Also accept a range for the number of atomic propositions. * src/twaalgos/randomgraph.cc (random_acceptance): Move... * src/twa/acc.cc, src/twa/acc.hh (random): ... here. (parse_acc_code): Generalize to accept ranges instead of numbers whenever sensible, and accept a 'random' acceptance. * src/tests/randaut.test: Adjust tests and add more. * wrap/python/tests/randaut.ipynb: Adjust call to randaut.
This commit is contained in:
parent
d5598a9aaa
commit
88141b2711
6 changed files with 2150 additions and 1998 deletions
173
src/twa/acc.cc
173
src/twa/acc.cc
|
|
@ -26,6 +26,7 @@
|
|||
#include "acc.hh"
|
||||
#include "priv/bddalloc.hh"
|
||||
#include "misc/minato.hh"
|
||||
#include "misc/random.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -544,6 +545,47 @@ namespace spot
|
|||
return res;
|
||||
}
|
||||
|
||||
acc_cond::acc_code
|
||||
acc_cond::acc_code::random(unsigned n_accs, double reuse)
|
||||
{
|
||||
// With 0 acceptance sets, we always generate the true acceptance.
|
||||
// (Working with false is somehow pointless, and the formulas we
|
||||
// generate for n_accs>0 are always satisfiable, so it makes sense
|
||||
// that it should be satisfiable for n_accs=0 as well.)
|
||||
if (n_accs == 0)
|
||||
return {};
|
||||
|
||||
std::vector<acc_cond::acc_code> codes;
|
||||
codes.reserve(n_accs);
|
||||
for (unsigned i = 0; i < n_accs; ++i)
|
||||
{
|
||||
if (drand() < 0.5)
|
||||
codes.push_back(inf({i}));
|
||||
else
|
||||
codes.push_back(fin({i}));
|
||||
if (reuse > 0.0 && drand() < reuse)
|
||||
--i;
|
||||
}
|
||||
|
||||
int s = codes.size();
|
||||
while (s > 1)
|
||||
{
|
||||
// Pick a random code and put it at the end
|
||||
int p1 = mrand(s--);
|
||||
std::swap(codes[p1], codes[s]);
|
||||
// and another one
|
||||
int p2 = mrand(s);
|
||||
|
||||
if (drand() < 0.5)
|
||||
codes[p2].append_or(std::move(codes.back()));
|
||||
else
|
||||
codes[p2].append_and(std::move(codes.back()));
|
||||
|
||||
codes.pop_back();
|
||||
}
|
||||
return codes[0];
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bdd to_bdd_rec(const acc_cond::acc_word* c, const bdd* map)
|
||||
|
|
@ -1284,12 +1326,75 @@ namespace spot
|
|||
if (errno || num != n)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "syntax error at '" << input << "': value too large.";
|
||||
s << "syntax error at '" << input << "': invalid number.";
|
||||
throw parse_error(s.str());
|
||||
}
|
||||
input = end;
|
||||
return n;
|
||||
}
|
||||
|
||||
return num;
|
||||
static unsigned parse_range(const char*& str)
|
||||
{
|
||||
skip_space(str);
|
||||
int min;
|
||||
int max;
|
||||
char* end;
|
||||
errno = 0;
|
||||
min = strtol(str, &end, 10);
|
||||
if (end == str || errno)
|
||||
{
|
||||
// No leading number. It's OK as long as the string is not
|
||||
// empty.
|
||||
if (!*end || errno)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "syntax error at '" << str << "': invalid range.";
|
||||
throw parse_error(s.str());
|
||||
}
|
||||
min = 1;
|
||||
}
|
||||
if (!*end || (*end != ':' && *end != '.'))
|
||||
{
|
||||
// Only one number.
|
||||
max = min;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip : or ..
|
||||
if (end[0] == ':')
|
||||
++end;
|
||||
else if (end[0] == '.' && end[1] == '.')
|
||||
end += 2;
|
||||
|
||||
// Parse the next integer.
|
||||
char* end2;
|
||||
max = strtol(end, &end2, 10);
|
||||
if (end == end2 || errno)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "syntax error at '" << str
|
||||
<< "': invalid range (missing end?)";
|
||||
throw parse_error(s.str());
|
||||
}
|
||||
end = end2;
|
||||
}
|
||||
|
||||
if (min < 0 || max < 0)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "invalid range '" << str
|
||||
<< "': values must be positive";
|
||||
throw parse_error(s.str());
|
||||
}
|
||||
|
||||
str = end;
|
||||
|
||||
if (min == max)
|
||||
return min;
|
||||
|
||||
if (min > max)
|
||||
std::swap(min, max);
|
||||
return spot::rrand(min, max);
|
||||
}
|
||||
|
||||
static unsigned parse_par_num(const char*& input)
|
||||
|
|
@ -1302,6 +1407,28 @@ namespace spot
|
|||
return num;
|
||||
}
|
||||
|
||||
static double parse_proba(const char*& input)
|
||||
{
|
||||
errno = 0;
|
||||
char* end;
|
||||
double n = strtod(input, &end);
|
||||
if (errno)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "syntax error at '" << input << "': can't convert to double";
|
||||
throw parse_error(s.str());
|
||||
}
|
||||
if (!(n >= 0.0 && n <= 1.0))
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "syntax error at '" << input
|
||||
<< "': value should be between 0 and 1.";
|
||||
throw parse_error(s.str());
|
||||
}
|
||||
input = end;
|
||||
return n;
|
||||
}
|
||||
|
||||
static acc_cond::acc_code parse_term(const char*& input)
|
||||
{
|
||||
acc_cond::acc_code res;
|
||||
|
|
@ -1366,6 +1493,16 @@ namespace spot
|
|||
input += 3;
|
||||
return false;
|
||||
}
|
||||
if (!strncmp(input, "rand", 4))
|
||||
{
|
||||
input += 4;
|
||||
return drand() < 0.5;
|
||||
}
|
||||
if (!strncmp(input, "random", 6))
|
||||
{
|
||||
input += 6;
|
||||
return drand() < 0.5;
|
||||
}
|
||||
std::ostringstream s;
|
||||
s << "syntax error at '" << input
|
||||
<< "': expecting 'min' or 'max'";
|
||||
|
|
@ -1385,6 +1522,16 @@ namespace spot
|
|||
input += 4;
|
||||
return false;
|
||||
}
|
||||
if (!strncmp(input, "rand", 4))
|
||||
{
|
||||
input += 4;
|
||||
return drand() < 0.5;
|
||||
}
|
||||
if (!strncmp(input, "random", 6))
|
||||
{
|
||||
input += 6;
|
||||
return drand() < 0.5;
|
||||
}
|
||||
std::ostringstream s;
|
||||
s << "syntax error at '" << input
|
||||
<< "': expecting 'odd' or 'even'";
|
||||
|
|
@ -1420,22 +1567,22 @@ namespace spot
|
|||
else if (!strncmp(input, "generalized-Buchi", 17))
|
||||
{
|
||||
input += 17;
|
||||
c = acc_cond::acc_code::generalized_buchi(parse_num(input));
|
||||
c = acc_cond::acc_code::generalized_buchi(parse_range(input));
|
||||
}
|
||||
else if (!strncmp(input, "generalized-co-Buchi", 20))
|
||||
{
|
||||
input += 20;
|
||||
c = acc_cond::acc_code::generalized_co_buchi(parse_num(input));
|
||||
c = acc_cond::acc_code::generalized_co_buchi(parse_range(input));
|
||||
}
|
||||
else if (!strncmp(input, "Rabin", 5))
|
||||
{
|
||||
input += 5;
|
||||
c = acc_cond::acc_code::rabin(parse_num(input));
|
||||
c = acc_cond::acc_code::rabin(parse_range(input));
|
||||
}
|
||||
else if (!strncmp(input, "Streett", 7))
|
||||
{
|
||||
input += 7;
|
||||
c = acc_cond::acc_code::streett(parse_num(input));
|
||||
c = acc_cond::acc_code::streett(parse_range(input));
|
||||
}
|
||||
else if (!strncmp(input, "generalized-Rabin", 17))
|
||||
{
|
||||
|
|
@ -1445,7 +1592,7 @@ namespace spot
|
|||
v.reserve(num);
|
||||
while (num > 0)
|
||||
{
|
||||
v.push_back(parse_num(input));
|
||||
v.push_back(parse_range(input));
|
||||
--num;
|
||||
}
|
||||
c = acc_cond::acc_code::generalized_rabin(v.begin(), v.end());
|
||||
|
|
@ -1455,9 +1602,19 @@ namespace spot
|
|||
input += 6;
|
||||
bool max = max_or_min(input);
|
||||
bool odd = odd_or_even(input);
|
||||
unsigned num = parse_num(input);
|
||||
unsigned num = parse_range(input);
|
||||
c = acc_cond::acc_code::parity(max, odd, num);
|
||||
}
|
||||
else if (!strncmp(input, "random", 6))
|
||||
{
|
||||
input += 6;
|
||||
unsigned n = parse_range(input);
|
||||
skip_space(input);
|
||||
double reuse = (*input) ? parse_proba(input) : 0.0;
|
||||
if (reuse >= 1.0)
|
||||
throw parse_error("probability for set reuse should be <1.");
|
||||
c = acc_cond::acc_code::random(n, reuse);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = parse_acc(input);
|
||||
|
|
|
|||
|
|
@ -521,6 +521,11 @@ namespace spot
|
|||
|
||||
static acc_code parity(bool max, bool odd, unsigned sets);
|
||||
|
||||
// Number of acceptance sets to use, and probability to reuse
|
||||
// each set another time after it has been used in the
|
||||
// acceptance formula.
|
||||
static acc_code random(unsigned n, double reuse = 0.0);
|
||||
|
||||
void append_and(acc_code&& r)
|
||||
{
|
||||
if (is_true() || r.is_false())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue