Merge branch master (Spot 1.2.5) into next.

* src/bin/dstar2tgba.cc, src/bin/ltlcross.cc, src/bin/randltl.cc,
src/ltltest/reduccmp.test, src/neverparse/neverclaimparse.yy,
src/tgbatest/ltl2ta.test, src/tgbatest/ltl2tgba.cc,
src/tgbatest/ltlcross.test, src/tgbatest/neverclaimread.test,
wrap/python/ajax/ltl2tgba.html: Fix conflicts.
This commit is contained in:
Alexandre Duret-Lutz 2014-08-22 16:45:41 +02:00
commit 700cf88b06
30 changed files with 1029 additions and 163 deletions

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014 Laboratoire de Recherche et Développement de
// l'Epita (LRDE).
// Copyright (C) 2013, 2014 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
@ -34,6 +34,7 @@
#include "ltlast/formula.hh"
#include "tgbaalgos/dotty.hh"
#include "tgbaalgos/lbtt.hh"
#include "tgbaalgos/hoaf.hh"
#include "tgbaalgos/neverclaim.hh"
#include "tgbaalgos/save.hh"
#include "tgbaalgos/stats.hh"
@ -71,6 +72,10 @@ static const argp_option options[] =
/**************************************************/
{ 0, 0, 0, 0, "Output format:", 3 },
{ "dot", OPT_DOT, 0, 0, "GraphViz's format (default)", 0 },
{ "hoaf", 'H', "s|t|m|l", OPTION_ARG_OPTIONAL,
"Output the automaton in HOA format. Add letters to select "
"(s) state-based acceptance, (t) transition-based acceptance, "
"(m) mixed acceptance, (l) single-line output", 0 },
{ "lbtt", OPT_LBTT, "t", OPTION_ARG_OPTIONAL,
"LBTT's format (add =t to force transition-based acceptance even"
" on Büchi automata)", 0 },
@ -121,9 +126,10 @@ const struct argp_child children[] =
{ 0, 0, 0, 0 }
};
enum output_format { Dot, Lbtt, Lbtt_t, Spin, Spot, Stats } format = Dot;
enum output_format { Dot, Lbtt, Lbtt_t, Spin, Spot, Stats, Hoa } format = Dot;
bool utf8 = false;
const char* stats = "";
const char* hoaf_opt = 0;
spot::option_map extra_options;
static int
@ -141,6 +147,10 @@ parse_opt(int key, char* arg, struct argp_state*)
case 'F':
jobs.emplace_back(arg, true);
break;
case 'H':
format = Hoa;
hoaf_opt = arg;
break;
case 'M':
type = spot::postprocessor::Monitor;
break;
@ -317,6 +327,9 @@ namespace
case Lbtt_t:
spot::lbtt_reachable(std::cout, aut, false);
break;
case Hoa:
spot::hoaf_reachable(std::cout, aut, hoaf_opt) << '\n';
break;
case Spot:
spot::tgba_save_reachable(std::cout, aut);
break;

View file

@ -39,6 +39,7 @@
#include "tgbaalgos/lbtt.hh"
#include "tgbaalgos/neverclaim.hh"
#include "tgbaalgos/save.hh"
#include "tgbaalgos/hoaf.hh"
#include "tgbaalgos/stats.hh"
#include "tgbaalgos/translate.hh"
#include "tgba/bddprint.hh"
@ -72,6 +73,10 @@ static const argp_option options[] =
{ "csv-escape", OPT_CSV, 0, 0, "quote formula output by %f in --format "
"for use in CSV file", 0 },
{ "dot", OPT_DOT, 0, 0, "GraphViz's format (default)", 0 },
{ "hoaf", 'H', "s|t|m|l", OPTION_ARG_OPTIONAL,
"Output the automaton in HOA format. Add letters to select "
"(s) state-based acceptance, (t) transition-based acceptance, "
"(m) mixed acceptance, (l) single-line output", 0 },
{ "lbtt", OPT_LBTT, "t", OPTION_ARG_OPTIONAL,
"LBTT's format (add =t to force transition-based acceptance even"
" on Büchi automata)", 0 },
@ -118,9 +123,10 @@ const struct argp_child children[] =
{ 0, 0, 0, 0 }
};
enum output_format { Dot, Lbtt, Lbtt_t, Spin, Spot, Stats } format = Dot;
enum output_format { Dot, Lbtt, Lbtt_t, Spin, Spot, Stats, Hoa } format = Dot;
bool utf8 = false;
const char* stats = "";
const char* hoaf_opt = 0;
spot::option_map extra_options;
static int
@ -136,6 +142,10 @@ parse_opt(int key, char* arg, struct argp_state*)
case 'B':
type = spot::postprocessor::BA;
break;
case 'H':
format = Hoa;
hoaf_opt = arg;
break;
case 'M':
type = spot::postprocessor::Monitor;
break;
@ -244,6 +254,9 @@ namespace
case Lbtt_t:
spot::lbtt_reachable(std::cout, aut, false);
break;
case Hoa:
spot::hoaf_reachable(std::cout, aut, hoaf_opt, f) << '\n';
break;
case Spot:
spot::tgba_save_reachable(std::cout, aut);
break;

View file

@ -95,6 +95,7 @@ Exit status:\n\
#define OPT_COLOR 10
#define OPT_NOCOMP 11
#define OPT_OMIT 12
#define OPT_BOGUS 13
static const argp_option options[] =
{
@ -160,6 +161,8 @@ static const argp_option options[] =
"colorize output; WHEN can be 'never', 'always' (the default if "
"--color is used without argument), or "
"'auto' (the default if --color is not used)", 0 },
{ "save-bogus", OPT_BOGUS, "FILENAME", 0,
"save formulas for which problems were detected in FILENAME", 0 },
{ 0, 0, 0, 0, 0, 0 }
};
@ -188,7 +191,7 @@ ARGMATCH_VERIFY(color_args, color_types);
color_type color_opt = color_if_tty;
const char* bright_red = "\033[01;31m";
const char* bright_white = "\033[01;37m";
const char* bright_blue = "\033[01;34m";
const char* bright_yellow = "\033[01;33m";
const char* reset_color = "\033[m";
@ -207,6 +210,8 @@ unsigned products = 1;
bool products_avg = true;
bool opt_omit = false;
bool has_sr = false; // Has Streett or Rabin automata to process.
const char* bogus_output_filename = 0;
std::ofstream* bogus_output = 0;
struct translator_spec
{
@ -510,6 +515,14 @@ parse_opt(int key, char* arg, struct argp_state*)
<< "on your platform" << std::endl;
#endif
break;
case OPT_BOGUS:
{
bogus_output = new std::ofstream(arg);
if (!*bogus_output)
error(2, errno, "cannot open '%s'", arg);
bogus_output_filename = arg;
break;
}
case OPT_COLOR:
{
if (arg)
@ -850,7 +863,8 @@ namespace
}
spot::const_tgba_ptr
translate(unsigned int translator_num, char l, statistics_formula* fstats)
translate(unsigned int translator_num, char l, statistics_formula* fstats,
bool& problem)
{
output.reset(translator_num);
@ -875,11 +889,13 @@ namespace
std::cerr << "warning: timeout during execution of command\n";
++timeout_count;
status_str = "timeout";
problem = false; // A timeout is not a sign of a bug
es = -1;
}
else if (WIFSIGNALED(es))
{
status_str = "signal";
problem = true;
es = WTERMSIG(es);
global_error() << "error: execution terminated by signal "
<< es << ".\n";
@ -889,6 +905,7 @@ namespace
{
es = WEXITSTATUS(es);
status_str = "exit code";
problem = true;
global_error() << "error: execution returned exit code "
<< es << ".\n";
end_error();
@ -896,6 +913,7 @@ namespace
else
{
status_str = "ok";
problem = false;
es = 0;
switch (output.format)
{
@ -907,6 +925,7 @@ namespace
if (!pel.empty())
{
status_str = "parse error";
problem = true;
es = -1;
std::ostream& err = global_error();
err << "error: failed to parse the produced neverclaim.\n";
@ -923,6 +942,7 @@ namespace
if (!f)
{
status_str = "no output";
problem = true;
es = -1;
global_error() << "Cannot open " << output.val()
<< std::endl;
@ -934,6 +954,7 @@ namespace
if (!res)
{
status_str = "parse error";
problem = true;
es = -1;
global_error() << ("error: failed to parse output in "
"LBTT format: ")
@ -951,6 +972,7 @@ namespace
if (!pel.empty())
{
status_str = "parse error";
problem = true;
es = -1;
std::ostream& err = global_error();
err << "error: failed to parse the produced DSTAR"
@ -1043,7 +1065,7 @@ namespace
}
};
static void
static bool
check_empty_prod(const spot::const_tgba_ptr& aut_i,
const spot::const_tgba_ptr& aut_j,
size_t i, size_t j, bool icomp, bool jcomp)
@ -1086,9 +1108,10 @@ namespace
}
delete res;
delete ec;
return res;
}
static void
static bool
cross_check(const std::vector<spot::scc_map*>& maps, char l, unsigned p)
{
size_t m = maps.size();
@ -1141,7 +1164,9 @@ namespace
else
err << "the state-space\n";
end_error();
return true;
}
return false;
}
typedef std::set<spot::state*, spot::state_ptr_less_than> state_set;
@ -1204,12 +1229,35 @@ namespace
(*i++)->destroy();
}
int
process_string(const std::string& input,
const char* filename,
int linenum)
{
spot::ltl::parse_error_list pel;
const spot::ltl::formula* f = parse_formula(input, pel);
if (!f || !pel.empty())
{
if (filename)
error_at_line(0, 0, filename, linenum, "parse error:");
spot::ltl::format_parse_errors(std::cerr, input, pel);
if (f)
f->destroy();
return 1;
}
int res = process_formula(f, filename, linenum);
if (res && bogus_output)
*bogus_output << input << std::endl;
return 0;
}
int
process_formula(const spot::ltl::formula* f,
const char* filename = 0, int linenum = 0)
{
(void) filename;
(void) linenum;
static unsigned round = 0;
// If we need LBT atomic proposition in any of the input or
@ -1236,7 +1284,7 @@ namespace
if (filename || linenum)
std::cerr << ' ';
if (color_opt)
std::cerr << bright_white;
std::cerr << bright_blue;
std::cerr << fstr << '\n';
if (color_opt)
std::cerr << reset_color;
@ -1260,6 +1308,9 @@ namespace
}
}
int problems = 0;
// These store the result of the translation of the positive and
// negative formulas.
size_t m = translators.size();
@ -1280,7 +1331,10 @@ namespace
for (size_t n = 0; n < m; ++n)
{
pos[n] = runner.translate(n, 'P', pstats);
bool prob;
pos[n] = runner.translate(n, 'P', pstats, prob);
problems += prob;
// 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()
@ -1318,7 +1372,10 @@ namespace
for (size_t n = 0; n < m; ++n)
{
neg[n] = runner.translate(n, 'N', nstats);
bool prob;
neg[n] = runner.translate(n, 'N', nstats, prob);
problems += prob;
// If the automaton is deterministic, compute its
// complement as well. Note that if we have computed
// statistics already, there is no need to call
@ -1345,7 +1402,8 @@ namespace
for (size_t j = 0; j < m; ++j)
if (neg[j])
{
check_empty_prod(pos[i], neg[j], i, j, false, false);
problems +=
check_empty_prod(pos[i], neg[j], i, j, false, false);
// Deal with the extra complemented automata if we
// have some.
@ -1363,13 +1421,18 @@ namespace
// 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);
problems +=
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);
problems +=
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);
problems +=
check_empty_prod(comp_pos[i], comp_neg[j],
i, j, true, true);
}
}
else
@ -1448,14 +1511,16 @@ namespace
if (!no_checks)
{
// cross-comparison test
cross_check(pos_map, 'P', p);
cross_check(neg_map, 'N', p);
problems += cross_check(pos_map, 'P', p);
problems += cross_check(neg_map, 'N', p);
// consistency check
for (size_t i = 0; i < m; ++i)
if (pos_map[i] && neg_map[i] &&
!(consistency_check(pos_map[i], neg_map[i], statespace)))
{
++problems;
std::ostream& err = global_error();
err << "error: inconsistency between P" << i
<< " and N" << i;
@ -1481,7 +1546,7 @@ namespace
// Shall we stop processing formulas now?
abort_run = global_error_flag && stop_on_error;
return 0;
return problems;
}
};
}
@ -1499,7 +1564,7 @@ print_stats_csv(const char* filename)
else
{
out = outfile = new std::ofstream(filename);
if (!outfile)
if (!*outfile)
error(2, errno, "cannot open '%s'", filename);
}
@ -1537,7 +1602,7 @@ print_stats_json(const char* filename)
else
{
out = outfile = new std::ofstream(filename);
if (!outfile)
if (!*outfile)
error(2, errno, "cannot open '%s'", filename);
}
@ -1616,10 +1681,16 @@ main(int argc, char** argv)
if (global_error_flag)
{
std::ostream& err = global_error();
err << ("error: some error was detected during the above runs,\n"
" please search for 'error:' messages in the above "
"trace.")
<< std::endl;
if (bogus_output)
err << ("error: some error was detected during the above runs.\n"
" Check file ")
<< bogus_output_filename
<< " for problematic formulas.";
else
err << ("error: some error was detected during the above runs,\n"
" please search for 'error:' messages in the above"
" trace.");
err << std::endl;
if (timeout_count == 1)
err << "Additionally, 1 timeout occurred." << std::endl;
else if (timeout_count > 1)
@ -1636,6 +1707,8 @@ main(int argc, char** argv)
<< " timeouts, but no other problem detected." << std::endl;
}
delete bogus_output;
if (json_output)
print_stats_json(json_output);
if (csv_output)

View file

@ -1,5 +1,42 @@
[NAME]
ltl2tgba \- translate LTL/PSL formulas into Büchi automata
[NOTE ON TGBA]
TGBA stands for Transition-based Generalized Büchi Automaton. The
name was coined by Dimitra Giannakopoulou and Flavio Lerda in their
FORTE'02 paper (From States to Transitions: Improving Translation of
LTL Formulae to Büchi Automata), although similar automata have been
used under different names long before that.
As its name implies a TGBA uses a generalized Büchi acceptance
condition, meanings that a run of the automaton is accepted iff it
visits ininitely often multiple acceptance sets, and it also uses
transition-based acceptance, i.e., those acceptance sets are sets of
transitions. TGBA are often more consise than traditional Büchi
automata. For instance the LTL formula \f(CWGFa & GFb\fR can be
translated into a single-state TGBA while a traditional Büchi
automaton would need 3 states. Compare
% ltl2tgba 'GFa & GFb'
with
% ltl2tgba --ba 'GFa & GFb'
In the dot output produced by the above commands, the membership of
the transitions to the various acceptance sets is denoted using names
in braces. The actuall names do not really matter as they may be
produced by the translation algorithm or altered by any latter
postprocessing.
When the \fB\--ba\fR option is used to request a Büchi automaton, Spot
builds a TGBA with a single acceptance set, and in which for any state
either all outgoing transitions are accepting (this is equivalent to
the state being accepting) or none of them are. Double circles are
used to highlight accepting states in the output, but the braces
denoting the accepting transitions are still shown because the
underling structure really is a TGBA.
[NOTE ON LBTT'S FORMAT]
The format, described at
http://www.tcs.hut.fi/Software/lbtt/doc/html/Format-for-automata.html,
@ -10,7 +47,7 @@ internally, it will normally use the transition-based flavor of that
format, indicated with a 't' flag after the number of acceptance sets.
For instance:
% bin/ltl2tgba --lbtt 'GFp0 & GFp1 & FGp2'
% ltl2tgba --lbtt 'GFp0 & GFp1 & FGp2'
2 2t // 2 states, 2 transition-based acceptance sets
0 1 // state 0: initial
0 -1 t // trans. to state 0, no acc., label: true
@ -80,6 +117,38 @@ p[0-9]+ as double-quoted strings.
0 -1 & ! "b" ! "a"
-1
[NOTE ON GENERATING MONITORS]
The monitors generated with option \fB\-M\fR are finite state automata
used to reject finite words that cannot be extended to infinite words
compatible with the supplied formula. The idea is that the monitor
should progress alongside the system, and can only make decisions
based on the finite prefix read so far.
Monitors can be seen as Büchi automata in which all recognized runs are
accepting. As such, the only infinite words they can reject are those
are not recognized, i.e., infinite words that start with a bad prefix.
Because of this limited expressiveness, a monitor for some given LTL
or PSL formula may accept a larger language than the one specified by
the formula. For instance a monitor for the LTL formula \f(CWa U b\fR
will reject (for instance) any word starting with \f(CW!a&!b\fR as
there is no way such a word can validate the formula, but it will not
reject a finite prefix repeating only \f(CWa&!b\fR as such a prefix
could be extented in a way that is comptible with \f(CWa U b\fR.
For more information about monitors, we refer the readers to the
following two papers (the first paper describes the construction of
the second paper in a more concise way):
.TP
\(bu
Deian Tabakov and Moshe Y. Vardi: Optimized Temporal Monitors for SystemC.
Proceedings of RV'10. LNCS 6418.
.TP
\(bu
Marcelo dAmorim and Grigoire Roşu: Efficient monitoring of
ω-languages. Proceedings of CAV'05. LNCS 3576.
[BIBLIOGRAPHY]
If you would like to give a reference to this tool in an article,
we suggest you cite one of the following papers:

View file

@ -44,13 +44,19 @@
#include "misc/hash.hh"
const char argp_program_doc[] ="\
Generate random temporal logic formulas.\v\
Generate random temporal logic formulas.\n\n\
The formulas are built over the atomic propositions named by PROPS...\n\
or, if N is a nonnegative number, using N arbitrary names.\v\
Examples:\n\
\n\
The following generates 10 random LTL formulas over the propositions a, b,\n\
and c, with the default tree-size, and all available operators.\n\
% randltl -n10 a b c\n\
\n\
If you do not mind about the name of the atomic propositions, just give\n\
a number instead:\n\
% ./randltl -n10 3\n\
\n\
You can disable or favor certain operators by changing their priority.\n\
The following disables xor, implies, and equiv, and multiply the probability\n\
of X to occur by 10.\n\
@ -139,6 +145,7 @@ static int opt_seed = 0;
static range opt_tree_size = { 15, 15 };
static bool opt_unique = true;
static bool opt_wf = false;
static bool ap_count_given = false;
void
remove_some_props(spot::ltl::atomic_prop_set& s)
@ -184,7 +191,7 @@ to_int(const char* s)
}
static int
parse_opt(int key, char* arg, struct argp_state*)
parse_opt(int key, char* arg, struct argp_state* as)
{
// This switch is alphabetically-ordered.
switch (key)
@ -235,6 +242,32 @@ parse_opt(int key, char* arg, struct argp_state*)
opt_wf = true;
break;
case ARGP_KEY_ARG:
// If this is the unique non-option argument, it can
// be a number of atomic propositions to build.
//
// argp reorganizes argv[] so that options always come before
// non-options. So if as->argc == as->next we know this is the
// last non-option argument, and if aprops.empty() we know this
// is the also the first one.
if (aprops.empty() && as->argc == as->next)
{
char* endptr;
int res = strtol(arg, &endptr, 10);
if (!*endptr && res >= 0) // arg is a number
{
ap_count_given = true;
spot::ltl::default_environment& e =
spot::ltl::default_environment::instance();
for (int i = 0; i < res; ++i)
{
std::ostringstream p;
p << 'p' << i;
aprops.insert(static_cast<const spot::ltl::atomic_prop*>
(e.require(p.str())));
}
break;
}
}
aprops.insert(static_cast<const spot::ltl::atomic_prop*>
(spot::ltl::default_environment::instance().require(arg)));
break;
@ -249,7 +282,7 @@ main(int argc, char** argv)
{
setup(argv);
const argp ap = { options, parse_opt, "PROP...", argp_program_doc,
const argp ap = { options, parse_opt, "N|PROP...", argp_program_doc,
children, 0, 0 };
if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, 0, 0))
@ -339,14 +372,17 @@ main(int argc, char** argv)
exit(0);
}
if (aprops.empty())
// running 'randltl 0' is one way to generate formulas using no
// atomic propositions so do not complain in that case.
if (aprops.empty() && !ap_count_given)
error(2, 0, "No atomic proposition supplied? Run '%s --help' for usage.",
program_name);
spot::srand(opt_seed);
typedef
std::unordered_set<const spot::ltl::formula*,
const spot::ptr_hash<const spot::ltl::formula>> fset_t;
fset_t unique_set;
spot::ltl::ltl_simplifier simpl(simplifier_options());
@ -357,7 +393,6 @@ main(int argc, char** argv)
unsigned trials = MAX_TRIALS;
bool ignore;
const spot::ltl::formula* f = 0;
spot::srand(opt_seed++);
do
{
ignore = false;

View file

@ -97,3 +97,29 @@ c
EOF
diff expected out2
# atomic proposition can be implicitly specified using a number
$randltl -n 1000 3 --tree-size=10..20 > out
grep -q p0 out
grep -q p1 out
grep -q p2 out
grep p3 out && exit 1
# We should be able to generate exactly two formulas with 0 atomic
# propositions.
run 0 $randltl -n2 0 | sort > out
cat >expected <<EOF
0
1
EOF
diff out expected
# requesting more formulas should fail
run 2 $randltl -n3 0
# If more numbers are given, there are interpreted as atomic propositions
run 0 $randltl -n1000 0 1 > out
grep -q '"0"' out
grep -q '"1"' out

View file

@ -85,7 +85,7 @@ static bool accept_all_seen = false;
%token <str> FORMULA "boolean formula"
%token <str> IDENT "identifier"
%type <b> formula
%type <str> opt_dest
%type <str> opt_dest formula_or_ident
%type <p> transition src_dest
%type <list> transitions transition_block
%type <str> ident_list
@ -193,7 +193,9 @@ transitions:
}
formula: FORMULA
formula_or_ident: FORMULA | IDENT
formula: formula_or_ident
{
formula_cache::const_iterator i = fcache.find(*$1);
if (i == fcache.end())

View file

@ -42,6 +42,7 @@ tgbaalgos_HEADERS = \
emptiness.hh \
emptiness_stats.hh \
gv04.hh \
hoaf.hh \
isdet.hh \
isweakscc.hh \
lbtt.hh \
@ -87,6 +88,7 @@ libtgbaalgos_la_SOURCES = \
dupexp.cc \
emptiness.cc \
gv04.cc \
hoaf.cc \
isdet.cc \
isweakscc.cc \
lbtt.cc \

364
src/tgbaalgos/hoaf.cc Normal file
View file

@ -0,0 +1,364 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2014 Laboratoire de Recherche et
// Developpement de l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// 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 <ostream>
#include <sstream>
#include <map>
#include "tgba/tgba.hh"
#include "hoaf.hh"
#include "reachiter.hh"
#include "misc/escape.hh"
#include "misc/bddlt.hh"
#include "misc/minato.hh"
#include "tgba/formula2bdd.hh"
#include "ltlvisit/tostring.hh"
namespace spot
{
namespace
{
struct metadata
{
// Assign a number to each atomic proposition.
typedef std::map<int, unsigned> ap_map;
ap_map ap;
typedef std::vector<int> vap_t;
vap_t vap;
// Assign a number to each acceptance condition.
typedef std::map<bdd, unsigned, bdd_less_than> acc_map;
acc_map acc;
// Map each state to a number.
typedef std::unordered_map<const state*, unsigned,
state_ptr_hash, state_ptr_equal> state_map;
state_map sm;
// Map each number to its states.
typedef std::vector<const state*> number_map;
number_map nm;
std::vector<bool> common_acc;
bool state_acc;
bool is_complete;
bool is_deterministic;
// Label support: the set of all conditions occurring in the
// automaton.
typedef std::map<bdd, std::string, bdd_less_than> sup_map;
sup_map sup;
metadata(const const_tgba_ptr& aut)
: state_acc(true), is_complete(true), is_deterministic(true)
{
number_all_acc(aut);
number_all_states_and_fill_sup(aut);
number_all_ap();
}
void number_all_acc(const const_tgba_ptr& aut)
{
bdd all_acc = aut->all_acceptance_conditions();
unsigned count = 0;
while (all_acc != bddfalse)
{
bdd one = bdd_satone(all_acc);
all_acc -= one;
acc[one] = count++;
}
}
std::ostream&
emit_acc(std::ostream& os, bdd b)
{
// FIXME: We could use a cache for this.
if (b == bddfalse)
return os;
os << " {";
bool notfirst = false;
while (b != bddfalse)
{
bdd one = bdd_satone(b);
b -= one;
if (notfirst)
os << ' ';
else
notfirst = true;
os << acc[one];
}
os << '}';
return os;
}
void number_all_states_and_fill_sup(const const_tgba_ptr& aut)
{
std::string empty;
// Scan the whole automaton to number states.
std::deque<const state*> todo;
const state* init = aut->get_init_state();
sm[init] = 0;
nm.push_back(init);
todo.push_back(init);
while (!todo.empty())
{
auto src = todo.front();
todo.pop_front();
bdd prev = bddtrue;
bool st_acc = true;
bdd sum = bddfalse;
bdd available = bddtrue;
for (auto i: aut->succ(src))
{
const state* dst = i->current_state();
bdd cond = i->current_condition();
if (is_complete)
sum |= cond;
if (is_deterministic)
{
if (!bdd_implies(cond, available))
is_deterministic = false;
else
available -= cond;
}
sup.insert(std::make_pair(cond, empty));
if (sm.insert(std::make_pair(dst, nm.size())).second)
{
nm.push_back(dst);
todo.push_back(dst);
}
else
{
dst->destroy();
}
if (st_acc)
{
bdd acc = i->current_acceptance_conditions();
if (prev != bddtrue && prev != acc)
st_acc = false;
else
prev = acc;
}
}
if (is_complete)
is_complete &= sum == bddtrue;
common_acc.push_back(st_acc);
state_acc &= st_acc;
}
}
void number_all_ap()
{
sup_map::iterator i;
bdd all = bddtrue;
for (i = sup.begin(); i != sup.end(); ++i)
all &= bdd_support(i->first);
while (all != bddtrue)
{
int v = bdd_var(all);
all = bdd_high(all);
ap.insert(std::make_pair(v, vap.size()));
vap.push_back(v);
}
for (i = sup.begin(); i != sup.end(); ++i)
{
bdd cond = i->first;
if (cond == bddtrue)
{
i->second = "t";
continue;
}
if (cond == bddfalse)
{
i->second = "f";
continue;
}
std::ostringstream s;
bool notfirstor = false;
minato_isop isop(cond);
bdd cube;
while ((cube = isop.next()) != bddfalse)
{
if (notfirstor)
s << " | ";
bool notfirstand = false;
while (cube != bddtrue)
{
if (notfirstand)
s << '&';
else
notfirstand = true;
bdd h = bdd_high(cube);
if (h == bddfalse)
{
s << '!' << ap[bdd_var(cube)];
cube = bdd_low(cube);
}
else
{
s << ap[bdd_var(cube)];
cube = h;
}
}
notfirstor = true;
}
i->second = s.str();
}
}
};
}
std::ostream&
hoaf_reachable(std::ostream& os,
const const_tgba_ptr& aut,
const ltl::formula* f,
hoaf_acceptance acceptance,
hoaf_alias alias,
bool newline)
{
(void) alias;
metadata md(aut);
if (acceptance == Hoaf_Acceptance_States
&& !md.state_acc)
acceptance = Hoaf_Acceptance_Transitions;
unsigned num_states = md.nm.size();
const char nl = newline ? '\n' : ' ';
os << "HOA: v1" << nl;
if (f)
escape_str(os << "name: \"", to_string(f)) << '"' << nl;
os << "States: " << num_states << nl
<< "Start: 0" << nl
<< "AP: " << md.vap.size();
auto d = aut->get_dict();
for (metadata::vap_t::const_iterator i = md.vap.begin();
i != md.vap.end(); ++i)
escape_str(os << " \"", to_string(d->bdd_map[*i].f)) << '"';
os << nl;
unsigned num_acc = md.acc.size();
if (num_acc == 0)
os << "acc-name: all";
else if (num_acc == 1)
os << "acc-name: Buchi";
else
os << "acc-name: generalized-Buchi " << num_acc;
os << nl;
os << "Acceptance: " << num_acc;
if (num_acc > 0)
{
os << " I(0";
for (unsigned i = 1; i < num_acc; ++i)
os << ")&I(" << i;
os << ')';
}
else
{
os << " t";
}
os << nl;
os << "properties: trans-labels explicit-labels";
if (acceptance == Hoaf_Acceptance_States)
os << " state-acc";
else if (acceptance == Hoaf_Acceptance_Transitions)
os << " trans-acc";
if (md.is_complete)
os << " complete";
if (md.is_deterministic)
os << " deterministic";
os << nl;
os << "--BODY--" << nl;
for (unsigned i = 0; i < num_states; ++i)
{
hoaf_acceptance this_acc = acceptance;
if (this_acc == Hoaf_Acceptance_Mixed)
this_acc = (md.common_acc[i] ?
Hoaf_Acceptance_States : Hoaf_Acceptance_Transitions);
tgba_succ_iterator* j = aut->succ_iter(md.nm[i]);
j->first();
os << "State: " << i;
if (this_acc == Hoaf_Acceptance_States && !j->done())
md.emit_acc(os, j->current_acceptance_conditions());
os << nl;
for (; !j->done(); j->next())
{
const state* dst = j->current_state();
os << '[' << md.sup[j->current_condition()] << "] " << md.sm[dst];
if (this_acc == Hoaf_Acceptance_Transitions)
md.emit_acc(os, j->current_acceptance_conditions());
os << nl;
dst->destroy();
}
aut->release_iter(j);
}
os << "--END--"; // No newline. Let the caller decide.
for (unsigned i = 0; i < num_states; ++i)
md.nm[i]->destroy();
return os;
}
std::ostream&
hoaf_reachable(std::ostream& os,
const const_tgba_ptr& aut,
const char* opt,
const ltl::formula* f)
{
bool newline = true;
hoaf_acceptance acceptance = Hoaf_Acceptance_States;
hoaf_alias alias = Hoaf_Alias_None;
if (opt)
while (*opt)
{
switch (*opt++)
{
case 'l':
newline = false;
break;
case 'm':
acceptance = Hoaf_Acceptance_Mixed;
break;
case 's':
acceptance = Hoaf_Acceptance_States;
break;
case 't':
acceptance = Hoaf_Acceptance_Transitions;
break;
}
}
return hoaf_reachable(os, aut, f, acceptance, alias, newline);
}
}

67
src/tgbaalgos/hoaf.hh Normal file
View file

@ -0,0 +1,67 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2014 Laboratoire de Recherche et Développement de
// l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SPOT_TGBAALGOS_HOAF_HH
# define SPOT_TGBAALGOS_HOAF_HH
#include <iosfwd>
#include "ltlast/formula.hh"
#include "tgba/fwd.hh"
namespace spot
{
class tgba;
enum hoaf_alias { Hoaf_Alias_None, Hoaf_Alias_Ap, Hoaf_Alias_Cond };
enum hoaf_acceptance
{
Hoaf_Acceptance_States, /// state-based acceptance if
/// (globally) possible
/// transition-based acceptance
/// otherwise.
Hoaf_Acceptance_Transitions, /// transition-based acceptance globally
Hoaf_Acceptance_Mixed /// mix state-based and transition-based
};
/// \ingroup tgba_io
/// \brief Print reachable states in Hanoi Omega Automata format.
///
/// \param os The output stream to print on.
/// \param g The automaton to output.
/// \param f The (optional) formula associated to the automaton. If given
/// it will be output as a comment.
/// \parama acceptance Force the type of acceptance mode used
/// in output.
/// \param alias Whether aliases should be used in output.
/// \param newslines Whether to use newlines in output.
SPOT_API std::ostream&
hoaf_reachable(std::ostream& os,
const const_tgba_ptr& g,
const ltl::formula* f = 0,
hoaf_acceptance acceptance = Hoaf_Acceptance_States,
hoaf_alias alias = Hoaf_Alias_None,
bool newlines = true);
SPOT_API std::ostream&
hoaf_reachable(std::ostream& os,
const const_tgba_ptr& g,
const char* opt,
const ltl::formula* f = 0);
}
#endif // SPOT_TGBAALGOS_HOAF_HH

View file

@ -260,24 +260,59 @@ namespace spot
// Similarly
// a M b = (a R (b&P(a)))
// (a M b) M c = (a R (b & Pa)) R (c & P(a M b))
// = (a R (b & Pa)) R (c & P(a))
// The rules also apply to F:
// P(F(a)) = P(a)
again:
while (const binop* b = is_binop(f))
// = (a R (b & Pa)) R (c & P(a & b))
//
// The code below therefore implement the following
// rules:
// P(a U b) = P(b)
// P(F(a)) = P(a)
// P(a M b) = P(a & b)
//
// The latter rule INCORRECTLY appears as P(a M b)=P(a)
// in section 3.5 of
// "LTL translation improvements in Spot 1.0",
// A. Duret-Lutz. IJCCBS 5(1/2):31-54, March 2014.
// and was unfortunately implemented this way until Spot
// 1.2.4. A counterexample is given by the formula
// G(Fa & ((a M b) U ((c U !d) M d)))
// that was found by Joachim Klein. Here P((c U !d) M d)
// and P(c U !d) should not both be simplified to P(!d).
for (;;)
{
binop::type op = b->op();
if (op == binop::U)
f = b->second();
else if (op == binop::M)
f = b->first();
if (const binop* b = is_binop(f))
{
binop::type op = b->op();
if (op == binop::U)
{
// P(a U b) = P(b)
f = b->second();
}
else if (op == binop::M)
{
// P(a M b) = P(a & b)
const formula* g =
multop::instance(multop::And,
b->first()->clone(),
b->second()->clone());
int num = dict->register_acceptance_variable(g, this);
a_set &= bdd_ithvar(num);
g->destroy();
return num;
}
else
{
break;
}
}
else if (const unop* u = is_unop(f, unop::F))
{
// P(F(a)) = P(a)
f = u->child();
}
else
break;
}
if (const unop* u = is_unop(f, unop::F))
{
f = u->child();
goto again;
{
break;
}
}
int num = dict->register_acceptance_variable(f, this);
a_set &= bdd_ithvar(num);
@ -1346,8 +1381,7 @@ namespace spot
}
else
{
dest->clone();
const formula* dest2 = unop::instance(op, dest);
const formula* dest2 = unop::instance(op, dest->clone());
if (dest2 == constant::false_instance())
continue;
int x = dict_.register_next_variable(dest2);
@ -1363,48 +1397,48 @@ namespace spot
case unop::NegClosure:
rat_seen_ = true;
{
const formula* c = node->child();
if (mark_all_)
{
op = unop::NegClosureMarked;
has_marked_ = true;
}
bdd f1 = translate_ratexp(c, dict_);
// trace_ltl_bdd(dict_, f1);
const formula* f = node->child();
auto p = dict_.transdfa.succ(f);
res_ = bddtrue;
auto aut = std::get<0>(p);
auto namer = std::get<1>(p);
auto st = std::get<2>(p);
bdd var_set = bdd_existcomp(bdd_support(f1), dict_.var_set);
bdd all_props = bdd_existcomp(f1, dict_.var_set);
if (!aut)
break;
res_ = !all_props &
res_ = bddfalse;
bdd missing = bddtrue;
for (auto i: aut->succ(st))
{
bdd label = i->current_condition();
state* s = i->current_state();
const formula* dest = namer->get_name(aut->state_number(s));
missing -= label;
if (!dest->accepts_eword())
{
const formula* dest2 = unop::instance(op, dest->clone());
if (dest2 == constant::false_instance())
continue;
int x = dict_.register_next_variable(dest2);
dest2->destroy();
res_ |= label & bdd_ithvar(x);
}
}
res_ |= missing &
// stick X(1) to preserve determinism.
bdd_ithvar(dict_.register_next_variable
(constant::true_instance()));
while (all_props != bddfalse)
{
bdd label = bdd_satoneset(all_props, var_set, bddtrue);
all_props -= label;
const formula* dest =
dict_.bdd_to_sere(bdd_exist(f1 & label, dict_.var_set));
// !{ Exp } is false if Exp accepts the empty word.
if (dest->accepts_eword())
{
dest->destroy();
continue;
}
const formula* dest2 = unop::instance(op, dest);
if (dest2 == constant::false_instance())
continue;
int x = dict_.register_next_variable(dest2);
dest2->destroy();
res_ |= label & bdd_ithvar(x);
}
//trace_ltl_bdd(dict_, res_);
}
break;
@ -1479,9 +1513,23 @@ namespace spot
{
res_ = recurse(node->second(), recurring_);
bdd f1 = recurse(node->first());
// r(f1 M f2) = r(f2)(r(f1) + a(f1)X(f1 M f2)) if not recurring
// r(f1 M f2) = r(f2)(r(f1) + a(f1)) if recurring
bdd a = bdd_ithvar(dict_.register_a_variable(node->first()));
// r(f1 M f2) = r(f2)(r(f1) + a(f1&f2)X(f1 M f2)) if not recurring
// r(f1 M f2) = r(f2)(r(f1) + a(f1&f2)) if recurring
//
// Note that the rule above differs from the one given
// in Figure 2 of
// "LTL translation improvements in Spot 1.0",
// A. Duret-Lutz. IJCCBS 5(1/2):31-54, March 2014.
// Both rules should be OK, but this one is a better fit
// to the promises simplifications performed in
// register_a_variable() (see comments in this function).
// We do not want a U (c M d) to generate two different
// promises. Generating c&d also makes the output similar
// to what we would get with the equivalent a U (d U (c & d)).
//
// Here we just appear to emit a(f1 M f2) and the conversion
// to a(f1&f2) is done by register_a_variable().
bdd a = bdd_ithvar(dict_.register_a_variable(node));
if (!recurring_)
a &= bdd_ithvar(dict_.register_next_variable(node));
res_ &= f1 | a;

View file

@ -389,26 +389,26 @@ in: Gq|Gr|(G(q|FGp)&G(r|FG!p))
-x -TA -DS -in | 33 | 152 | 25
-x -TA -DS -in -RT | 21 | 112 | 17
in: FG((WaitRight4 M (HasRight1 W GWaitLeft0)) M HasLeft4)
-TGTA | 35 | 543 | XXX
-TGTA -RT | 32 | 527 | XXX
-TA | 34 | 428 | 11
-TA -RT | 30 | 408 | 9
-TA -lv | 35 | 498 | 5
-TA -lv -RT | 32 | 485 | 4
-TA -sp | 34 | 490 | 4
-TA -sp -RT | 31 | 477 | 3
-TA -lv -sp | 35 | 498 | 5
-TA -lv -sp -RT | 32 | 485 | 4
-TA -DS | 44 | 504 | 21
-TA -DS -RT | 40 | 486 | 18
-TA -DS -lv | 45 | 578 | 15
-TA -DS -lv -RT | 41 | 560 | 12
-TA -DS -sp | 44 | 568 | 14
-TA -DS -sp -RT | 40 | 550 | 11
-TA -DS -lv -sp | 45 | 578 | 15
-TA -DS -lv -sp -RT | 41 | 560 | 12
-x -TA -DS -in | 45 | 558 | 11
-x -TA -DS -in -RT | 39 | 532 | 8
-TGTA | 45 | 717 | XXX
-TGTA -RT | 35 | 598 | XXX
-TA | 44 | 602 | 16
-TA -RT | 33 | 482 | 9
-TA -lv | 45 | 676 | 9
-TA -lv -RT | 35 | 566 | 4
-TA -sp | 44 | 654 | 8
-TA -sp -RT | 34 | 545 | 3
-TA -lv -sp | 45 | 676 | 9
-TA -lv -sp -RT | 35 | 566 | 4
-TA -DS | 54 | 722 | 26
-TA -DS -RT | 42 | 608 | 18
-TA -DS -lv | 55 | 800 | 19
-TA -DS -lv -RT | 44 | 702 | 13
-TA -DS -sp | 54 | 776 | 18
-TA -DS -sp -RT | 43 | 678 | 12
-TA -DS -lv -sp | 55 | 800 | 19
-TA -DS -lv -sp -RT | 44 | 702 | 13
-x -TA -DS -in | 55 | 694 | 11
-x -TA -DS -in -RT | 41 | 597 | 8
in: G(F(GWaitLeft7 U Idle4) U (WaitLeft2 M IsEating2))
-TGTA | 69 | 1539 | XXX
-TGTA -RT | 49 | 935 | XXX

View file

@ -36,6 +36,7 @@
#include "tgbaalgos/save.hh"
#include "tgbaalgos/dotty.hh"
#include "tgbaalgos/lbtt.hh"
#include "tgbaalgos/hoaf.hh"
#include "tgba/tgbasgba.hh"
#include "tgbaalgos/degen.hh"
#include "tgba/tgbaproduct.hh"
@ -385,6 +386,7 @@ checked_main(int argc, char** argv)
bool containment = false;
bool show_fc = false;
bool spin_comments = false;
const char* hoaf_opt = 0;
spot::ltl::environment& env(spot::ltl::default_environment::instance());
spot::ltl::atomic_prop_set* unobservables = 0;
spot::tgba_ptr system_aut = 0;
@ -553,6 +555,11 @@ checked_main(int argc, char** argv)
accepting_run = true;
graph_run_tgba_opt = true;
}
else if (!strncmp(argv[formula_index], "-H", 2))
{
output = 17;
hoaf_opt = argv[formula_index] + 2;
}
else if (!strcmp(argv[formula_index], "-k"))
{
output = 9;
@ -1693,7 +1700,11 @@ checked_main(int argc, char** argv)
}
break;
}
case 17:
{
hoaf_reachable(std::cout, a, hoaf_opt, f) << '\n';
break;
}
default:
SPOT_UNREACHABLE();
}

View file

@ -23,7 +23,21 @@ set -e
ltl2tgba=../ltl2tgba
../../bin/randltl -n 100 p1 p2 p3 p4 p5 p6 --tree-size 5..15 |
(
# Some formulas supplied by Joachim Klein. The first two were
# incorrectly translated by ltl_to_tgba_fm(), while the other have
# shown some bugs in other translators.
cat <<EOF
G(Fa & ((a M b) U ((c U !d) M d)))
XF(p2 R (!Fp1 W p1))
X p0 || ((X p0) V <>p0)
p0 xor (p0 W X!p0)
p0 & (!p0 W Xp0)
EOF
# Random formulas
../../bin/randltl -n 100 p1 p2 p3 p4 p5 p6 --tree-size 5..15
) |
../../bin/ltlcross --products=2 \
"$ltl2tgba -t -f %f > %T" \
"$ltl2tgba -t -f -y %f > %T" \
@ -44,4 +58,3 @@ ltl2tgba=../ltl2tgba
"$ltl2tgba -t -taa -r4 %f > %T" \
"$ltl2tgba -t -taa -r4 -c %f > %T" \
"$ltl2tgba -t -taa -r4 -R3 -RDS %f > %T"

View file

@ -1,6 +1,6 @@
#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2012, 2013 Laboratoire de Recherche et Développement
# Copyright (C) 2012, 2013, 2014 Laboratoire de Recherche et Développement
# de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
@ -23,8 +23,8 @@ set -e
ltl2tgba=../../bin/ltl2tgba
../../bin/randltl -P -n 100 p1 p2 p3 p4 p5 p6 --tree-size 5..15 |
../../bin/ltlcross --products=3 \
../../bin/randltl -P -n 100 p1 p2 p3 p4 p5 p6 --tree-size 5..15 --seed=314 |
../../bin/ltlcross --products=3 --timeout=60 \
"$ltl2tgba --lbtt --any --low %f > %T" \
"$ltl2tgba --lbtt --any --medium %f > %T" \
"$ltl2tgba --lbtt --any --high %f > %T" \

View file

@ -1,6 +1,6 @@
#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2012, 2013 Laboratoire de Recherche et
# Copyright (C) 2012, 2013, 2014 Laboratoire de Recherche et
# Développement de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
@ -55,13 +55,18 @@ test `grep '"exit code",1' out.csv | wc -l` -eq 0
check_csv out.csv
# Likewise for timeouts
echo foo >bug
run 0 ../../bin/ltlcross 'sleep 5; false %f >%N' \
--timeout 2 -f a --csv=out.csv 2>stderr
--timeout 2 -f a --csv=out.csv \
--save-bogus=bug 2>stderr
grep '"exit_status"' out.csv
grep '"exit_code"' out.csv
test `grep 'warning:.*timeout' stderr | wc -l` -eq 2
test `grep '"timeout",-1' out.csv | wc -l` -eq 2
check_csv out.csv
# 'bug' should exist but be empty
test -f bug
test -s bug && exit 1
run 0 ../../bin/ltlcross 'sleep 5; false %f >%N' \
--timeout 2 --omit-missing -f a --csv=out.csv 2>stderr
@ -115,12 +120,13 @@ test $q -eq `expr $p + 12`
# Check with Rabin/Streett output
run 1 ../../bin/ltlcross "$ltl2tgba -s %f >%N" 'false %f >%D' \
-f a --csv=out.csv 2>stderr
-f 'X a' --csv=out.csv --save-bogus=bug.txt 2>stderr
q=`sed 's/[^,]//g;q' out.csv | wc -c`
grep '"exit_status"' out.csv
grep '"exit_code"' out.csv
test `grep 'error:.*returned exit code 1' stderr | wc -l` -eq 2
test `grep '"exit code",1' out.csv | wc -l` -eq 2
check_csv out.csv
grep 'X a' bug.txt
test $q -eq `expr $p + 6`

View file

@ -1,7 +1,7 @@
#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Laboratoire de Recherche et
# Développement de l'Epita (LRDE).
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Laboratoire de Recherche
# et Développement de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
#
@ -172,6 +172,40 @@ EOF
grep input: stderr >> stderrfilt
diff stderrfilt expected
# This output from MoDeLLa was not property parsed by Spot because of
# the missing parentheses around p0. Report from František Blahoudek.
cat >input <<EOF
never{
T0_init:
if
:: true -> goto T1
:: p0 -> goto T2
fi;
T1:
if
:: true -> goto T1
:: p0 -> goto accept_T3
fi;
T2:
if
:: p0 -> goto accept_T3
fi;
accept_T3:
if
:: p0 -> goto T2
fi;
}
EOF
cat >expected<<EOF
transitions: 6
states: 4
EOF
run 0 ../ltl2tgba -ks -XN input > output
diff output expected
cat >formulae<<EOF
a
FG a

View file

@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (C) 2011, 2012 Laboratoire de Recherche et Développement
# Copyright (C) 2011, 2012, 2014 Laboratoire de Recherche et Développement
# de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
@ -22,23 +22,10 @@
set -e
check_psl()
{
# Do not use "run", this is too slow.
# Make cross products with FM
../ltl2tgba -f -R3 -b "$1" > out.tgba
../ltl2tgba -f -R3 -Pout.tgba -E "!($1)"
# Also try with -x turned on.
../ltl2tgba -f -x -R3 -b "$1" > out.tgba
../ltl2tgba -f -x -R3 -Pout.tgba -E "!($1)"
}
# Generate 50 random unique PSL formula that do not simplify to LTL
# formulae, and that have a size of at lease 12.
../../bin/randltl -n -1 --tree-size 30 --seed 0 --psl a b c |
../../bin/ltlfilt -r --size-min 12 --unique |
../../bin/ltlfilt -v --ltl | head -n 50 |
while read formula; do
check_psl "$formula"
done
../../bin/ltlcross '../ltl2tgba -R3 -t %f >%T' '../ltl2tgba -x -R3 -t %f >%T' \
-F - -f '{{(p1)}[*]:{(p3) && {{!(p1)} xor {!(p3)}}}}'