ltlcross: Complement deterministic automata.

* src/bin/ltlcross.cc: Complement deterministic automata,
and use them for additional intersection checks.
* NEWS, doc/org/ltlcross.org, src/bin/man/ltlcross.x: Document it.
This commit is contained in:
Alexandre Duret-Lutz 2013-08-18 22:37:25 +02:00
parent 2dda2c9122
commit 1029d08a77
4 changed files with 182 additions and 23 deletions

View file

@ -53,6 +53,7 @@
#include "tgbaalgos/isweakscc.hh"
#include "tgbaalgos/reducerun.hh"
#include "tgbaalgos/word.hh"
#include "tgbaalgos/dbacomp.hh"
#include "misc/formater.hh"
#include "tgbaalgos/stats.hh"
#include "tgbaalgos/isdet.hh"
@ -91,6 +92,7 @@ Exit status:\n\
#define OPT_SEED 8
#define OPT_PRODUCTS 9
#define OPT_COLOR 10
#define OPT_NOCOMP 11
static const argp_option options[] =
{
@ -122,6 +124,8 @@ static const argp_option options[] =
{ "no-checks", OPT_NOCHECKS, 0, 0,
"do not perform any sanity checks (negated formulas "
"will not be translated)", 0 },
{ "no-complement", OPT_NOCOMP, 0, 0,
"do not complement deterministic automata to perform extra checks", 0 },
{ "stop-on-error", OPT_STOP_ERR, 0, 0,
"stop on first execution error or failure to pass"
" sanity checks (timeouts are OK)", 0 },
@ -190,6 +194,7 @@ const char* csv_output = 0;
bool want_stats = false;
bool allow_dups = false;
bool no_checks = false;
bool no_complement = false;
bool stop_on_error = false;
int seed = 0;
unsigned products = 1;
@ -403,6 +408,10 @@ parse_opt(int key, char* arg, struct argp_state*)
break;
case OPT_NOCHECKS:
no_checks = true;
no_complement = true;
break;
case OPT_NOCOMP:
no_complement = true;
break;
case OPT_SEED:
seed = to_pos_int(arg);
@ -850,7 +859,7 @@ namespace
static void
check_empty_prod(const spot::tgba* aut_i, const spot::tgba* aut_j,
size_t i, size_t j)
size_t i, size_t j, bool icomp, bool jcomp)
{
spot::tgba_product* prod = new spot::tgba_product(aut_i, aut_j);
spot::emptiness_check* ec = spot::couvreur99(prod);
@ -858,8 +867,17 @@ namespace
if (res)
{
global_error() << "error: P" << i << "*N" << j
<< " is nonempty";
std::ostream& err = global_error();
err << "error: ";
if (icomp)
err << "Comp(N" << i << ")";
else
err << "P" << i;
if (jcomp)
err << "*Comp(P" << j << ")";
else
err << "*N" << j;
err << " is nonempty";
spot::tgba_run* run = res->accepting_run();
if (run)
@ -1059,9 +1077,16 @@ namespace
}
}
// These store the result of the translation of the positive and
// negative formulas.
size_t m = translators.size();
std::vector<const spot::tgba*> pos(m);
std::vector<const spot::tgba*> neg(m);
// These store the complement of the above results, when we can
// compute it easily.
std::vector<const spot::tgba*> comp_pos(m);
std::vector<const spot::tgba*> comp_neg(m);
unsigned n = vstats.size();
vstats.resize(n + (no_checks ? 1 : 2));
@ -1071,7 +1096,17 @@ namespace
formulas.push_back(fstr);
for (size_t n = 0; n < m; ++n)
pos[n] = runner.translate(n, 'P', pstats);
{
pos[n] = runner.translate(n, 'P', pstats);
// If the automaton is deterministic, compute its complement
// as well. Note that if we have computed statistics
// already, there is no need to call is_deterministic()
// again.
if (!no_complement && pos[n]
&& ((want_stats && !(*pstats)[n].nondeterministic)
|| (!want_stats && is_deterministic(pos[n]))))
comp_pos[n] = dba_complement(pos[n]);
}
// ---------- Negative Formula ----------
@ -1099,7 +1134,17 @@ namespace
formulas.push_back(runner.formula());
for (size_t n = 0; n < m; ++n)
neg[n] = runner.translate(n, 'N', nstats);
{
neg[n] = runner.translate(n, 'N', nstats);
// If the automaton is deterministic, compute its
// complement as well. Note that if we have computed
// statistics already, there is no need to call
// is_deterministic() again.
if (!no_complement && neg[n]
&& ((want_stats && !(*nstats)[n].nondeterministic)
|| (!want_stats && is_deterministic(neg[n]))))
comp_neg[n] = dba_complement(neg[n]);
}
nf->destroy();
}
@ -1116,7 +1161,33 @@ namespace
if (pos[i])
for (size_t j = 0; j < m; ++j)
if (neg[j])
check_empty_prod(pos[i], neg[j], i, j);
{
check_empty_prod(pos[i], neg[j], i, j, false, false);
// Deal with the extra complemented automata if we
// have some.
// If comp_pos[j] and comp_neg[j] exist for the
// same j, it means pos[j] and neg[j] were both
// deterministic. In that case, we will want to
// make sure that comp_pos[j]*comp_neg[j] is empty
// to assert the complementary of pos[j] and
// neg[j]. However using comp_pos[j] and
// comp_neg[j] against other translator will not
// give us any more insight than pos[j] and
// neg[j]. So we only do intersection checks with
// a complement automata when one of the two
// translation was not deterministic.
if (i != j && comp_pos[j] && !comp_neg[j])
check_empty_prod(pos[i], comp_pos[j], i, j, false, true);
if (i != j && comp_neg[i] && !comp_neg[i])
check_empty_prod(comp_neg[i], neg[j], i, j, true, false);
if (comp_pos[i] && comp_neg[j] &&
(i == j || (!comp_neg[i] && !comp_pos[j])))
check_empty_prod(comp_pos[i], comp_neg[j],
i, j, true, true);
}
}
else
{
@ -1236,7 +1307,11 @@ namespace
if (!no_checks)
for (size_t i = 0; i < m; ++i)
delete neg[i];
{
delete neg[i];
delete comp_neg[i];
delete comp_pos[i];
}
for (size_t i = 0; i < m; ++i)
delete pos[i];

View file

@ -81,10 +81,7 @@ Technology. The main motivation for the reimplementation was to
support PSL, and output more statistics about the translations.
The sanity checks performed on the result of each translator (by
either LBTT or ltlcross) are described in the following paper. Our
implementation will detect and reports problems (like inconsistencies
between two translations) but unlike LBTT it does not offer an
interactive mode to investigate such problems.
either LBTT or ltlcross) are described in the following paper.
.TP
th02
@ -92,3 +89,20 @@ H. Tauriainen and K. Heljanko: Testing LTL formula translation into
Büchi automata. Int. J. on Software Tools for Technology Transfer.
Volume 4, number 1, October 2002.
LBTT did not implement Test 2 described in this paper. ltlcross
implements a slight variation: when an automaton produced by some
translator is deterministic, its complement is built and used for
additional cross-comparisons with other tools. If the translation P1
of the positive formula and the translation N1 of the negative formula
both yield deterministic automata (this may only happen for obligation
properties) then the emptiness check of Comp(P1)*Comp(N1) is
equivalent to Test 2 of Tauriainen and Heljanko. If only one
automaton is deterministic, say P1, it can still be used to check we
can be used to check the result of another translators, for instance
checking the emptiness of Comp(P1)*P2.
Our implementation will detect and reports problems (like
inconsistencies between two translations) but unlike LBTT it does not
offer an interactive mode to investigate such problems.