kill the ltl namespace

* NEWS: Mention it.
* bench/stutter/stutter_invariance_formulas.cc,
bench/stutter/stutter_invariance_randomgraph.cc, doc/mainpage.dox,
doc/org/tut01.org, doc/org/tut02.org, doc/org/tut10.org, doc/tl/tl.tex,
iface/ltsmin/ltsmin.cc, iface/ltsmin/ltsmin.hh,
iface/ltsmin/modelcheck.cc, src/bin/autfilt.cc,
src/bin/common_aoutput.cc, src/bin/common_aoutput.hh,
src/bin/common_finput.cc, src/bin/common_finput.hh,
src/bin/common_output.cc, src/bin/common_output.hh, src/bin/common_r.hh,
src/bin/common_trans.cc, src/bin/common_trans.hh, src/bin/dstar2tgba.cc,
src/bin/genltl.cc, src/bin/ltl2tgba.cc, src/bin/ltl2tgta.cc,
src/bin/ltlcross.cc, src/bin/ltldo.cc, src/bin/ltlfilt.cc,
src/bin/ltlgrind.cc, src/bin/randaut.cc, src/bin/randltl.cc,
src/kripke/kripkeexplicit.cc, src/kripke/kripkeexplicit.hh,
src/kripkeparse/kripkeparse.yy, src/kripkeparse/public.hh,
src/ltlparse/fmterror.cc, src/ltlparse/ltlparse.yy,
src/ltlparse/ltlscan.ll, src/ltlparse/parsedecl.hh,
src/ltlparse/public.hh, src/parseaut/parseaut.yy,
src/parseaut/public.hh, src/tests/checkpsl.cc, src/tests/checkta.cc,
src/tests/complementation.cc, src/tests/consterm.cc,
src/tests/emptchk.cc, src/tests/equalsf.cc, src/tests/ikwiad.cc,
src/tests/kind.cc, src/tests/length.cc, src/tests/ltlprod.cc,
src/tests/ltlrel.cc, src/tests/parse.test,
src/tests/parse_print_test.cc, src/tests/randtgba.cc,
src/tests/readltl.cc, src/tests/reduc.cc, src/tests/syntimpl.cc,
src/tests/taatgba.cc, src/tests/tostring.cc, src/tests/tostring.test,
src/tl/apcollect.cc, src/tl/apcollect.hh, src/tl/contain.cc,
src/tl/contain.hh, src/tl/declenv.cc, src/tl/declenv.hh,
src/tl/defaultenv.cc, src/tl/defaultenv.hh, src/tl/dot.cc,
src/tl/dot.hh, src/tl/environment.hh, src/tl/exclusive.cc,
src/tl/exclusive.hh, src/tl/formula.cc, src/tl/formula.hh,
src/tl/length.cc, src/tl/length.hh, src/tl/mark.cc, src/tl/mark.hh,
src/tl/mutation.cc, src/tl/mutation.hh, src/tl/nenoform.cc,
src/tl/nenoform.hh, src/tl/print.cc, src/tl/print.hh,
src/tl/randomltl.cc, src/tl/randomltl.hh, src/tl/relabel.cc,
src/tl/relabel.hh, src/tl/remove_x.cc, src/tl/remove_x.hh,
src/tl/simpfg.cc, src/tl/simpfg.hh, src/tl/simplify.cc,
src/tl/simplify.hh, src/tl/snf.cc, src/tl/snf.hh, src/tl/unabbrev.cc,
src/tl/unabbrev.hh, src/twa/bdddict.cc, src/twa/bdddict.hh,
src/twa/bddprint.cc, src/twa/formula2bdd.cc, src/twa/formula2bdd.hh,
src/twa/taatgba.cc, src/twa/taatgba.hh, src/twa/twa.hh,
src/twa/twagraph.cc, src/twa/twagraph.hh, src/twaalgos/compsusp.cc,
src/twaalgos/compsusp.hh, src/twaalgos/ltl2taa.cc,
src/twaalgos/ltl2taa.hh, src/twaalgos/ltl2tgba_fm.cc,
src/twaalgos/ltl2tgba_fm.hh, src/twaalgos/minimize.cc,
src/twaalgos/minimize.hh, src/twaalgos/neverclaim.cc,
src/twaalgos/postproc.cc, src/twaalgos/postproc.hh,
src/twaalgos/powerset.cc, src/twaalgos/powerset.hh,
src/twaalgos/randomgraph.cc, src/twaalgos/randomgraph.hh,
src/twaalgos/relabel.cc, src/twaalgos/relabel.hh,
src/twaalgos/remprop.cc, src/twaalgos/remprop.hh, src/twaalgos/stats.cc,
src/twaalgos/stats.hh, src/twaalgos/stutter.cc, src/twaalgos/stutter.hh,
src/twaalgos/translate.cc, src/twaalgos/translate.hh,
wrap/python/spot_impl.i: Remove the ltl namespace.
This commit is contained in:
Alexandre Duret-Lutz 2015-09-28 16:20:53 +02:00
parent 6ded5e75c4
commit cb39210166
137 changed files with 10771 additions and 10919 deletions

17
NEWS
View file

@ -28,9 +28,9 @@ New in spot 1.99.3a (not yet released)
* The class hierarchy for temporal formulas has been entirely * The class hierarchy for temporal formulas has been entirely
rewritten. This change is actually quite massive (~13200 lines rewritten. This change is actually quite massive (~13200 lines
removed, ~8200 lines added), and brings some nice benefits: removed, ~8200 lines added), and brings some nice benefits:
- LTL/PSL formulas are now represented by lightweight ltl::formula - LTL/PSL formulas are now represented by lightweight formula
objects (instead of ltl::formula* pointers) that perform objects (instead of pointers to children of an abstract formula
reference counting automatically. class) that perform reference counting automatically.
- There is no hierachy anymore: all operators are represented by a - There is no hierachy anymore: all operators are represented by a
single type of node in the syntax tree, and an enumerator is single type of node in the syntax tree, and an enumerator is
used to distinguish between operators. used to distinguish between operators.
@ -41,10 +41,13 @@ New in spot 1.99.3a (not yet released)
more friendly, and several algorithms that spanned a few pages more friendly, and several algorithms that spanned a few pages
have been reduced to a few lines. have been reduced to a few lines.
* The source directories ltlast/, ltlenv/, and ltlvisit/, have been * Directories ltlast/, ltlenv/, and ltlvisit/, have been merged into
merged into a single tl/ directory (for temporal logic). This is a single tl/ directory (for temporal logic). This is motivated by
motivated by the fact that these formulas are not restricted to the fact that these formulas are not restricted to LTL, and by the
LTL, and by the fact that we no longuer use the "visitor" pattern. fact that we no longuer use the "visitor" pattern.
* For similar reasons, the spot::ltl namespace has been merged
with the spot namespace.
New in spot 1.99.3 (2015-08-26) New in spot 1.99.3 (2015-08-26)

View file

@ -62,12 +62,12 @@ namespace
} }
int int
process_formula(spot::ltl::formula f, const char*, int) process_formula(spot::formula f, const char*, int)
{ {
spot::twa_graph_ptr a = trans.run(f); spot::twa_graph_ptr a = trans.run(f);
spot::twa_graph_ptr na = trans.run(spot::ltl::formula::Not(f)); spot::twa_graph_ptr na = trans.run(spot::formula::Not(f));
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f); spot::atomic_prop_set* ap = spot::atomic_prop_collect(f);
bdd apdict = spot::ltl::atomic_prop_collect_as_bdd(f, a); bdd apdict = spot::atomic_prop_collect_as_bdd(f, a);
std::cout << formula << ',' << ap->size() << ','; std::cout << formula << ',' << ap->size() << ',';
stats.print(a); stats.print(a);

View file

@ -55,7 +55,7 @@ main(int argc, char** argv)
constexpr unsigned n = 10; constexpr unsigned n = 10;
// random ap set // random ap set
auto ap = spot::ltl::create_atomic_prop_set(props_n); auto ap = spot::create_atomic_prop_set(props_n);
// ap set as bdd // ap set as bdd
bdd apdict = bddtrue; bdd apdict = bddtrue;
for (auto& i: ap) for (auto& i: ap)

View file

@ -19,12 +19,12 @@
/// ///
/// \section pointers Handy starting points /// \section pointers Handy starting points
/// ///
/// \li spot::ltl::formula Base class for an LTL or PSL formula. /// \li spot::formula Base class for an LTL or PSL formula.
/// \li spot::ltl::parse_infix_psl Parsing a text string into a /// \li spot::parse_infix_psl Parsing a text string into a
/// spot::ltl::formula. /// spot::formula.
/// \li spot::twa Base class for Transition-based /// \li spot::twa Base class for Transition-based
/// ω-Automata. /// ω-Automata.
/// \li spot::translator Convert a spot::ltl::formula into a /// \li spot::translator Convert a spot::formula into a
/// spot::tgba. /// spot::tgba.
/// \li spot::kripke Base class for Kripke structures. /// \li spot::kripke Base class for Kripke structures.
/// \li spot::twa_product On-the-fly product of two spot::twa. /// \li spot::twa_product On-the-fly product of two spot::twa.

View file

@ -71,8 +71,8 @@ exceptions.
int main() int main()
{ {
print_latex_psl(std::cout, spot::ltl::parse_formula("[]<>p0 || <>[]p1")) << '\n'; print_latex_psl(std::cout, spot::parse_formula("[]<>p0 || <>[]p1")) << '\n';
spot::ltl::formula f = spot::ltl::parse_formula("& & G p0 p1 p2"); spot::formula f = spot::parse_formula("& & G p0 p1 p2");
print_lbt_ltl(std::cout, f) << '\n'; print_lbt_ltl(std::cout, f) << '\n';
print_spin_ltl(std::cout, f, true) << '\n'; print_spin_ltl(std::cout, f, true) << '\n';
return 0; return 0;
@ -110,9 +110,9 @@ Here is how to call the infix parser explicitly,:
int main() int main()
{ {
std::string input = "[]<>p0 || <>[]p1"; std::string input = "[]<>p0 || <>[]p1";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel); spot::formula f = spot::parse_infix_psl(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
return 1; return 1;
print_latex_psl(std::cout, f) << '\n'; print_latex_psl(std::cout, f) << '\n';
return 0; return 0;
@ -152,11 +152,11 @@ with the "fixed" formula if you wish. Here is an example:
int main() int main()
{ {
std::string input = "(a U b))"; std::string input = "(a U b))";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel); spot::formula f = spot::parse_infix_psl(input, pel);
// Use std::cout instead of std::cerr because we can only // Use std::cout instead of std::cerr because we can only
// show the output of std::cout in this documentation. // show the output of std::cout in this documentation.
(void) spot::ltl::format_parse_errors(std::cout, input, pel); (void) spot::format_parse_errors(std::cout, input, pel);
if (f == nullptr) if (f == nullptr)
return 1; return 1;
std::cout << "Parsed formula: "; std::cout << "Parsed formula: ";
@ -194,9 +194,9 @@ of =parse_infix_psl()=.
int main() int main()
{ {
std::string input = "& & G p0 p1 p2"; std::string input = "& & G p0 p1 p2";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_prefix_ltl(input, pel); spot::formula f = spot::parse_prefix_ltl(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
return 1; return 1;
print_lbt_ltl(std::cout, f) << '\n'; print_lbt_ltl(std::cout, f) << '\n';
print_spin_ltl(std::cout, f, true) << '\n'; print_spin_ltl(std::cout, f, true) << '\n';
@ -236,9 +236,9 @@ For instance, let's see what happens if a PSL formulas is passed to
int main() int main()
{ {
std::string input = "{a*;b}<>->(a U (b & GF c))"; std::string input = "{a*;b}<>->(a U (b & GF c))";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel); spot::formula f = spot::parse_infix_psl(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
return 1; return 1;
print_spin_ltl(std::cout, f) << '\n'; print_spin_ltl(std::cout, f) << '\n';
return 0; return 0;
@ -266,9 +266,9 @@ The first is to simply diagnose non-LTL formulas.
int main() int main()
{ {
std::string input = "{a*;b}<>->(a U (b & GF c))"; std::string input = "{a*;b}<>->(a U (b & GF c))";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel); spot::formula f = spot::parse_infix_psl(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
return 1; return 1;
if (!f.is_ltl_formula()) if (!f.is_ltl_formula())
{ {
@ -296,13 +296,13 @@ prepared to reject the formula any way. In our example, we are lucky
int main() int main()
{ {
std::string input = "{a*;b}<>->(a U (b & GF c))"; std::string input = "{a*;b}<>->(a U (b & GF c))";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel); spot::formula f = spot::parse_infix_psl(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
return 1; return 1;
if (!f.is_ltl_formula()) if (!f.is_ltl_formula())
{ {
spot::ltl::ltl_simplifier simp; spot::ltl_simplifier simp;
f = simp.simplify(f); f = simp.simplify(f);
} }
if (!f.is_ltl_formula()) if (!f.is_ltl_formula())

View file

@ -74,7 +74,7 @@ print(g.to_str('spin', True))
* C++ * C++
The =spot::ltl::relabeling_map= is just a =std::map= with a custom The =spot::relabeling_map= is just a =std::map= with a custom
destructor. destructor.
#+BEGIN_SRC C++ :results verbatim :exports both #+BEGIN_SRC C++ :results verbatim :exports both
@ -87,12 +87,12 @@ destructor.
int main() int main()
{ {
std::string input = "\"Proc@Here\" U (\"var > 10\" | \"var < 4\")"; std::string input = "\"Proc@Here\" U (\"var > 10\" | \"var < 4\")";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel); spot::formula f = spot::parse_infix_psl(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
return 1; return 1;
spot::ltl::relabeling_map m; spot::relabeling_map m;
f = spot::ltl::relabel(f, spot::ltl::Pnn, &m); f = spot::relabel(f, spot::Pnn, &m);
for (auto& i: m) for (auto& i: m)
{ {
std::cout << "#define "; std::cout << "#define ";
@ -115,8 +115,8 @@ destructor.
** Two ways to name atomic propositions ** Two ways to name atomic propositions
Instead of =--relabel=pnn= (or =spot.Pnn=, or =spot::ltl::Pnn=), you can Instead of =--relabel=pnn= (or =spot.Pnn=, or =spot::Pnn=), you can
actually use =--relabel=abc= (or =spot.Abc=, or =spot::ltl::Abc=) to have actually use =--relabel=abc= (or =spot.Abc=, or =spot::Abc=) to have
the atomic propositions named =a=, =b=, =c=, etc. the atomic propositions named =a=, =b=, =c=, etc.
** Relabeling Boolean sub-expressions ** Relabeling Boolean sub-expressions

View file

@ -137,9 +137,9 @@ never claim is done via the =print_never_claim= function.
int main() int main()
{ {
std::string input = "[]<>p0 || <>[]p1"; std::string input = "[]<>p0 || <>[]p1";
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel); spot::formula f = spot::parse_infix_psl(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
return 1; return 1;
spot::translator trans; spot::translator trans;
trans.set_type(spot::postprocessor::BA); trans.set_type(spot::postprocessor::BA);

View file

@ -1001,7 +1001,7 @@ both right-associative, other have only $\IMPLIES$ as right-associative.
When Spot builds a formula (represented by an AST with shared When Spot builds a formula (represented by an AST with shared
subtrees) it computes a set of properties for each node. These subtrees) it computes a set of properties for each node. These
properties can be queried from any \texttt{spot::ltl::formula} properties can be queried from any \texttt{spot::formula}
instance using the following methods: instance using the following methods:
\noindent \noindent

View file

@ -323,10 +323,10 @@ namespace spot
int int
convert_aps(const ltl::atomic_prop_set* aps, convert_aps(const atomic_prop_set* aps,
const spins_interface* d, const spins_interface* d,
bdd_dict_ptr dict, bdd_dict_ptr dict,
ltl::formula dead, formula dead,
prop_set& out) prop_set& out)
{ {
int errors = 0; int errors = 0;
@ -353,7 +353,7 @@ namespace spot
enum_map[i].emplace(d->get_type_value_name(i, j), j); enum_map[i].emplace(d->get_type_value_name(i, j), j);
} }
for (ltl::atomic_prop_set::const_iterator ap = aps->begin(); for (atomic_prop_set::const_iterator ap = aps->begin();
ap != aps->end(); ++ap) ap != aps->end(); ++ap)
{ {
if (*ap == dead) if (*ap == dead)
@ -602,7 +602,7 @@ namespace spot
public: public:
spins_kripke(const spins_interface* d, const bdd_dict_ptr& dict, spins_kripke(const spins_interface* d, const bdd_dict_ptr& dict,
const spot::prop_set* ps, ltl::formula dead, const spot::prop_set* ps, formula dead,
int compress) int compress)
: kripke(dict), : kripke(dict),
d_(d), d_(d),
@ -1016,8 +1016,8 @@ namespace spot
kripke_ptr kripke_ptr
load_ltsmin(const std::string& file_arg, const bdd_dict_ptr& dict, load_ltsmin(const std::string& file_arg, const bdd_dict_ptr& dict,
const ltl::atomic_prop_set* to_observe, const atomic_prop_set* to_observe,
const ltl::formula dead, int compress, bool verbose) const formula dead, int compress, bool verbose)
{ {
std::string file; std::string file;
if (file_arg.find_first_of("/\\") != std::string::npos) if (file_arg.find_first_of("/\\") != std::string::npos)

View file

@ -57,7 +57,7 @@ namespace spot
// \a verbose whether to output verbose messages // \a verbose whether to output verbose messages
SPOT_API kripke_ptr SPOT_API kripke_ptr
load_ltsmin(const std::string& file, const bdd_dict_ptr& dict, load_ltsmin(const std::string& file, const bdd_dict_ptr& dict,
const ltl::atomic_prop_set* to_observe, const atomic_prop_set* to_observe,
ltl::formula dead = ltl::formula::tt(), formula dead = formula::tt(),
int compress = 0, bool verbose = true); int compress = 0, bool verbose = true);
} }

View file

@ -150,11 +150,11 @@ checked_main(int argc, char **argv)
if (argc != 3) if (argc != 3)
syntax(argv[0]); syntax(argv[0]);
spot::ltl::default_environment& env = spot::default_environment& env =
spot::ltl::default_environment::instance(); spot::default_environment::instance();
spot::ltl::atomic_prop_set ap; spot::atomic_prop_set ap;
auto dict = spot::make_bdd_dict(); auto dict = spot::make_bdd_dict();
spot::const_kripke_ptr model = nullptr; spot::const_kripke_ptr model = nullptr;
spot::const_twa_ptr prop = nullptr; spot::const_twa_ptr prop = nullptr;
@ -162,16 +162,16 @@ checked_main(int argc, char **argv)
spot::emptiness_check_instantiator_ptr echeck_inst = nullptr; spot::emptiness_check_instantiator_ptr echeck_inst = nullptr;
int exit_code = 0; int exit_code = 0;
spot::postprocessor post; spot::postprocessor post;
spot::ltl::formula deadf = nullptr; spot::formula deadf = nullptr;
spot::ltl::formula f = nullptr; spot::formula f = nullptr;
if (!dead || !strcasecmp(dead, "true")) if (!dead || !strcasecmp(dead, "true"))
{ {
deadf = spot::ltl::formula::tt(); deadf = spot::formula::tt();
} }
else if (!strcasecmp(dead, "false")) else if (!strcasecmp(dead, "false"))
{ {
deadf = spot::ltl::formula::ff(); deadf = spot::formula::ff();
} }
else else
{ {
@ -193,9 +193,9 @@ checked_main(int argc, char **argv)
tm.start("parsing formula"); tm.start("parsing formula");
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
f = spot::ltl::parse_infix_psl(argv[2], pel, env, false); f = spot::parse_infix_psl(argv[2], pel, env, false);
exit_code = spot::ltl::format_parse_errors(std::cerr, argv[2], pel); exit_code = spot::format_parse_errors(std::cerr, argv[2], pel);
} }
tm.stop("parsing formula"); tm.stop("parsing formula");
@ -366,6 +366,6 @@ main(int argc, char **argv)
auto exit_code = checked_main(argc, argv); auto exit_code = checked_main(argc, argv);
// Additional checks to debug reference counts in formulas. // Additional checks to debug reference counts in formulas.
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
exit(exit_code); exit(exit_code);
} }

View file

@ -505,7 +505,7 @@ namespace
} }
int int
process_formula(spot::ltl::formula, const char*, int) process_formula(spot::formula, const char*, int)
{ {
SPOT_UNREACHABLE(); SPOT_UNREACHABLE();
} }

View file

@ -287,7 +287,7 @@ automaton_printer::automaton_printer(stat_style input)
void void
automaton_printer::print(const spot::twa_graph_ptr& aut, automaton_printer::print(const spot::twa_graph_ptr& aut,
spot::ltl::formula f, spot::formula f,
// Input location for errors and statistics. // Input location for errors and statistics.
const char* filename, const char* filename,
int loc, int loc,

View file

@ -107,7 +107,7 @@ public:
std::ostream& std::ostream&
print(const spot::const_parsed_aut_ptr& haut, print(const spot::const_parsed_aut_ptr& haut,
const spot::const_twa_graph_ptr& aut, const spot::const_twa_graph_ptr& aut,
spot::ltl::formula f, spot::formula f,
const char* filename, int loc, double run_time) const char* filename, int loc, double run_time)
{ {
filename_ = filename ? filename : ""; filename_ = filename ? filename : "";
@ -225,7 +225,7 @@ public:
void void
print(const spot::twa_graph_ptr& aut, print(const spot::twa_graph_ptr& aut,
spot::ltl::formula f = nullptr, spot::formula f = nullptr,
// Input location for errors and statistics. // Input location for errors and statistics.
const char* filename = nullptr, const char* filename = nullptr,
int loc = -1, int loc = -1,

View file

@ -77,14 +77,14 @@ parse_opt_finput(int key, char* arg, struct argp_state*)
return 0; return 0;
} }
spot::ltl::formula spot::formula
parse_formula(const std::string& s, spot::ltl::parse_error_list& pel) parse_formula(const std::string& s, spot::parse_error_list& pel)
{ {
if (lbt_input) if (lbt_input)
return spot::ltl::parse_prefix_ltl(s, pel); return spot::parse_prefix_ltl(s, pel);
else else
return spot::ltl::parse_infix_psl return spot::parse_infix_psl
(s, pel, spot::ltl::default_environment::instance(), false, lenient); (s, pel, spot::default_environment::instance(), false, lenient);
} }
job_processor::job_processor() job_processor::job_processor()
@ -109,14 +109,14 @@ job_processor::process_string(const std::string& input,
const char* filename, const char* filename,
int linenum) int linenum)
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
auto f = parse_formula(input, pel); auto f = parse_formula(input, pel);
if (!f || !pel.empty()) if (!f || !pel.empty())
{ {
if (filename) if (filename)
error_at_line(0, 0, filename, linenum, "parse error:"); error_at_line(0, 0, filename, linenum, "parse error:");
spot::ltl::format_parse_errors(std::cerr, input, pel); spot::format_parse_errors(std::cerr, input, pel);
return 1; return 1;
} }
return process_formula(f, filename, linenum); return process_formula(f, filename, linenum);

View file

@ -44,8 +44,8 @@ extern const struct argp finput_argp;
int parse_opt_finput(int key, char* arg, struct argp_state* state); int parse_opt_finput(int key, char* arg, struct argp_state* state);
spot::ltl::formula spot::formula
parse_formula(const std::string& s, spot::ltl::parse_error_list& error_list); parse_formula(const std::string& s, spot::parse_error_list& error_list);
class job_processor class job_processor
@ -58,7 +58,7 @@ public:
virtual ~job_processor(); virtual ~job_processor();
virtual int virtual int
process_formula(spot::ltl::formula f, process_formula(spot::formula f,
const char* filename = nullptr, int linenum = 0) = 0; const char* filename = nullptr, int linenum = 0) = 0;
virtual int virtual int

View file

@ -70,10 +70,10 @@ const struct argp output_argp = { options, parse_opt_output,
static static
void void
report_not_ltl(spot::ltl::formula f, report_not_ltl(spot::formula f,
const char* filename, int linenum, const char* syn) const char* filename, int linenum, const char* syn)
{ {
std::string s = spot::ltl::str_psl(f); std::string s = spot::str_psl(f);
static const char msg[] = static const char msg[] =
"formula '%s' cannot be written %s's syntax because it is not LTL"; "formula '%s' cannot be written %s's syntax because it is not LTL";
if (filename) if (filename)
@ -84,36 +84,36 @@ report_not_ltl(spot::ltl::formula f,
std::ostream& std::ostream&
stream_formula(std::ostream& out, stream_formula(std::ostream& out,
spot::ltl::formula f, const char* filename, int linenum) spot::formula f, const char* filename, int linenum)
{ {
switch (output_format) switch (output_format)
{ {
case lbt_output: case lbt_output:
if (f.is_ltl_formula()) if (f.is_ltl_formula())
spot::ltl::print_lbt_ltl(out, f); spot::print_lbt_ltl(out, f);
else else
report_not_ltl(f, filename, linenum, "LBT"); report_not_ltl(f, filename, linenum, "LBT");
break; break;
case spot_output: case spot_output:
spot::ltl::print_psl(out, f, full_parenth); spot::print_psl(out, f, full_parenth);
break; break;
case spin_output: case spin_output:
if (f.is_ltl_formula()) if (f.is_ltl_formula())
spot::ltl::print_spin_ltl(out, f, full_parenth); spot::print_spin_ltl(out, f, full_parenth);
else else
report_not_ltl(f, filename, linenum, "Spin"); report_not_ltl(f, filename, linenum, "Spin");
break; break;
case wring_output: case wring_output:
if (f.is_ltl_formula()) if (f.is_ltl_formula())
spot::ltl::print_wring_ltl(out, f); spot::print_wring_ltl(out, f);
else else
report_not_ltl(f, filename, linenum, "Wring"); report_not_ltl(f, filename, linenum, "Wring");
break; break;
case utf8_output: case utf8_output:
spot::ltl::print_utf8_psl(out, f, full_parenth); spot::print_utf8_psl(out, f, full_parenth);
break; break;
case latex_output: case latex_output:
spot::ltl::print_latex_psl(out, f, full_parenth); spot::print_latex_psl(out, f, full_parenth);
break; break;
case count_output: case count_output:
case quiet_output: case quiet_output:
@ -124,7 +124,7 @@ stream_formula(std::ostream& out,
static void static void
stream_escapable_formula(std::ostream& os, stream_escapable_formula(std::ostream& os,
spot::ltl::formula f, spot::formula f,
const char* filename, int linenum) const char* filename, int linenum)
{ {
if (escape_csv) if (escape_csv)
@ -146,7 +146,7 @@ namespace
{ {
struct formula_with_location struct formula_with_location
{ {
spot::ltl::formula f; spot::formula f;
const char* filename; const char* filename;
int line; int line;
const char* prefix; const char* prefix;
@ -260,7 +260,7 @@ parse_opt_output(int key, char* arg, struct argp_state*)
static void static void
output_formula(std::ostream& out, output_formula(std::ostream& out,
spot::ltl::formula f, spot::formula f,
const char* filename = nullptr, int linenum = 0, const char* filename = nullptr, int linenum = 0,
const char* prefix = nullptr, const char* suffix = nullptr) const char* prefix = nullptr, const char* suffix = nullptr)
{ {
@ -286,7 +286,7 @@ void
} }
void void
output_formula_checked(spot::ltl::formula f, output_formula_checked(spot::formula f,
const char* filename, int linenum, const char* filename, int linenum,
const char* prefix, const char* suffix) const char* prefix, const char* suffix)
{ {

View file

@ -43,20 +43,20 @@ int parse_opt_output(int key, char* arg, struct argp_state* state);
// Low-level output // Low-level output
std::ostream& std::ostream&
stream_formula(std::ostream& out, stream_formula(std::ostream& out,
spot::ltl::formula f, const char* filename, int linenum); spot::formula f, const char* filename, int linenum);
void output_formula_checked(spot::ltl::formula f, void output_formula_checked(spot::formula f,
const char* filename = nullptr, int linenum = 0, const char* filename = nullptr, int linenum = 0,
const char* prefix = nullptr, const char* prefix = nullptr,
const char* suffix = nullptr); const char* suffix = nullptr);
class printable_formula: class printable_formula:
public spot::printable_value<spot::ltl::formula> public spot::printable_value<spot::formula>
{ {
public: public:
printable_formula& printable_formula&
operator=(spot::ltl::formula new_val) operator=(spot::formula new_val)
{ {
val_ = new_val; val_ = new_val;
return *this; return *this;
@ -79,7 +79,7 @@ public:
std::ostream& std::ostream&
print(const spot::const_twa_graph_ptr& aut, print(const spot::const_twa_graph_ptr& aut,
spot::ltl::formula f = nullptr, spot::formula f = nullptr,
double run_time = -1.) double run_time = -1.)
{ {
formula_ = f; formula_ = f;

View file

@ -44,4 +44,4 @@
extern int simplification_level; extern int simplification_level;
void parse_r(const char* arg); void parse_r(const char* arg);
spot::ltl::ltl_simplifier_options simplifier_options(); spot::ltl_simplifier_options simplifier_options();

View file

@ -290,16 +290,16 @@ translator_runner::formula() const
} }
void void
translator_runner::round_formula(spot::ltl::formula f, unsigned serial) translator_runner::round_formula(spot::formula f, unsigned serial)
{ {
if (has('f') || has('F')) if (has('f') || has('F'))
string_ltl_spot = spot::ltl::str_psl(f, true); string_ltl_spot = spot::str_psl(f, true);
if (has('s') || has('S')) if (has('s') || has('S'))
string_ltl_spin = spot::ltl::str_spin_ltl(f, true); string_ltl_spin = spot::str_spin_ltl(f, true);
if (has('l') || has('L')) if (has('l') || has('L'))
string_ltl_lbt = spot::ltl::str_lbt_ltl(f); string_ltl_lbt = spot::str_lbt_ltl(f);
if (has('w') || has('W')) if (has('w') || has('W'))
string_ltl_wring = spot::ltl::str_wring_ltl(f); string_ltl_wring = spot::str_wring_ltl(f);
if (has('F')) if (has('F'))
string_to_tmp(string_ltl_spot, serial, filename_ltl_spot); string_to_tmp(string_ltl_spot, serial, filename_ltl_spot);
if (has('S')) if (has('S'))

View file

@ -94,7 +94,7 @@ public:
bool no_output_allowed = false); bool no_output_allowed = false);
void string_to_tmp(std::string& str, unsigned n, std::string& tmpname); void string_to_tmp(std::string& str, unsigned n, std::string& tmpname);
const std::string& formula() const; const std::string& formula() const;
void round_formula(spot::ltl::formula f, unsigned serial); void round_formula(spot::formula f, unsigned serial);
}; };

View file

@ -139,7 +139,7 @@ namespace
} }
int int
process_formula(spot::ltl::formula, const char*, int) process_formula(spot::formula, const char*, int)
{ {
SPOT_UNREACHABLE(); SPOT_UNREACHABLE();
} }

View file

@ -90,7 +90,6 @@
#include "tl/relabel.hh" #include "tl/relabel.hh"
using namespace spot; using namespace spot;
using namespace spot::ltl;
const char argp_program_doc[] ="\ const char argp_program_doc[] ="\
Generate temporal logic formulas from predefined scalable patterns."; Generate temporal logic formulas from predefined scalable patterns.";

View file

@ -139,16 +139,16 @@ namespace
} }
int int
process_formula(spot::ltl::formula f, process_formula(spot::formula f,
const char* filename = nullptr, int linenum = 0) const char* filename = nullptr, int linenum = 0)
{ {
// This should not happen, because the parser we use can only // This should not happen, because the parser we use can only
// read PSL/LTL formula, but since our ltl::formula type can // read PSL/LTL formula, but since our formula type can
// represent more than PSL formula, let's make this // represent more than PSL formula, let's make this
// future-proof. // future-proof.
if (!f.is_psl_formula()) if (!f.is_psl_formula())
{ {
std::string s = spot::ltl::str_psl(f); std::string s = spot::str_psl(f);
error_at_line(2, 0, filename, linenum, error_at_line(2, 0, filename, linenum,
"formula '%s' is not an LTL or PSL formula", "formula '%s' is not an LTL or PSL formula",
s.c_str()); s.c_str());

View file

@ -170,18 +170,18 @@ namespace
} }
int int
process_formula(spot::ltl::formula f, process_formula(spot::formula f,
const char* filename = nullptr, int linenum = 0) const char* filename = nullptr, int linenum = 0)
{ {
auto aut = trans.run(&f); auto aut = trans.run(&f);
// This should not happen, because the parser we use can only // This should not happen, because the parser we use can only
// read PSL/LTL formula, but since our ltl::formula type can // read PSL/LTL formula, but since our formula type can
// represent more than PSL formula, let's make this // represent more than PSL formula, let's make this
// future-proof. // future-proof.
if (!f.is_psl_formula()) if (!f.is_psl_formula())
{ {
std::string s = spot::ltl::str_psl(f); std::string s = spot::str_psl(f);
error_at_line(2, 0, filename, linenum, error_at_line(2, 0, filename, linenum,
"formula '%s' is not an LTL or PSL formula", "formula '%s' is not an LTL or PSL formula",
s.c_str()); s.c_str());

View file

@ -819,7 +819,7 @@ namespace
} }
typedef typedef
std::unordered_set<spot::ltl::formula> fset_t; std::unordered_set<spot::formula> fset_t;
class processor: public job_processor class processor: public job_processor
@ -838,14 +838,14 @@ namespace
const char* filename, const char* filename,
int linenum) int linenum)
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = parse_formula(input, pel); spot::formula f = parse_formula(input, pel);
if (!f || !pel.empty()) if (!f || !pel.empty())
{ {
if (filename) if (filename)
error_at_line(0, 0, filename, linenum, "parse error:"); error_at_line(0, 0, filename, linenum, "parse error:");
spot::ltl::format_parse_errors(std::cerr, input, pel); spot::format_parse_errors(std::cerr, input, pel);
return 1; return 1;
} }
@ -856,7 +856,7 @@ namespace
if (res && grind_output) if (res && grind_output)
{ {
std::string bogus = input; std::string bogus = input;
std::vector<spot::ltl::formula> mutations; std::vector<spot::formula> mutations;
unsigned mutation_count; unsigned mutation_count;
unsigned mutation_max; unsigned mutation_max;
while (res) while (res)
@ -886,9 +886,9 @@ namespace
if (res) if (res)
{ {
if (lbt_input) if (lbt_input)
bogus = spot::ltl::str_lbt_ltl(f); bogus = spot::str_lbt_ltl(f);
else else
bogus = spot::ltl::str_psl(f); bogus = spot::str_psl(f);
if (bogus_output) if (bogus_output)
bogus_output->ostream() << bogus << std::endl; bogus_output->ostream() << bogus << std::endl;
} }
@ -938,7 +938,7 @@ namespace
} }
int int
process_formula(spot::ltl::formula f, process_formula(spot::formula f,
const char* filename = nullptr, int linenum = 0) const char* filename = nullptr, int linenum = 0)
{ {
static unsigned round = 0; static unsigned round = 0;
@ -947,7 +947,7 @@ namespace
// output, relabel the formula. // output, relabel the formula.
if (!f.has_lbt_atomic_props() && if (!f.has_lbt_atomic_props() &&
(runner.has('l') || runner.has('L') || runner.has('T'))) (runner.has('l') || runner.has('L') || runner.has('T')))
f = spot::ltl::relabel(f, spot::ltl::Pnn); f = spot::relabel(f, spot::Pnn);
// ---------- Positive Formula ---------- // ---------- Positive Formula ----------
@ -1028,7 +1028,7 @@ namespace
nstats = &vstats[n + 1]; nstats = &vstats[n + 1];
nstats->resize(m); nstats->resize(m);
spot::ltl::formula nf = spot::ltl::formula::Not(f); spot::formula nf = spot::formula::Not(f);
if (!allow_dups) if (!allow_dups)
{ {
@ -1143,7 +1143,7 @@ namespace
std::cerr << "Gathering statistics..." << std::endl; std::cerr << "Gathering statistics..." << std::endl;
} }
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f); spot::atomic_prop_set* ap = spot::atomic_prop_collect(f);
if (want_stats) if (want_stats)
for (size_t i = 0; i < m; ++i) for (size_t i = 0; i < m; ++i)

View file

@ -237,14 +237,14 @@ namespace
const char* filename, const char* filename,
int linenum) int linenum)
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = parse_formula(input, pel); spot::formula f = parse_formula(input, pel);
if (!f || !pel.empty()) if (!f || !pel.empty())
{ {
if (filename) if (filename)
error_at_line(0, 0, filename, linenum, "parse error:"); error_at_line(0, 0, filename, linenum, "parse error:");
spot::ltl::format_parse_errors(std::cerr, input, pel); spot::format_parse_errors(std::cerr, input, pel);
return 1; return 1;
} }
@ -255,10 +255,10 @@ namespace
int int
process_formula(spot::ltl::formula f, process_formula(spot::formula f,
const char* filename = nullptr, int linenum = 0) const char* filename = nullptr, int linenum = 0)
{ {
std::unique_ptr<spot::ltl::relabeling_map> relmap; std::unique_ptr<spot::relabeling_map> relmap;
// If atomic propositions are incompatible with one of the // If atomic propositions are incompatible with one of the
// output, relabel the formula. // output, relabel the formula.
@ -267,8 +267,8 @@ namespace
|| (!f.has_spin_atomic_props() && || (!f.has_spin_atomic_props() &&
(runner.has('s') || runner.has('S')))) (runner.has('s') || runner.has('S'))))
{ {
relmap.reset(new spot::ltl::relabeling_map); relmap.reset(new spot::relabeling_map);
f = spot::ltl::relabel(f, spot::ltl::Pnn, relmap.get()); f = spot::relabel(f, spot::Pnn, relmap.get());
} }
static unsigned round = 1; static unsigned round = 1;

View file

@ -251,7 +251,7 @@ static int bsize_min = -1;
static int bsize_max = -1; static int bsize_max = -1;
enum relabeling_mode { NoRelabeling = 0, ApRelabeling, BseRelabeling }; enum relabeling_mode { NoRelabeling = 0, ApRelabeling, BseRelabeling };
static relabeling_mode relabeling = NoRelabeling; static relabeling_mode relabeling = NoRelabeling;
static spot::ltl::relabeling_style style = spot::ltl::Abc; static spot::relabeling_style style = spot::Abc;
static bool remove_x = false; static bool remove_x = false;
static bool stutter_insensitive = false; static bool stutter_insensitive = false;
static bool ap = false; static bool ap = false;
@ -262,16 +262,16 @@ static spot::exclusive_ap excl_ap;
static std::unique_ptr<output_file> output_define = nullptr; static std::unique_ptr<output_file> output_define = nullptr;
static std::string unabbreviate; static std::string unabbreviate;
static spot::ltl::formula implied_by = nullptr; static spot::formula implied_by = nullptr;
static spot::ltl::formula imply = nullptr; static spot::formula imply = nullptr;
static spot::ltl::formula equivalent_to = nullptr; static spot::formula equivalent_to = nullptr;
static spot::ltl::formula static spot::formula
parse_formula_arg(const std::string& input) parse_formula_arg(const std::string& input)
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = parse_formula(input, pel); spot::formula f = parse_formula(input, pel);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
error(2, 0, "parse error when parsing an argument"); error(2, 0, "parse error when parsing an argument");
return f; return f;
} }
@ -343,16 +343,16 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case OPT_IMPLIED_BY: case OPT_IMPLIED_BY:
{ {
spot::ltl::formula i = parse_formula_arg(arg); spot::formula i = parse_formula_arg(arg);
// a→c∧b→c ≡ (ab)→c // a→c∧b→c ≡ (ab)→c
implied_by = spot::ltl::formula::Or({implied_by, i}); implied_by = spot::formula::Or({implied_by, i});
break; break;
} }
case OPT_IMPLY: case OPT_IMPLY:
{ {
// a→b∧a→c ≡ a→(b∧c) // a→b∧a→c ≡ a→(b∧c)
spot::ltl::formula i = parse_formula_arg(arg); spot::formula i = parse_formula_arg(arg);
imply = spot::ltl::formula::And({imply, i}); imply = spot::formula::And({imply, i});
break; break;
} }
case OPT_LTL: case OPT_LTL:
@ -371,9 +371,9 @@ parse_opt(int key, char* arg, struct argp_state*)
case OPT_RELABEL_BOOL: case OPT_RELABEL_BOOL:
relabeling = (key == OPT_RELABEL_BOOL ? BseRelabeling : ApRelabeling); relabeling = (key == OPT_RELABEL_BOOL ? BseRelabeling : ApRelabeling);
if (!arg || !strncasecmp(arg, "abc", 6)) if (!arg || !strncasecmp(arg, "abc", 6))
style = spot::ltl::Abc; style = spot::Abc;
else if (!strncasecmp(arg, "pnn", 4)) else if (!strncasecmp(arg, "pnn", 4))
style = spot::ltl::Pnn; style = spot::Pnn;
else else
error(2, 0, "invalid argument for --relabel%s: '%s'", error(2, 0, "invalid argument for --relabel%s: '%s'",
(key == OPT_RELABEL_BOOL ? "-bool" : ""), (key == OPT_RELABEL_BOOL ? "-bool" : ""),
@ -404,7 +404,7 @@ parse_opt(int key, char* arg, struct argp_state*)
if (arg) if (arg)
unabbreviate += arg; unabbreviate += arg;
else else
unabbreviate += spot::ltl::default_unabbrev_string; unabbreviate += spot::default_unabbrev_string;
break; break;
case OPT_AP_N: case OPT_AP_N:
ap = true; ap = true;
@ -438,18 +438,18 @@ parse_opt(int key, char* arg, struct argp_state*)
} }
typedef typedef
std::unordered_set<spot::ltl::formula> fset_t; std::unordered_set<spot::formula> fset_t;
namespace namespace
{ {
class ltl_processor: public job_processor class ltl_processor: public job_processor
{ {
public: public:
spot::ltl::ltl_simplifier& simpl; spot::ltl_simplifier& simpl;
fset_t unique_set; fset_t unique_set;
spot::ltl::relabeling_map relmap; spot::relabeling_map relmap;
ltl_processor(spot::ltl::ltl_simplifier& simpl) ltl_processor(spot::ltl_simplifier& simpl)
: simpl(simpl) : simpl(simpl)
{ {
} }
@ -458,8 +458,8 @@ namespace
process_string(const std::string& input, process_string(const std::string& input,
const char* filename = nullptr, int linenum = 0) const char* filename = nullptr, int linenum = 0)
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
spot::ltl::formula f = parse_formula(input, pel); spot::formula f = parse_formula(input, pel);
if (!f || pel.size() > 0) if (!f || pel.size() > 0)
{ {
@ -467,7 +467,7 @@ namespace
{ {
if (filename) if (filename)
error_at_line(0, 0, filename, linenum, "parse error:"); error_at_line(0, 0, filename, linenum, "parse error:");
spot::ltl::format_parse_errors(std::cerr, input, pel); spot::format_parse_errors(std::cerr, input, pel);
} }
if (error_style == skip_errors) if (error_style == skip_errors)
@ -489,7 +489,7 @@ namespace
} }
int int
process_formula(spot::ltl::formula f, process_formula(spot::formula f,
const char* filename = nullptr, int linenum = 0) const char* filename = nullptr, int linenum = 0)
{ {
if (opt_max_count >= 0 && match_count >= opt_max_count) if (opt_max_count >= 0 && match_count >= opt_max_count)
@ -499,14 +499,14 @@ namespace
} }
if (negate) if (negate)
f = spot::ltl::formula::Not(f); f = spot::formula::Not(f);
if (remove_x) if (remove_x)
{ {
// If simplification are enabled, we do them before and after. // If simplification are enabled, we do them before and after.
if (simplification_level) if (simplification_level)
f = simpl.simplify(f); f = simpl.simplify(f);
f = spot::ltl::remove_x(f); f = spot::remove_x(f);
} }
if (simplification_level || boolean_to_isop) if (simplification_level || boolean_to_isop)
@ -520,13 +520,13 @@ namespace
case ApRelabeling: case ApRelabeling:
{ {
relmap.clear(); relmap.clear();
f = spot::ltl::relabel(f, style, &relmap); f = spot::relabel(f, style, &relmap);
break; break;
} }
case BseRelabeling: case BseRelabeling:
{ {
relmap.clear(); relmap.clear();
f = spot::ltl::relabel_bse(f, style, &relmap); f = spot::relabel_bse(f, style, &relmap);
break; break;
} }
case NoRelabeling: case NoRelabeling:
@ -534,7 +534,7 @@ namespace
} }
if (!unabbreviate.empty()) if (!unabbreviate.empty())
f = spot::ltl::unabbreviate(f, unabbreviate.c_str()); f = spot::unabbreviate(f, unabbreviate.c_str());
if (!excl_ap.empty()) if (!excl_ap.empty())
f = excl_ap.constrain(f); f = excl_ap.constrain(f);
@ -556,14 +556,14 @@ namespace
if (matched && (size_min > 0 || size_max >= 0)) if (matched && (size_min > 0 || size_max >= 0))
{ {
int l = spot::ltl::length(f); int l = spot::length(f);
matched &= (size_min <= 0) || (l >= size_min); matched &= (size_min <= 0) || (l >= size_min);
matched &= (size_max < 0) || (l <= size_max); matched &= (size_max < 0) || (l <= size_max);
} }
if (matched && (bsize_min > 0 || bsize_max >= 0)) if (matched && (bsize_min > 0 || bsize_max >= 0))
{ {
int l = spot::ltl::length_boolone(f); int l = spot::length_boolone(f);
matched &= (bsize_min <= 0) || (l >= bsize_min); matched &= (bsize_min <= 0) || (l >= bsize_min);
matched &= (bsize_max < 0) || (l <= bsize_max); matched &= (bsize_max < 0) || (l <= bsize_max);
} }
@ -606,7 +606,7 @@ namespace
&& output_format != quiet_output) && output_format != quiet_output)
{ {
// Sort the formulas alphabetically. // Sort the formulas alphabetically.
std::map<std::string, spot::ltl::formula> m; std::map<std::string, spot::formula> m;
for (auto& p: relmap) for (auto& p: relmap)
m.emplace(str_psl(p.first), p.second); m.emplace(str_psl(p.first), p.second);
for (auto& p: m) for (auto& p: m)
@ -641,9 +641,9 @@ main(int argc, char** argv)
if (boolean_to_isop && simplification_level == 0) if (boolean_to_isop && simplification_level == 0)
simplification_level = 1; simplification_level = 1;
spot::ltl::ltl_simplifier_options opt(simplification_level); spot::ltl_simplifier_options opt(simplification_level);
opt.boolean_to_isop = boolean_to_isop; opt.boolean_to_isop = boolean_to_isop;
spot::ltl::ltl_simplifier simpl(opt); spot::ltl_simplifier simpl(opt);
ltl_processor processor(simpl); ltl_processor processor(simpl);
if (processor.run()) if (processor.run())

View file

@ -43,7 +43,7 @@ enum {
static unsigned mutation_nb = 1; static unsigned mutation_nb = 1;
static unsigned max_output = -1U; static unsigned max_output = -1U;
static unsigned opt_all = spot::ltl::Mut_All; static unsigned opt_all = spot::Mut_All;
static unsigned mut_opts = 0; static unsigned mut_opts = 0;
static bool opt_sort = false; static bool opt_sort = false;
@ -96,11 +96,11 @@ namespace
{ {
public: public:
int int
process_formula(spot::ltl::formula f, const char* filename = nullptr, process_formula(spot::formula f, const char* filename = nullptr,
int linenum = 0) int linenum = 0)
{ {
auto mutations = auto mutations =
spot::ltl::mutate(f, mut_opts, max_output, mutation_nb, opt_sort); spot::mutate(f, mut_opts, max_output, mutation_nb, opt_sort);
for (auto g: mutations) for (auto g: mutations)
output_formula_checked(g, filename, linenum); output_formula_checked(g, filename, linenum);
return 0; return 0;
@ -121,31 +121,31 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case OPT_AP2CONST: case OPT_AP2CONST:
opt_all = 0; opt_all = 0;
mut_opts |= spot::ltl::Mut_Ap2Const; mut_opts |= spot::Mut_Ap2Const;
break; break;
case OPT_REMOVE_ONE_AP: case OPT_REMOVE_ONE_AP:
opt_all = 0; opt_all = 0;
mut_opts |= spot::ltl::Mut_Remove_One_Ap; mut_opts |= spot::Mut_Remove_One_Ap;
break; break;
case OPT_REMOVE_MULTOP_OPERANDS: case OPT_REMOVE_MULTOP_OPERANDS:
opt_all = 0; opt_all = 0;
mut_opts |= spot::ltl::Mut_Remove_Multop_Operands; mut_opts |= spot::Mut_Remove_Multop_Operands;
break; break;
case OPT_REMOVE_OPS: case OPT_REMOVE_OPS:
opt_all = 0; opt_all = 0;
mut_opts |= spot::ltl::Mut_Remove_Ops; mut_opts |= spot::Mut_Remove_Ops;
break; break;
case OPT_SPLIT_OPS: case OPT_SPLIT_OPS:
opt_all = 0; opt_all = 0;
mut_opts |= spot::ltl::Mut_Split_Ops; mut_opts |= spot::Mut_Split_Ops;
break; break;
case OPT_REWRITE_OPS: case OPT_REWRITE_OPS:
opt_all = 0; opt_all = 0;
mut_opts |= spot::ltl::Mut_Rewrite_Ops; mut_opts |= spot::Mut_Rewrite_Ops;
break; break;
case OPT_SIMPLIFY_BOUNDS: case OPT_SIMPLIFY_BOUNDS:
opt_all = 0; opt_all = 0;
mut_opts |= spot::ltl::Mut_Simplify_Bounds; mut_opts |= spot::Mut_Simplify_Bounds;
break; break;
case OPT_SORT: case OPT_SORT:
opt_sort = true; opt_sort = true;

View file

@ -135,7 +135,7 @@ static const struct argp_child children[] =
static const char* opt_acceptance = nullptr; static const char* opt_acceptance = nullptr;
typedef spot::twa_graph::graph_t::edge_storage_t tr_t; typedef spot::twa_graph::graph_t::edge_storage_t tr_t;
typedef std::set<std::vector<tr_t>> unique_aut_t; typedef std::set<std::vector<tr_t>> unique_aut_t;
static spot::ltl::atomic_prop_set aprops; static spot::atomic_prop_set aprops;
static range ap_count_given = {-1, -2}; // Must be two different negative val static range ap_count_given = {-1, -2}; // Must be two different negative val
static int opt_seed = 0; static int opt_seed = 0;
static const char* opt_seed_str = "0"; static const char* opt_seed_str = "0";
@ -249,10 +249,10 @@ parse_opt(int key, char* arg, struct argp_state* as)
ap_count_given = parse_range(arg); ap_count_given = parse_range(arg);
// Create the set once if the count is fixed. // Create the set once if the count is fixed.
if (ap_count_given.min == ap_count_given.max) if (ap_count_given.min == ap_count_given.max)
aprops = spot::ltl::create_atomic_prop_set(ap_count_given.min); aprops = spot::create_atomic_prop_set(ap_count_given.min);
break; break;
} }
aprops.insert(spot::ltl::formula::ap(arg)); aprops.insert(spot::formula::ap(arg));
break; break;
default: default:
@ -329,7 +329,7 @@ main(int argc, char** argv)
&& ap_count_given.min != ap_count_given.max) && ap_count_given.min != ap_count_given.max)
{ {
int c = spot::rrand(ap_count_given.min, ap_count_given.max); int c = spot::rrand(ap_count_given.min, ap_count_given.max);
aprops = spot::ltl::create_atomic_prop_set(c); aprops = spot::create_atomic_prop_set(c);
} }
int size = opt_states.min; int size = opt_states.min;

View file

@ -130,7 +130,7 @@ const struct argp_child children[] =
{ nullptr, 0, nullptr, 0 } { nullptr, 0, nullptr, 0 }
}; };
spot::ltl::atomic_prop_set aprops; spot::atomic_prop_set aprops;
static int output = OUTPUTLTL; static int output = OUTPUTLTL;
static char* opt_pL = nullptr; static char* opt_pL = nullptr;
static char* opt_pS = nullptr; static char* opt_pS = nullptr;
@ -209,11 +209,11 @@ parse_opt(int key, char* arg, struct argp_state* as)
if (!*endptr && res >= 0) // arg is a number if (!*endptr && res >= 0) // arg is a number
{ {
ap_count_given = true; ap_count_given = true;
aprops = spot::ltl::create_atomic_prop_set(res); aprops = spot::create_atomic_prop_set(res);
break; break;
} }
} }
aprops.insert(spot::ltl::default_environment::instance().require(arg)); aprops.insert(spot::default_environment::instance().require(arg));
break; break;
default: default:
return ARGP_ERR_UNKNOWN; return ARGP_ERR_UNKNOWN;
@ -241,7 +241,7 @@ main(int argc, char** argv)
spot::srand(opt_seed); spot::srand(opt_seed);
try try
{ {
spot::ltl::randltlgenerator rg spot::randltlgenerator rg
(aprops, (aprops,
[&] (){ [&] (){
spot::option_map opts; spot::option_map opts;
@ -292,7 +292,7 @@ main(int argc, char** argv)
while (opt_formulas < 0 || opt_formulas--) while (opt_formulas < 0 || opt_formulas--)
{ {
static int count = 0; static int count = 0;
spot::ltl::formula f = rg.next(); spot::formula f = rg.next();
if (!f) if (!f)
{ {
error(2, 0, "failed to generate a new unique formula after %d " \ error(2, 0, "failed to generate a new unique formula after %d " \

View file

@ -260,7 +260,7 @@ namespace spot
} }
void kripke_explicit::add_condition(ltl::formula f, std::string on_me) void kripke_explicit::add_condition(formula f, std::string on_me)
{ {
add_conditions(formula_to_bdd(f, get_dict(), this), on_me); add_conditions(formula_to_bdd(f, get_dict(), this), on_me);
} }

View file

@ -151,7 +151,7 @@ namespace spot
/// ///
/// \param f the formula to add. /// \param f the formula to add.
/// \param on_me the state where to add. /// \param on_me the state where to add.
void add_condition(ltl::formula f, std::string on_me); void add_condition(formula f, std::string on_me);
/// \brief Return map between states and their names. /// \brief Return map between states and their names.
const std::map<const state_kripke*, std::string>& const std::map<const state_kripke*, std::string>&

View file

@ -40,7 +40,7 @@ typedef std::map<std::string, bdd> formula_cache;
} }
%parse-param {spot::kripke_parse_error_list& error_list} %parse-param {spot::kripke_parse_error_list& error_list}
%parse-param {spot::ltl::environment& parse_environment} %parse-param {spot::environment& parse_environment}
%parse-param {spot::kripke_explicit_ptr& result} %parse-param {spot::kripke_explicit_ptr& result}
%parse-param {formula_cache& fcache} %parse-param {formula_cache& fcache}
@ -62,9 +62,9 @@ typedef std::map<std::string, bdd> formula_cache;
before parsedecl.hh uses it. */ before parsedecl.hh uses it. */
#include "parsedecl.hh" #include "parsedecl.hh"
using namespace spot::ltl; using namespace spot;
#include <iostream> #include <iostream>
//typedef std::pair<bool, spot::ltl::formula*> pair; //typedef std::pair<bool, spot::formula*> pair;
} }
%token <str> STRING UNTERMINATED_STRING IDENT %token <str> STRING UNTERMINATED_STRING IDENT
@ -109,7 +109,7 @@ strident "," condition "," follow_list ";"
if (i == fcache.end()) if (i == fcache.end())
{ {
parse_error_list pel; parse_error_list pel;
formula f = spot::ltl::parse_infix_boolean(*$3, pel, formula f = spot::parse_infix_boolean(*$3, pel,
parse_environment); parse_environment);
for (parse_error_list::iterator i = pel.begin(); for (parse_error_list::iterator i = pel.begin();
i != pel.end(); ++i) i != pel.end(); ++i)
@ -207,7 +207,7 @@ namespace spot
error_list.push_back error_list.push_back
(kripke_parse_error(spot::location(), (kripke_parse_error(spot::location(),
std::string("Cannot open file ") + name)); std::string("Cannot open file ") + name));
return 0; return nullptr;
} }
formula_cache fcache; formula_cache fcache;
auto result = make_kripke_explicit(dict); auto result = make_kripke_explicit(dict);

View file

@ -41,15 +41,15 @@ namespace spot
kripke_parse(const std::string& name, kripke_parse(const std::string& name,
kripke_parse_error_list& error_list, kripke_parse_error_list& error_list,
const bdd_dict_ptr& dict, const bdd_dict_ptr& dict,
ltl::environment& env environment& env
= ltl::default_environment::instance(), = default_environment::instance(),
bool debug = false); bool debug = false);
/// \brief Format diagnostics produced by spot::kripke_parse. /// \brief Format diagnostics produced by spot::kripke_parse.
/// \param os Where diagnostics should be output. /// \param os Where diagnostics should be output.
/// \param filename The filename that should appear in the diagnostics. /// \param filename The filename that should appear in the diagnostics.
/// \param error_list The error list filled by spot::ltl::parse while /// \param error_list The error list filled by spot::parse while
/// parsing \a ltl_string. /// parsing \a ltl_string.
/// \return \c true if any diagnostic was output. /// \return \c true if any diagnostic was output.
SPOT_API SPOT_API

View file

@ -28,90 +28,85 @@
namespace spot namespace spot
{ {
namespace ltl void
fix_utf8_locations(const std::string& ltl_string,
parse_error_list& error_list)
{ {
// LUT to convert byte positions to utf8 positions.
// (The +2 is to account for position 0, not used,
// and position ltl_string.size()+1 denoting EOS.)
std::vector<unsigned> b2u(ltl_string.size() + 2);
void // i will iterate over all utf8 characters between b and e
fix_utf8_locations(const std::string& ltl_string, std::string::const_iterator b = ltl_string.begin();
parse_error_list& error_list) std::string::const_iterator i = b;
std::string::const_iterator e = ltl_string.end();
unsigned n = 0; // number of current utf8 character
unsigned prev = 0; // last byte of previous utf8 character
while (i != e)
{
utf8::next(i, e);
++n;
unsigned d = std::distance(b, i);
while (prev < d)
b2u[++prev] = n;
}
b2u[++prev] = ++n;
// use b2u to update error_list
parse_error_list::iterator it;
for (it = error_list.begin(); it != error_list.end(); ++it)
{
location& l = it->first;
l.begin.column = b2u[l.begin.column];
l.end.column = b2u[l.end.column];
}
}
namespace
{
bool
format_parse_errors_aux(std::ostream& os,
const std::string& ltl_string,
const parse_error_list& error_list)
{ {
// LUT to convert byte positions to utf8 positions. bool printed = false;
// (The +2 is to account for position 0, not used, parse_error_list::const_iterator it;
// and position ltl_string.size()+1 denoting EOS.)
std::vector<unsigned> b2u(ltl_string.size() + 2);
// i will iterate over all utf8 characters between b and e
std::string::const_iterator b = ltl_string.begin();
std::string::const_iterator i = b;
std::string::const_iterator e = ltl_string.end();
unsigned n = 0; // number of current utf8 character
unsigned prev = 0; // last byte of previous utf8 character
while (i != e)
{
utf8::next(i, e);
++n;
unsigned d = std::distance(b, i);
while (prev < d)
b2u[++prev] = n;
}
b2u[++prev] = ++n;
// use b2u to update error_list
parse_error_list::iterator it;
for (it = error_list.begin(); it != error_list.end(); ++it) for (it = error_list.begin(); it != error_list.end(); ++it)
{ {
location& l = it->first; os << ">>> " << ltl_string << std::endl;
l.begin.column = b2u[l.begin.column]; const location& l = it->first;
l.end.column = b2u[l.end.column];
}
}
namespace unsigned n = 1;
{ for (; n < 4 + l.begin.column; ++n)
bool os << ' ';
format_parse_errors_aux(std::ostream& os, // Write at least one '^', even if begin==end.
const std::string& ltl_string, os << '^';
const parse_error_list& error_list) ++n;
{ for (; n < 4 + l.end.column; ++n)
bool printed = false;
parse_error_list::const_iterator it;
for (it = error_list.begin(); it != error_list.end(); ++it)
{
os << ">>> " << ltl_string << std::endl;
const location& l = it->first;
unsigned n = 1;
for (; n < 4 + l.begin.column; ++n)
os << ' ';
// Write at least one '^', even if begin==end.
os << '^'; os << '^';
++n; os << std::endl << it->second << std::endl << std::endl;
for (; n < 4 + l.end.column; ++n) printed = true;
os << '^'; }
os << std::endl << it->second << std::endl << std::endl; return printed;
printed = true; }
} }
return printed;
bool
format_parse_errors(std::ostream& os,
const std::string& ltl_string,
const parse_error_list& error_list)
{
if (utf8::is_valid(ltl_string.begin(), ltl_string.end()))
{
parse_error_list fixed = error_list;
fix_utf8_locations(ltl_string, fixed);
return format_parse_errors_aux(os, ltl_string, fixed);
}
else
{
return format_parse_errors_aux(os, ltl_string, error_list);
} }
}
bool
format_parse_errors(std::ostream& os,
const std::string& ltl_string,
const parse_error_list& error_list)
{
if (utf8::is_valid(ltl_string.begin(), ltl_string.end()))
{
parse_error_list fixed = error_list;
fix_utf8_locations(ltl_string, fixed);
return format_parse_errors_aux(os, ltl_string, fixed);
}
else
{
return format_parse_errors_aux(os, ltl_string, error_list);
}
}
} }
} }

View file

@ -27,7 +27,7 @@
%debug %debug
%error-verbose %error-verbose
%expect 0 %expect 0
%lex-param { spot::ltl::parse_error_list& error_list } %lex-param { spot::parse_error_list& error_list }
%define api.location.type "spot::location" %define api.location.type "spot::location"
%code requires %code requires
@ -41,13 +41,13 @@
struct minmax_t { unsigned min, max; }; struct minmax_t { unsigned min, max; };
} }
%parse-param {spot::ltl::parse_error_list &error_list} %parse-param {spot::parse_error_list &error_list}
%parse-param {spot::ltl::environment &parse_environment} %parse-param {spot::environment &parse_environment}
%parse-param {spot::ltl::formula &result} %parse-param {spot::formula &result}
%union %union
{ {
std::string* str; std::string* str;
const spot::ltl::fnode* ltl; const spot::fnode* ltl;
unsigned num; unsigned num;
minmax_t minmax; minmax_t minmax;
} }
@ -57,7 +57,7 @@
We mut ensure that YYSTYPE is declared (by the above %union) We mut ensure that YYSTYPE is declared (by the above %union)
before parsedecl.hh uses it. */ before parsedecl.hh uses it. */
#include "parsedecl.hh" #include "parsedecl.hh"
using namespace spot::ltl; using namespace spot;
#define missing_right_op_msg(op, str) \ #define missing_right_op_msg(op, str) \
error_list.emplace_back(op, \ error_list.emplace_back(op, \
@ -94,10 +94,10 @@ using namespace spot::ltl;
static formula static formula
try_recursive_parse(const std::string& str, try_recursive_parse(const std::string& str,
const spot::location& location, const spot::location& location,
spot::ltl::environment& env, spot::environment& env,
bool debug, bool debug,
parser_type type, parser_type type,
spot::ltl::parse_error_list& error_list) spot::parse_error_list& error_list)
{ {
// We want to parse a U (b U c) as two until operators applied // We want to parse a U (b U c) as two until operators applied
// to the atomic propositions a, b, and c. We also want to // to the atomic propositions a, b, and c. We also want to
@ -120,18 +120,18 @@ using namespace spot::ltl;
return nullptr; return nullptr;
} }
spot::ltl::parse_error_list suberror; spot::parse_error_list suberror;
formula f; formula f;
switch (type) switch (type)
{ {
case parser_sere: case parser_sere:
f = spot::ltl::parse_infix_sere(str, suberror, env, debug, true); f = spot::parse_infix_sere(str, suberror, env, debug, true);
break; break;
case parser_bool: case parser_bool:
f = spot::ltl::parse_infix_boolean(str, suberror, env, debug, true); f = spot::parse_infix_boolean(str, suberror, env, debug, true);
break; break;
case parser_ltl: case parser_ltl:
f = spot::ltl::parse_infix_psl(str, suberror, env, debug, true); f = spot::parse_infix_psl(str, suberror, env, debug, true);
break; break;
} }
@ -237,8 +237,8 @@ using namespace spot::ltl;
%destructor { $$->destroy(); } <ltl> %destructor { $$->destroy(); } <ltl>
%printer { debug_stream() << *$$; } <str> %printer { debug_stream() << *$$; } <str>
%printer { spot::ltl::print_psl(debug_stream(), formula($$)); } <ltl> %printer { print_psl(debug_stream(), formula($$)); } <ltl>
%printer { spot::ltl::print_sere(debug_stream(), formula($$)); } sere bracedsere %printer { print_sere(debug_stream(), formula($$)); } sere bracedsere
%printer { debug_stream() << $$; } <num> %printer { debug_stream() << $$; } <num>
%printer { debug_stream() << $$.min << ".." << $$.max; } <minmax> %printer { debug_stream() << $$.min << ".." << $$.max; } <minmax>
@ -993,95 +993,91 @@ ltlyy::parser::error(const location_type& location, const std::string& message)
namespace spot namespace spot
{ {
namespace ltl formula
parse_infix_psl(const std::string& ltl_string,
parse_error_list& error_list,
environment& env,
bool debug, bool lenient)
{ {
formula formula result = nullptr;
parse_infix_psl(const std::string& ltl_string, flex_set_buffer(ltl_string,
parse_error_list& error_list, ltlyy::parser::token::START_LTL,
environment& env, lenient);
bool debug, bool lenient) ltlyy::parser parser(error_list, env, result);
{ parser.set_debug_level(debug);
formula result = nullptr; parser.parse();
flex_set_buffer(ltl_string, flex_unset_buffer();
ltlyy::parser::token::START_LTL, return result;
lenient); }
ltlyy::parser parser(error_list, env, result);
parser.set_debug_level(debug);
parser.parse();
flex_unset_buffer();
return result;
}
formula formula
parse_infix_boolean(const std::string& ltl_string, parse_infix_boolean(const std::string& ltl_string,
parse_error_list& error_list, parse_error_list& error_list,
environment& env, environment& env,
bool debug, bool lenient) bool debug, bool lenient)
{ {
formula result = nullptr; formula result = nullptr;
flex_set_buffer(ltl_string, flex_set_buffer(ltl_string,
ltlyy::parser::token::START_BOOL, ltlyy::parser::token::START_BOOL,
lenient); lenient);
ltlyy::parser parser(error_list, env, result); ltlyy::parser parser(error_list, env, result);
parser.set_debug_level(debug); parser.set_debug_level(debug);
parser.parse(); parser.parse();
flex_unset_buffer(); flex_unset_buffer();
return result; return result;
} }
formula formula
parse_prefix_ltl(const std::string& ltl_string, parse_prefix_ltl(const std::string& ltl_string,
parse_error_list& error_list, parse_error_list& error_list,
environment& env, environment& env,
bool debug) bool debug)
{ {
formula result = nullptr; formula result = nullptr;
flex_set_buffer(ltl_string, flex_set_buffer(ltl_string,
ltlyy::parser::token::START_LBT, ltlyy::parser::token::START_LBT,
false); false);
ltlyy::parser parser(error_list, env, result); ltlyy::parser parser(error_list, env, result);
parser.set_debug_level(debug); parser.set_debug_level(debug);
parser.parse(); parser.parse();
flex_unset_buffer(); flex_unset_buffer();
return result; return result;
} }
formula formula
parse_infix_sere(const std::string& sere_string, parse_infix_sere(const std::string& sere_string,
parse_error_list& error_list, parse_error_list& error_list,
environment& env, environment& env,
bool debug, bool debug,
bool lenient) bool lenient)
{ {
formula result = nullptr; formula result = nullptr;
flex_set_buffer(sere_string, flex_set_buffer(sere_string,
ltlyy::parser::token::START_SERE, ltlyy::parser::token::START_SERE,
lenient); lenient);
ltlyy::parser parser(error_list, env, result); ltlyy::parser parser(error_list, env, result);
parser.set_debug_level(debug); parser.set_debug_level(debug);
parser.parse(); parser.parse();
flex_unset_buffer(); flex_unset_buffer();
return result; return result;
} }
formula
parse_formula(const std::string& ltl_string, environment& env)
{
parse_error_list pel;
formula f = parse_infix_psl(ltl_string, pel, env);
std::ostringstream s;
if (format_parse_errors(s, ltl_string, pel))
{
parse_error_list pel2;
formula g = parse_prefix_ltl(ltl_string, pel2, env);
if (pel2.empty())
return g;
else
throw parse_error(s.str());
}
return f;
}
formula
parse_formula(const std::string& ltl_string, environment& env)
{
parse_error_list pel;
formula f = parse_infix_psl(ltl_string, pel, env);
std::ostringstream s;
if (format_parse_errors(s, ltl_string, pel))
{
parse_error_list pel2;
formula g = parse_prefix_ltl(ltl_string, pel2, env);
if (pel2.empty())
return g;
else
throw parse_error(s.str());
}
return f;
} }
} }

View file

@ -99,7 +99,7 @@ eol2 (\n\r)+|(\r\n)+
<<EOF>> { <<EOF>> {
BEGIN(orig_cond); BEGIN(orig_cond);
error_list.push_back( error_list.push_back(
spot::ltl::one_parse_error(*yylloc, spot::one_parse_error(*yylloc,
"unclosed comment")); "unclosed comment"));
return 0; return 0;
} }
@ -141,7 +141,7 @@ eol2 (\n\r)+|(\r\n)+
unput(')'); unput(')');
if (!missing_parent) if (!missing_parent)
error_list.push_back( error_list.push_back(
spot::ltl::one_parse_error(*yylloc, spot::one_parse_error(*yylloc,
"missing closing parenthese")); "missing closing parenthese"));
missing_parent = true; missing_parent = true;
} }
@ -195,7 +195,7 @@ eol2 (\n\r)+|(\r\n)+
unput(')'); unput(')');
if (!missing_parent) if (!missing_parent)
error_list.push_back( error_list.push_back(
spot::ltl::one_parse_error(*yylloc, spot::one_parse_error(*yylloc,
"missing closing brace")); "missing closing brace"));
missing_parent = true; missing_parent = true;
} }
@ -238,7 +238,7 @@ eol2 (\n\r)+|(\r\n)+
if (errno || yylval->num != n) if (errno || yylval->num != n)
{ {
error_list.push_back( error_list.push_back(
spot::ltl::one_parse_error(*yylloc, spot::one_parse_error(*yylloc,
"value too large ignored")); "value too large ignored"));
// Skip this number and read next token // Skip this number and read next token
yylloc->step(); yylloc->step();
@ -347,7 +347,7 @@ eol2 (\n\r)+|(\r\n)+
[^\\\"\n\r]+ s.append(yytext, yyleng); [^\\\"\n\r]+ s.append(yytext, yyleng);
<<EOF>> { <<EOF>> {
error_list.push_back( error_list.push_back(
spot::ltl::one_parse_error(*yylloc, spot::one_parse_error(*yylloc,
"unclosed string")); "unclosed string"));
BEGIN(orig_cond); BEGIN(orig_cond);
yylval->str = new std::string(s); yylval->str = new std::string(s);

View file

@ -28,7 +28,7 @@
# define YY_DECL \ # define YY_DECL \
int ltlyylex (ltlyy::parser::semantic_type *yylval, \ int ltlyylex (ltlyy::parser::semantic_type *yylval, \
spot::location *yylloc, \ spot::location *yylloc, \
spot::ltl::parse_error_list& error_list) spot::parse_error_list& error_list)
YY_DECL; YY_DECL;
void flex_set_buffer(const std::string& buf, int start_tok, bool lenient); void flex_set_buffer(const std::string& buf, int start_tok, bool lenient);

View file

@ -32,180 +32,177 @@
namespace spot namespace spot
{ {
namespace ltl /// \addtogroup ltl_io
{ /// @{
/// \addtogroup ltl_io
/// @{
#ifndef SWIG #ifndef SWIG
/// \brief A parse diagnostic with its location. /// \brief A parse diagnostic with its location.
typedef std::pair<location, std::string> one_parse_error; typedef std::pair<location, std::string> one_parse_error;
/// \brief A list of parser diagnostics, as filled by parse. /// \brief A list of parser diagnostics, as filled by parse.
typedef std::list<one_parse_error> parse_error_list; typedef std::list<one_parse_error> parse_error_list;
#else #else
// Turn parse_error_list into an opaque type for Swig. // Turn parse_error_list into an opaque type for Swig.
struct parse_error_list {}; struct parse_error_list {};
#endif #endif
/// \brief Build a formula from an LTL string. /// \brief Build a formula from an LTL string.
/// \param ltl_string The string to parse. /// \param ltl_string The string to parse.
/// \param error_list A list that will be filled with /// \param error_list A list that will be filled with
/// parse errors that occured during parsing. /// parse errors that occured during parsing.
/// \param env The environment into which parsing should take place. /// \param env The environment into which parsing should take place.
/// \param debug When true, causes the parser to trace its execution. /// \param debug When true, causes the parser to trace its execution.
/// \param lenient When true, parenthesized blocks that cannot be /// \param lenient When true, parenthesized blocks that cannot be
/// parsed as subformulas will be considered as /// parsed as subformulas will be considered as
/// atomic propositions. /// atomic propositions.
/// \return A formula built from \a ltl_string, or /// \return A formula built from \a ltl_string, or
/// formula(nullptr) if the input was unparsable. /// formula(nullptr) if the input was unparsable.
/// ///
/// Note that the parser usually tries to recover from errors. It can /// Note that the parser usually tries to recover from errors. It can
/// return a non zero value even if it encountered error during the /// return a non zero value even if it encountered error during the
/// parsing of \a ltl_string. If you want to make sure \a ltl_string /// parsing of \a ltl_string. If you want to make sure \a ltl_string
/// was parsed succesfully, check \a error_list for emptiness. /// was parsed succesfully, check \a error_list for emptiness.
/// ///
/// \warning This function is not reentrant. /// \warning This function is not reentrant.
SPOT_API SPOT_API
formula parse_infix_psl(const std::string& ltl_string, formula parse_infix_psl(const std::string& ltl_string,
parse_error_list& error_list, parse_error_list& error_list,
environment& env = environment& env =
default_environment::instance(), default_environment::instance(),
bool debug = false, bool debug = false,
bool lenient = false); bool lenient = false);
/// \brief Build a Boolean formula from a string. /// \brief Build a Boolean formula from a string.
/// \param ltl_string The string to parse. /// \param ltl_string The string to parse.
/// \param error_list A list that will be filled with /// \param error_list A list that will be filled with
/// parse errors that occured during parsing. /// parse errors that occured during parsing.
/// \param env The environment into which parsing should take place. /// \param env The environment into which parsing should take place.
/// \param debug When true, causes the parser to trace its execution. /// \param debug When true, causes the parser to trace its execution.
/// \param lenient When true, parenthesized blocks that cannot be /// \param lenient When true, parenthesized blocks that cannot be
/// parsed as subformulas will be considered as /// parsed as subformulas will be considered as
/// atomic propositions. /// atomic propositions.
/// \return A formula built from \a ltl_string, or /// \return A formula built from \a ltl_string, or
/// formula(nullptr) if the input was unparsable. /// formula(nullptr) if the input was unparsable.
/// ///
/// Note that the parser usually tries to recover from errors. It can /// Note that the parser usually tries to recover from errors. It can
/// return a non zero value even if it encountered error during the /// return a non zero value even if it encountered error during the
/// parsing of \a ltl_string. If you want to make sure \a ltl_string /// parsing of \a ltl_string. If you want to make sure \a ltl_string
/// was parsed succesfully, check \a error_list for emptiness. /// was parsed succesfully, check \a error_list for emptiness.
/// ///
/// \warning This function is not reentrant. /// \warning This function is not reentrant.
SPOT_API SPOT_API
formula parse_infix_boolean(const std::string& ltl_string, formula parse_infix_boolean(const std::string& ltl_string,
parse_error_list& error_list, parse_error_list& error_list,
environment& env = environment& env =
default_environment::instance(), default_environment::instance(),
bool debug = false, bool debug = false,
bool lenient = false); bool lenient = false);
/// \brief Build a formula from an LTL string in LBT's format. /// \brief Build a formula from an LTL string in LBT's format.
/// \param ltl_string The string to parse. /// \param ltl_string The string to parse.
/// \param error_list A list that will be filled with /// \param error_list A list that will be filled with
/// parse errors that occured during parsing. /// parse errors that occured during parsing.
/// \param env The environment into which parsing should take place. /// \param env The environment into which parsing should take place.
/// \param debug When true, causes the parser to trace its execution. /// \param debug When true, causes the parser to trace its execution.
/// \return A formula built from \a ltl_string, or /// \return A formula built from \a ltl_string, or
/// formula(nullptr) if the input was unparsable. /// formula(nullptr) if the input was unparsable.
/// ///
/// Note that the parser usually tries to recover from errors. It can /// Note that the parser usually tries to recover from errors. It can
/// return an non zero value even if it encountered error during the /// return an non zero value even if it encountered error during the
/// parsing of \a ltl_string. If you want to make sure \a ltl_string /// parsing of \a ltl_string. If you want to make sure \a ltl_string
/// was parsed succesfully, check \a error_list for emptiness. /// was parsed succesfully, check \a error_list for emptiness.
/// ///
/// The LBT syntax, also used by the lbtt and scheck tools, is /// The LBT syntax, also used by the lbtt and scheck tools, is
/// extended to support W, and M operators (as done in lbtt), and /// extended to support W, and M operators (as done in lbtt), and
/// double-quoted atomic propositions that do not start with 'p'. /// double-quoted atomic propositions that do not start with 'p'.
/// ///
/// \warning This function is not reentrant. /// \warning This function is not reentrant.
SPOT_API SPOT_API
formula parse_prefix_ltl(const std::string& ltl_string, formula parse_prefix_ltl(const std::string& ltl_string,
parse_error_list& error_list, parse_error_list& error_list,
environment& env = environment& env =
default_environment::instance(), default_environment::instance(),
bool debug = false); bool debug = false);
/// \brief A simple wrapper to parse_infix_psl() and parse_prefix_ltl(). /// \brief A simple wrapper to parse_infix_psl() and parse_prefix_ltl().
/// ///
/// This is mostly meant for interactive use. It first tries /// This is mostly meant for interactive use. It first tries
/// parse_infix_psl(); if this fails it tries parse_prefix_ltl(); /// parse_infix_psl(); if this fails it tries parse_prefix_ltl();
/// and if both fails it returns the errors of the first call to /// and if both fails it returns the errors of the first call to
/// parse_infix_psl() as a parse_error exception. /// parse_infix_psl() as a parse_error exception.
SPOT_API formula SPOT_API formula
parse_formula(const std::string& ltl_string, parse_formula(const std::string& ltl_string,
environment& env = default_environment::instance()); environment& env = default_environment::instance());
/// \brief Build a formula from a string representing a SERE. /// \brief Build a formula from a string representing a SERE.
/// \param sere_string The string to parse. /// \param sere_string The string to parse.
/// \param error_list A list that will be filled with /// \param error_list A list that will be filled with
/// parse errors that occured during parsing. /// parse errors that occured during parsing.
/// \param env The environment into which parsing should take place. /// \param env The environment into which parsing should take place.
/// \param debug When true, causes the parser to trace its execution. /// \param debug When true, causes the parser to trace its execution.
/// \param lenient When true, parenthesized blocks that cannot be /// \param lenient When true, parenthesized blocks that cannot be
/// parsed as subformulas will be considered as /// parsed as subformulas will be considered as
/// atomic propositions. /// atomic propositions.
/// \return A formula built from \a sere_string, or /// \return A formula built from \a sere_string, or
/// formula(0) if the input was unparsable. /// formula(0) if the input was unparsable.
/// ///
/// Note that the parser usually tries to recover from errors. It can /// Note that the parser usually tries to recover from errors. It can
/// return an non zero value even if it encountered error during the /// return an non zero value even if it encountered error during the
/// parsing of \a ltl_string. If you want to make sure \a ltl_string /// parsing of \a ltl_string. If you want to make sure \a ltl_string
/// was parsed succesfully, check \a error_list for emptiness. /// was parsed succesfully, check \a error_list for emptiness.
/// ///
/// \warning This function is not reentrant. /// \warning This function is not reentrant.
SPOT_API SPOT_API
formula parse_infix_sere(const std::string& sere_string, formula parse_infix_sere(const std::string& sere_string,
parse_error_list& error_list, parse_error_list& error_list,
environment& env = environment& env =
default_environment::instance(), default_environment::instance(),
bool debug = false, bool debug = false,
bool lenient = false); bool lenient = false);
/// \brief Format diagnostics produced by spot::ltl::parse /// \brief Format diagnostics produced by spot::parse
/// or spot::ltl::ratexp /// or spot::ratexp
/// ///
/// If the string is utf8 encoded, spot::ltl::fix_utf8_locations() /// If the string is utf8 encoded, spot::fix_utf8_locations()
/// will be used to report correct utf8 locations (assuming the /// will be used to report correct utf8 locations (assuming the
/// output is utf8 aware). Nonetheless, the supplied \a /// output is utf8 aware). Nonetheless, the supplied \a
/// error_list will not be modified. /// error_list will not be modified.
/// ///
/// \param os Where diagnostics should be output. /// \param os Where diagnostics should be output.
/// \param input_string The string that were parsed. /// \param input_string The string that were parsed.
/// \param error_list The error list filled by spot::ltl::parse /// \param error_list The error list filled by spot::parse
/// or spot::ltl::parse_sere while parsing \a input_string. /// or spot::parse_sere while parsing \a input_string.
/// \return \c true iff any diagnostic was output. /// \return \c true iff any diagnostic was output.
SPOT_API SPOT_API
bool format_parse_errors(std::ostream& os, bool format_parse_errors(std::ostream& os,
const std::string& input_string, const std::string& input_string,
const parse_error_list& error_list); const parse_error_list& error_list);
/// \brief Fix location of diagnostics assuming the input is utf8. /// \brief Fix location of diagnostics assuming the input is utf8.
/// ///
/// The different parser functions return a parse_error_list that /// The different parser functions return a parse_error_list that
/// contain locations specified at the byte level. Although these /// contain locations specified at the byte level. Although these
/// parser recognize some utf8 characters they only work byte by /// parser recognize some utf8 characters they only work byte by
/// byte and will report positions by counting byte. /// byte and will report positions by counting byte.
/// ///
/// This function fixes the positions returned by the parser to /// This function fixes the positions returned by the parser to
/// look correct when the string is interpreted as a utf8-encoded /// look correct when the string is interpreted as a utf8-encoded
/// string. /// string.
/// ///
/// It is invalid to call this function on a string that is not /// It is invalid to call this function on a string that is not
/// valid utf8. /// valid utf8.
/// ///
/// You should NOT call this function before calling /// You should NOT call this function before calling
/// spot::ltl::format_parse_errors() because it is already called /// spot::format_parse_errors() because it is already called
/// inside if needed. You may need this function only if you want /// inside if needed. You may need this function only if you want
/// to write your own error reporting code. /// to write your own error reporting code.
/// ///
/// \param input_string The string that were parsed. /// \param input_string The string that were parsed.
/// \param error_list The error list filled by spot::ltl::parse /// \param error_list The error list filled by spot::parse
/// or spot::ltl::parse_sere while parsing \a input_string. /// or spot::parse_sere while parsing \a input_string.
SPOT_API SPOT_API
void void
fix_utf8_locations(const std::string& input_string, fix_utf8_locations(const std::string& input_string,
parse_error_list& error_list); parse_error_list& error_list);
/// @} /// @}
}
} }

View file

@ -44,7 +44,7 @@
typedef std::map<int, bdd> map_t; typedef std::map<int, bdd> map_t;
/* Cache parsed formulae. Labels on arcs are frequently identical /* Cache parsed formulae. Labels on arcs are frequently identical
and it would be a waste of time to parse them to ltl::formula and it would be a waste of time to parse them to formula
over and over, and to register all their atomic_propositions in over and over, and to register all their atomic_propositions in
the bdd_dict. Keep the bdd result around so we can reuse the bdd_dict. Keep the bdd result around so we can reuse
it. */ it. */
@ -71,7 +71,7 @@
spot::location used_loc; spot::location used_loc;
}; };
spot::parsed_aut_ptr h; spot::parsed_aut_ptr h;
spot::ltl::environment* env; spot::environment* env;
formula_cache fcache; formula_cache fcache;
named_tgba_t* namer = nullptr; named_tgba_t* namer = nullptr;
spot::acc_mapper_int* acc_mapper = nullptr; spot::acc_mapper_int* acc_mapper = nullptr;
@ -1403,8 +1403,8 @@ nc-formula: nc-formula-or-ident
auto i = res.fcache.find(*$1); auto i = res.fcache.find(*$1);
if (i == res.fcache.end()) if (i == res.fcache.end())
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
auto f = spot::ltl::parse_infix_boolean(*$1, pel, *res.env, auto f = spot::parse_infix_boolean(*$1, pel, *res.env,
debug_level(), true); debug_level(), true);
for (auto& j: pel) for (auto& j: pel)
{ {
@ -1578,8 +1578,8 @@ lbtt-acc: { $$ = 0U; }
} }
lbtt-guard: STRING lbtt-guard: STRING
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
auto f = spot::ltl::parse_prefix_ltl(*$1, pel, *res.env); auto f = spot::parse_prefix_ltl(*$1, pel, *res.env);
if (!f || !pel.empty()) if (!f || !pel.empty())
{ {
std::string s = "failed to parse guard: "; std::string s = "failed to parse guard: ";
@ -1884,7 +1884,7 @@ namespace spot
parsed_aut_ptr parsed_aut_ptr
automaton_stream_parser::parse(parse_aut_error_list& error_list, automaton_stream_parser::parse(parse_aut_error_list& error_list,
const bdd_dict_ptr& dict, const bdd_dict_ptr& dict,
ltl::environment& env, environment& env,
bool debug) bool debug)
{ {
restart: restart:
@ -1927,7 +1927,7 @@ namespace spot
twa_graph_ptr twa_graph_ptr
automaton_stream_parser::parse_strict(const bdd_dict_ptr& dict, automaton_stream_parser::parse_strict(const bdd_dict_ptr& dict,
ltl::environment& env, environment& env,
bool debug) bool debug)
{ {
parse_aut_error_list pel; parse_aut_error_list pel;

View file

@ -79,13 +79,13 @@ namespace spot
~automaton_stream_parser(); ~automaton_stream_parser();
parsed_aut_ptr parse(parse_aut_error_list& error_list, parsed_aut_ptr parse(parse_aut_error_list& error_list,
const bdd_dict_ptr& dict, const bdd_dict_ptr& dict,
ltl::environment& env = environment& env =
ltl::default_environment::instance(), default_environment::instance(),
bool debug = false); bool debug = false);
// Raises a parse_error on any syntax error // Raises a parse_error on any syntax error
twa_graph_ptr parse_strict(const bdd_dict_ptr& dict, twa_graph_ptr parse_strict(const bdd_dict_ptr& dict,
ltl::environment& env = environment& env =
ltl::default_environment::instance(), default_environment::instance(),
bool debug = false); bool debug = false);
}; };
@ -120,7 +120,7 @@ namespace spot
parse_aut(const std::string& filename, parse_aut(const std::string& filename,
parse_aut_error_list& error_list, parse_aut_error_list& error_list,
const bdd_dict_ptr& dict, const bdd_dict_ptr& dict,
ltl::environment& env = ltl::default_environment::instance(), environment& env = default_environment::instance(),
bool debug = false) bool debug = false)
{ {
try try
@ -138,7 +138,7 @@ namespace spot
/// \brief Format diagnostics produced by spot::parse_aut. /// \brief Format diagnostics produced by spot::parse_aut.
/// \param os Where diagnostics should be output. /// \param os Where diagnostics should be output.
/// \param filename The filename that should appear in the diagnostics. /// \param filename The filename that should appear in the diagnostics.
/// \param error_list The error list filled by spot::ltl::parse while /// \param error_list The error list filled by spot::parse while
/// parsing \a ltl_string. /// parsing \a ltl_string.
/// \return \c true iff any diagnostic was output. /// \return \c true iff any diagnostic was output.
SPOT_API bool SPOT_API bool

View file

@ -60,13 +60,13 @@ main(int argc, char** argv)
if (s.empty() || s[0] == '#') // Skip comments if (s.empty() || s[0] == '#') // Skip comments
continue; continue;
spot::ltl::parse_error_list pe; spot::parse_error_list pe;
auto fpos = spot::ltl::parse_infix_psl(s, pe); auto fpos = spot::parse_infix_psl(s, pe);
if (spot::ltl::format_parse_errors(std::cerr, s, pe)) if (spot::format_parse_errors(std::cerr, s, pe))
return 2; return 2;
auto fneg = spot::ltl::formula::Not(fpos); auto fneg = spot::formula::Not(fpos);
{ {
auto apos = scc_filter(ltl_to_tgba_fm(fpos, d)); auto apos = scc_filter(ltl_to_tgba_fm(fpos, d));
@ -104,6 +104,6 @@ main(int argc, char** argv)
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -83,10 +83,10 @@ main(int argc, char** argv)
if (s.empty() || s[0] == '#') // Skip comments if (s.empty() || s[0] == '#') // Skip comments
continue; continue;
spot::ltl::parse_error_list pe; spot::parse_error_list pe;
auto f = spot::ltl::parse_infix_psl(s, pe); auto f = spot::parse_infix_psl(s, pe);
if (spot::ltl::format_parse_errors(std::cerr, s, pe)) if (spot::format_parse_errors(std::cerr, s, pe))
return 2; return 2;
@ -220,6 +220,6 @@ main(int argc, char** argv)
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -119,7 +119,7 @@ int main(int argc, char* argv[])
auto dict = spot::make_bdd_dict(); auto dict = spot::make_bdd_dict();
if (print_automaton || print_safra) if (print_automaton || print_safra)
{ {
spot::ltl::environment& env(spot::ltl::default_environment::instance()); spot::environment& env(spot::default_environment::instance());
spot::parse_aut_error_list pel; spot::parse_aut_error_list pel;
auto h = spot::parse_aut(file, pel, dict, env); auto h = spot::parse_aut(file, pel, dict, env);
if (spot::format_parse_aut_errors(std::cerr, file, pel)) if (spot::format_parse_aut_errors(std::cerr, file, pel))
@ -147,10 +147,10 @@ int main(int argc, char* argv[])
} }
else if (print_formula) else if (print_formula)
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_psl(file, p1); auto f1 = spot::parse_infix_psl(file, p1);
if (spot::ltl::format_parse_errors(std::cerr, file, p1)) if (spot::format_parse_errors(std::cerr, file, p1))
return 2; return 2;
auto a = spot::ltl_to_tgba_fm(f1, dict); auto a = spot::ltl_to_tgba_fm(f1, dict);
@ -162,14 +162,14 @@ int main(int argc, char* argv[])
else if (stats) else if (stats)
{ {
spot::twa_graph_ptr a; spot::twa_graph_ptr a;
spot::ltl::formula f1 = nullptr; spot::formula f1 = nullptr;
if (formula) if (formula)
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
f1 = spot::ltl::parse_infix_psl(file, p1); f1 = spot::parse_infix_psl(file, p1);
if (spot::ltl::format_parse_errors(std::cerr, file, p1)) if (spot::format_parse_errors(std::cerr, file, p1))
return 2; return 2;
a = spot::ltl_to_tgba_fm(f1, dict); a = spot::ltl_to_tgba_fm(f1, dict);
@ -177,7 +177,7 @@ int main(int argc, char* argv[])
else else
{ {
spot::parse_aut_error_list pel; spot::parse_aut_error_list pel;
spot::ltl::environment& env(spot::ltl::default_environment::instance()); spot::environment& env(spot::default_environment::instance());
auto h = spot::parse_aut(file, pel, dict, env); auto h = spot::parse_aut(file, pel, dict, env);
if (spot::format_parse_aut_errors(std::cerr, file, pel)) if (spot::format_parse_aut_errors(std::cerr, file, pel))
return 2; return 2;
@ -209,7 +209,7 @@ int main(int argc, char* argv[])
if (formula) if (formula)
{ {
auto a2 = spot::ltl_to_tgba_fm(spot::ltl::formula::Not(f1), dict); auto a2 = spot::ltl_to_tgba_fm(spot::formula::Not(f1), dict);
spot::tgba_statistics a_size = spot::stats_reachable(a2); spot::tgba_statistics a_size = spot::stats_reachable(a2);
std::cout << "Not Formula: " std::cout << "Not Formula: "
<< a_size.states << ", " << a_size.states << ", "
@ -220,14 +220,14 @@ int main(int argc, char* argv[])
} }
else else
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_psl(file, p1); auto f1 = spot::parse_infix_psl(file, p1);
if (spot::ltl::format_parse_errors(std::cerr, file, p1)) if (spot::format_parse_errors(std::cerr, file, p1))
return 2; return 2;
auto Af = spot::ltl_to_tgba_fm(f1, dict); auto Af = spot::ltl_to_tgba_fm(f1, dict);
auto nf1 = spot::ltl::formula::Not(f1); auto nf1 = spot::formula::Not(f1);
auto Anf = spot::ltl_to_tgba_fm(nf1, dict); auto Anf = spot::ltl_to_tgba_fm(nf1, dict);
auto nAf = spot::make_safra_complement(Af); auto nAf = spot::make_safra_complement(Af);
auto nAnf = spot::make_safra_complement(Anf); auto nAnf = spot::make_safra_complement(Anf);

View file

@ -58,9 +58,9 @@ main(int argc, char **argv)
std::getline(ss, form, ','); std::getline(ss, form, ',');
ss >> expected; ss >> expected;
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_sere(form, p1); auto f1 = spot::parse_infix_sere(form, p1);
if (spot::ltl::format_parse_errors(std::cerr, form, p1)) if (spot::format_parse_errors(std::cerr, form, p1))
return 2; return 2;
bool b = f1.accepts_eword(); bool b = f1.accepts_eword();
@ -73,6 +73,6 @@ main(int argc, char **argv)
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -89,9 +89,9 @@ main(int argc, char** argv)
int runs = atoi(tokens[0].c_str()); int runs = atoi(tokens[0].c_str());
spot::ltl::parse_error_list pe; spot::parse_error_list pe;
auto f = spot::ltl::parse_infix_psl(tokens[1], pe); auto f = spot::parse_infix_psl(tokens[1], pe);
if (spot::ltl::format_parse_errors(std::cerr, tokens[1], pe)) if (spot::format_parse_errors(std::cerr, tokens[1], pe))
return 2; return 2;
auto d = spot::make_bdd_dict(); auto d = spot::make_bdd_dict();
@ -199,6 +199,6 @@ main(int argc, char** argv)
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -95,47 +95,47 @@ main(int argc, char** argv)
return 2; return 2;
} }
spot::ltl::parse_error_list p2; spot::parse_error_list p2;
auto f2 = spot::ltl::parse_infix_psl(formulas[size - 1], p2); auto f2 = spot::parse_infix_psl(formulas[size - 1], p2);
if (spot::ltl::format_parse_errors(std::cerr, formulas[size - 1], p2)) if (spot::format_parse_errors(std::cerr, formulas[size - 1], p2))
return 2; return 2;
for (unsigned n = 0; n < size - 1; ++n) for (unsigned n = 0; n < size - 1; ++n)
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_psl(formulas[n], p1); auto f1 = spot::parse_infix_psl(formulas[n], p1);
if (check_first && if (check_first &&
spot::ltl::format_parse_errors(std::cerr, formulas[n], p1)) spot::format_parse_errors(std::cerr, formulas[n], p1))
return 2; return 2;
int exit_code = 0; int exit_code = 0;
{ {
#if defined UNABBREV || defined NENOFORM #if defined UNABBREV || defined NENOFORM
spot::ltl::formula tmp; spot::formula tmp;
#endif #endif
#ifdef UNABBREV #ifdef UNABBREV
tmp = f1; tmp = f1;
f1 = spot::ltl::unabbreviate(f1, UNABBREV); f1 = spot::unabbreviate(f1, UNABBREV);
f1.dump(std::cout) << std::endl; f1.dump(std::cout) << std::endl;
#endif #endif
#ifdef NENOFORM #ifdef NENOFORM
tmp = f1; tmp = f1;
f1 = spot::ltl::negative_normal_form(f1); f1 = spot::negative_normal_form(f1);
f1.dump(std::cout) << std::endl; f1.dump(std::cout) << std::endl;
#endif #endif
#ifdef REDUC #ifdef REDUC
spot::ltl::ltl_simplifier_options opt(true, true, true, spot::ltl_simplifier_options opt(true, true, true,
false, false); false, false);
# ifdef EVENT_UNIV # ifdef EVENT_UNIV
opt.favor_event_univ = true; opt.favor_event_univ = true;
# endif # endif
spot::ltl::ltl_simplifier simp(opt); spot::ltl_simplifier simp(opt);
{ {
spot::ltl::formula tmp; spot::formula tmp;
tmp = f1; tmp = f1;
f1 = simp.simplify(f1); f1 = simp.simplify(f1);
@ -143,18 +143,18 @@ main(int argc, char** argv)
{ {
std::cerr std::cerr
<< "Source and simplified formulae are not equivalent!\n"; << "Source and simplified formulae are not equivalent!\n";
spot::ltl::print_psl(std::cerr << "Simplified: ", f1) << '\n'; spot::print_psl(std::cerr << "Simplified: ", f1) << '\n';
exit_code = 1; exit_code = 1;
} }
} }
f1.dump(std::cout) << std::endl; f1.dump(std::cout) << std::endl;
#endif #endif
#ifdef REDUC_TAU #ifdef REDUC_TAU
spot::ltl::ltl_simplifier_options opt(false, false, false, spot::ltl_simplifier_options opt(false, false, false,
true, false); true, false);
spot::ltl::ltl_simplifier simp(opt); spot::ltl_simplifier simp(opt);
{ {
spot::ltl::formula tmp; spot::formula tmp;
tmp = f1; tmp = f1;
f1 = simp.simplify(f1); f1 = simp.simplify(f1);
@ -162,18 +162,18 @@ main(int argc, char** argv)
{ {
std::cerr std::cerr
<< "Source and simplified formulae are not equivalent!\n"; << "Source and simplified formulae are not equivalent!\n";
spot::ltl::print_psl(std::cerr << "Simplified: ", f1) << '\n'; spot::print_psl(std::cerr << "Simplified: ", f1) << '\n';
exit_code = 1; exit_code = 1;
} }
} }
f1.dump(std::cout) << std::endl; f1.dump(std::cout) << std::endl;
#endif #endif
#ifdef REDUC_TAUSTR #ifdef REDUC_TAUSTR
spot::ltl::ltl_simplifier_options opt(false, false, false, spot::ltl_simplifier_options opt(false, false, false,
true, true); true, true);
spot::ltl::ltl_simplifier simp(opt); spot::ltl_simplifier simp(opt);
{ {
spot::ltl::formula tmp; spot::formula tmp;
tmp = f1; tmp = f1;
f1 = simp.simplify(f1); f1 = simp.simplify(f1);
@ -181,7 +181,7 @@ main(int argc, char** argv)
{ {
std::cerr std::cerr
<< "Source and simplified formulae are not equivalent!\n"; << "Source and simplified formulae are not equivalent!\n";
spot::ltl::print_psl(std::cerr << "Simplified: ", f1) << '\n'; spot::print_psl(std::cerr << "Simplified: ", f1) << '\n';
exit_code = 1; exit_code = 1;
} }
} }
@ -191,7 +191,7 @@ main(int argc, char** argv)
exit_code |= f1 != f2; exit_code |= f1 != f2;
#if (!defined(REDUC) && !defined(REDUC_TAU) && !defined(REDUC_TAUSTR)) #if (!defined(REDUC) && !defined(REDUC_TAU) && !defined(REDUC_TAUSTR))
spot::ltl::ltl_simplifier simp; spot::ltl_simplifier simp;
#endif #endif
if (!simp.are_equivalent(f1, f2)) if (!simp.are_equivalent(f1, f2))
@ -215,6 +215,6 @@ main(int argc, char** argv)
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -342,7 +342,7 @@ checked_main(int argc, char** argv)
bool nra2nba = false; bool nra2nba = false;
bool scc_filter = false; bool scc_filter = false;
bool simpltl = false; bool simpltl = false;
spot::ltl::ltl_simplifier_options redopt(false, false, false, false, spot::ltl_simplifier_options redopt(false, false, false, false,
false, false, false); false, false, false);
bool simpcache_stats = false; bool simpcache_stats = false;
bool scc_filter_all = false; bool scc_filter_all = false;
@ -363,8 +363,8 @@ checked_main(int argc, char** argv)
bool opt_stutterize = false; bool opt_stutterize = false;
const char* opt_never = nullptr; const char* opt_never = nullptr;
const char* hoa_opt = nullptr; const char* hoa_opt = nullptr;
auto& env = spot::ltl::default_environment::instance(); auto& env = spot::default_environment::instance();
spot::ltl::atomic_prop_set* unobservables = nullptr; spot::atomic_prop_set* unobservables = nullptr;
spot::twa_ptr system_aut = nullptr; spot::twa_ptr system_aut = nullptr;
auto dict = spot::make_bdd_dict(); auto dict = spot::make_bdd_dict();
spot::timer_map tm; spot::timer_map tm;
@ -790,7 +790,7 @@ checked_main(int argc, char** argv)
} }
else if (!strncmp(argv[formula_index], "-U", 2)) else if (!strncmp(argv[formula_index], "-U", 2))
{ {
unobservables = new spot::ltl::atomic_prop_set; unobservables = new spot::atomic_prop_set;
translation = TransFM; translation = TransFM;
// Parse -U's argument. // Parse -U's argument.
const char* tok = strtok(argv[formula_index] + 2, ", \t;"); const char* tok = strtok(argv[formula_index] + 2, ", \t;");
@ -923,7 +923,7 @@ checked_main(int argc, char** argv)
input = argv[formula_index]; input = argv[formula_index];
} }
spot::ltl::formula f = nullptr; spot::formula f = nullptr;
if (!from_file) // Reading a formula, not reading an automaton from a file. if (!from_file) // Reading a formula, not reading an automaton from a file.
{ {
switch (translation) switch (translation)
@ -932,11 +932,11 @@ checked_main(int argc, char** argv)
case TransTAA: case TransTAA:
case TransCompo: case TransCompo:
{ {
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
tm.start("parsing formula"); tm.start("parsing formula");
f = spot::ltl::parse_infix_psl(input, pel, env, debug_opt); f = spot::parse_infix_psl(input, pel, env, debug_opt);
tm.stop("parsing formula"); tm.stop("parsing formula");
exit_code = spot::ltl::format_parse_errors(std::cerr, input, pel); exit_code = spot::format_parse_errors(std::cerr, input, pel);
} }
break; break;
} }
@ -964,14 +964,14 @@ checked_main(int argc, char** argv)
} }
else else
{ {
spot::ltl::ltl_simplifier* simp = nullptr; spot::ltl_simplifier* simp = nullptr;
if (simpltl) if (simpltl)
simp = new spot::ltl::ltl_simplifier(redopt, dict); simp = new spot::ltl_simplifier(redopt, dict);
if (simp) if (simp)
{ {
tm.start("reducing formula"); tm.start("reducing formula");
spot::ltl::formula t = simp->simplify(f); spot::formula t = simp->simplify(f);
tm.stop("reducing formula"); tm.stop("reducing formula");
f = t; f = t;
if (display_reduced_form) if (display_reduced_form)
@ -1659,6 +1659,6 @@ int
main(int argc, char** argv) main(int argc, char** argv)
{ {
int exit_code = checked_main(argc, argv); int exit_code = checked_main(argc, argv);
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return exit_code; return exit_code;
} }

View file

@ -58,13 +58,13 @@ main(int argc, char **argv)
std::getline(ss, form, ','); std::getline(ss, form, ',');
std::getline(ss, expected); std::getline(ss, expected);
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_psl(form, p1); auto f1 = spot::parse_infix_psl(form, p1);
if (spot::ltl::format_parse_errors(std::cerr, form, p1)) if (spot::format_parse_errors(std::cerr, form, p1))
return 2; return 2;
std::ostringstream so; std::ostringstream so;
spot::ltl::print_formula_props(so, f1, true); spot::print_formula_props(so, f1, true);
auto sost = so.str(); auto sost = so.str();
std::cout << form << ',' << sost << '\n'; std::cout << form << ',' << sost << '\n';
if (sost != expected) if (sost != expected)
@ -74,6 +74,6 @@ main(int argc, char **argv)
return 2; return 2;
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -45,18 +45,18 @@ main(int argc, char **argv)
} }
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_psl(argv[1], p1); auto f1 = spot::parse_infix_psl(argv[1], p1);
if (spot::ltl::format_parse_errors(std::cerr, argv[1], p1)) if (spot::format_parse_errors(std::cerr, argv[1], p1))
return 2; return 2;
if (boolone) if (boolone)
std::cout << spot::ltl::length_boolone(f1) << std::endl; std::cout << spot::length_boolone(f1) << std::endl;
else else
std::cout << spot::ltl::length(f1) << std::endl; std::cout << spot::length(f1) << std::endl;
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -44,18 +44,18 @@ main(int argc, char** argv)
syntax(argv[0]); syntax(argv[0]);
{ {
spot::ltl::environment& env(spot::ltl::default_environment::instance()); spot::environment& env(spot::default_environment::instance());
spot::ltl::parse_error_list pel1; spot::parse_error_list pel1;
auto f1 = spot::ltl::parse_infix_psl(argv[1], pel1, env); auto f1 = spot::parse_infix_psl(argv[1], pel1, env);
if (spot::ltl::format_parse_errors(std::cerr, argv[1], pel1)) if (spot::format_parse_errors(std::cerr, argv[1], pel1))
return 2; return 2;
spot::ltl::parse_error_list pel2; spot::parse_error_list pel2;
auto f2 = spot::ltl::parse_infix_psl(argv[2], pel2, env); auto f2 = spot::parse_infix_psl(argv[2], pel2, env);
if (spot::ltl::format_parse_errors(std::cerr, argv[2], pel2)) if (spot::format_parse_errors(std::cerr, argv[2], pel2))
return 2; return 2;
auto dict = spot::make_bdd_dict(); auto dict = spot::make_bdd_dict();
@ -65,6 +65,6 @@ main(int argc, char** argv)
spot::print_dot(std::cout, product(a1, a2)); spot::print_dot(std::cout, product(a1, a2));
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return exit_code; return exit_code;
} }

View file

@ -38,29 +38,29 @@ main(int argc, char **argv)
syntax(argv[0]); syntax(argv[0]);
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_psl(argv[1], p1); auto f1 = spot::parse_infix_psl(argv[1], p1);
if (spot::ltl::format_parse_errors(std::cerr, argv[1], p1)) if (spot::format_parse_errors(std::cerr, argv[1], p1))
return 2; return 2;
spot::ltl::relabeling_map* m = new spot::ltl::relabeling_map; spot::relabeling_map* m = new spot::relabeling_map;
auto f2 = spot::ltl::relabel_bse(f1, spot::ltl::Pnn, m); auto f2 = spot::relabel_bse(f1, spot::Pnn, m);
spot::ltl::print_psl(std::cout, f2) << '\n'; spot::print_psl(std::cout, f2) << '\n';
typedef std::map<std::string, std::string> map_t; typedef std::map<std::string, std::string> map_t;
map_t sorted_map; map_t sorted_map;
for (spot::ltl::relabeling_map::const_iterator i = m->begin(); for (spot::relabeling_map::const_iterator i = m->begin();
i != m->end(); ++i) i != m->end(); ++i)
sorted_map[spot::ltl::str_psl(i->first)] = sorted_map[spot::str_psl(i->first)] =
spot::ltl::str_psl(i->second); spot::str_psl(i->second);
for (map_t::const_iterator i = sorted_map.begin(); for (map_t::const_iterator i = sorted_map.begin();
i != sorted_map.end(); ++i) i != sorted_map.end(); ++i)
std::cout << " " << i->first << " -> " std::cout << " " << i->first << " -> "
<< i->second << '\n'; << i->second << '\n';
delete m; delete m;
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -22,7 +22,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# Check that spot::ltl::parse succeed on valid input, and that # Check that spot::parse succeed on valid input, and that
# dump and dotty will work with the resulting trees. Note that # dump and dotty will work with the resulting trees. Note that
# this doesn't check that the tree is correct w.r.t. the formula. # this doesn't check that the tree is correct w.r.t. the formula.

View file

@ -42,6 +42,6 @@ int main(int argc, char** argv)
kripke_save_reachable(std::cout, k); kripke_save_reachable(std::cout, k);
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return return_value; return return_value;
} }

View file

@ -486,9 +486,9 @@ print_ar_stats(ar_stats_type& ar_stats, const std::string& s)
std::cout << std::setiosflags(old); std::cout << std::setiosflags(old);
} }
spot::ltl::formula spot::formula
generate_formula(const spot::ltl::random_ltl& rl, generate_formula(const spot::random_ltl& rl,
spot::ltl::ltl_simplifier& simp, spot::ltl_simplifier& simp,
int opt_f, int opt_s, int opt_f, int opt_s,
int opt_l = 0, bool opt_u = false) int opt_l = 0, bool opt_u = false)
{ {
@ -498,7 +498,7 @@ generate_formula(const spot::ltl::random_ltl& rl,
while (max_tries_u--) while (max_tries_u--)
{ {
spot::srand(opt_s++); spot::srand(opt_s++);
spot::ltl::formula f; spot::formula f;
int max_tries_l = 1000; int max_tries_l = 1000;
while (max_tries_l--) while (max_tries_l--)
{ {
@ -506,12 +506,12 @@ generate_formula(const spot::ltl::random_ltl& rl,
if (opt_l) if (opt_l)
{ {
f = simp.simplify(f); f = simp.simplify(f);
if (spot::ltl::length(f) < opt_l) if (spot::length(f) < opt_l)
continue; continue;
} }
else else
{ {
assert(spot::ltl::length(f) <= opt_f); assert(spot::length(f) <= opt_f);
} }
break; break;
} }
@ -522,7 +522,7 @@ generate_formula(const spot::ltl::random_ltl& rl,
<< "of size " << opt_l << " or more." << std::endl; << "of size " << opt_l << " or more." << std::endl;
return nullptr; return nullptr;
} }
std::string txt = spot::ltl::str_psl(f); std::string txt = spot::str_psl(f);
if (!opt_u || unique.insert(txt).second) if (!opt_u || unique.insert(txt).second)
return f; return f;
} }
@ -576,12 +576,12 @@ main(int argc, char** argv)
spot::option_map options; spot::option_map options;
auto& env = spot::ltl::default_environment::instance(); auto& env = spot::default_environment::instance();
spot::ltl::atomic_prop_set* ap = new spot::ltl::atomic_prop_set; spot::atomic_prop_set* ap = new spot::atomic_prop_set;
auto dict = spot::make_bdd_dict(); auto dict = spot::make_bdd_dict();
spot::ltl::ltl_simplifier_options simpopt(true, true, true, true, true); spot::ltl_simplifier_options simpopt(true, true, true, true, true);
spot::ltl::ltl_simplifier simp(simpopt); spot::ltl_simplifier simp(simpopt);
if (argc <= 1) if (argc <= 1)
syntax(argv[0]); syntax(argv[0]);
@ -788,7 +788,7 @@ main(int argc, char** argv)
} }
} }
spot::ltl::random_ltl rl(ap); spot::random_ltl rl(ap);
const char* tok = rl.parse_options(opt_p); const char* tok = rl.parse_options(opt_p);
if (tok) if (tok)
{ {
@ -824,7 +824,7 @@ main(int argc, char** argv)
spot::timer_map tm_ar; spot::timer_map tm_ar;
std::set<int> failed_seeds; std::set<int> failed_seeds;
int init_opt_ec = opt_ec; int init_opt_ec = opt_ec;
spot::ltl::atomic_prop_set* apf = new spot::ltl::atomic_prop_set; spot::atomic_prop_set* apf = new spot::atomic_prop_set;
if (opt_ec) if (opt_ec)
{ {
@ -847,7 +847,7 @@ main(int argc, char** argv)
{ {
if (opt_F) if (opt_F)
{ {
spot::ltl::formula f = spot::formula f =
generate_formula(rl, simp, opt_f, opt_ec_seed, opt_l, opt_u); generate_formula(rl, simp, opt_f, opt_ec_seed, opt_l, opt_u);
if (!f) if (!f)
exit(1); exit(1);
@ -862,15 +862,15 @@ main(int argc, char** argv)
break; break;
else if (input == "") else if (input == "")
break; break;
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
auto f = spot::ltl::parse_infix_psl(input, pel, env); auto f = spot::parse_infix_psl(input, pel, env);
if (spot::ltl::format_parse_errors(std::cerr, input, pel)) if (spot::format_parse_errors(std::cerr, input, pel))
{ {
exit_code = 1; exit_code = 1;
break; break;
} }
formula = spot::ltl_to_tgba_fm(f, dict, true); formula = spot::ltl_to_tgba_fm(f, dict, true);
auto* tmp = spot::ltl::atomic_prop_collect(f); auto* tmp = spot::atomic_prop_collect(f);
for (auto i: *tmp) for (auto i: *tmp)
apf->insert(i); apf->insert(i);
delete tmp; delete tmp;

View file

@ -54,18 +54,18 @@ main(int argc, char** argv)
} }
{ {
spot::ltl::environment& env(spot::ltl::default_environment::instance()); spot::environment& env(spot::default_environment::instance());
spot::ltl::parse_error_list pel; spot::parse_error_list pel;
auto f = spot::ltl::parse_infix_psl(argv[formula_index], pel, env, debug); auto f = spot::parse_infix_psl(argv[formula_index], pel, env, debug);
exit_code = exit_code =
spot::ltl::format_parse_errors(std::cerr, argv[formula_index], pel); spot::format_parse_errors(std::cerr, argv[formula_index], pel);
if (f) if (f)
{ {
#ifdef DOTTY #ifdef DOTTY
spot::ltl::print_dot_psl(std::cout, f); spot::print_dot_psl(std::cout, f);
#else #else
f.dump(std::cout) << std::endl; f.dump(std::cout) << std::endl;
#endif #endif
@ -76,6 +76,6 @@ main(int argc, char** argv)
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return exit_code; return exit_code;
} }

View file

@ -45,7 +45,7 @@ main(int argc, char** argv)
bool hidereduc = false; bool hidereduc = false;
unsigned long sum_before = 0; unsigned long sum_before = 0;
unsigned long sum_after = 0; unsigned long sum_after = 0;
spot::ltl::ltl_simplifier_options o(false, false, false, false, false); spot::ltl_simplifier_options o(false, false, false, false, false);
if (argc < 3) if (argc < 3)
syntax(argv[0]); syntax(argv[0]);
@ -147,12 +147,12 @@ main(int argc, char** argv)
int exit_code = 0; int exit_code = 0;
{ {
spot::ltl::ltl_simplifier* simp = new spot::ltl::ltl_simplifier(o); spot::ltl_simplifier* simp = new spot::ltl_simplifier(o);
o.reduce_size_strictly = true; o.reduce_size_strictly = true;
spot::ltl::ltl_simplifier* simp_size = new spot::ltl::ltl_simplifier(o); spot::ltl_simplifier* simp_size = new spot::ltl_simplifier(o);
spot::ltl::formula f1 = nullptr; spot::formula f1 = nullptr;
spot::ltl::formula f2 = nullptr; spot::formula f2 = nullptr;
std::ifstream* fin = nullptr; std::ifstream* fin = nullptr;
@ -178,16 +178,16 @@ main(int argc, char** argv)
} }
while (input == ""); while (input == "");
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
f1 = spot::ltl::parse_infix_psl(input, p1); f1 = spot::parse_infix_psl(input, p1);
if (spot::ltl::format_parse_errors(std::cerr, input, p1)) if (spot::format_parse_errors(std::cerr, input, p1))
return 2; return 2;
} }
else else
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
f1 = spot::ltl::parse_infix_psl(argv[2], p1); f1 = spot::parse_infix_psl(argv[2], p1);
if (spot::ltl::format_parse_errors(std::cerr, argv[2], p1)) if (spot::format_parse_errors(std::cerr, argv[2], p1))
return 2; return 2;
} }
@ -199,23 +199,23 @@ main(int argc, char** argv)
exit(2); exit(2);
} }
spot::ltl::parse_error_list p2; spot::parse_error_list p2;
f2 = spot::ltl::parse_infix_psl(argv[3], p2); f2 = spot::parse_infix_psl(argv[3], p2);
if (spot::ltl::format_parse_errors(std::cerr, argv[3], p2)) if (spot::format_parse_errors(std::cerr, argv[3], p2))
return 2; return 2;
} }
{ {
spot::ltl::formula ftmp1; spot::formula ftmp1;
ftmp1 = f1; ftmp1 = f1;
f1 = simp_size->negative_normal_form(f1, false); f1 = simp_size->negative_normal_form(f1, false);
int length_f1_before = spot::ltl::length(f1); int length_f1_before = spot::length(f1);
std::string f1s_before = spot::ltl::str_psl(f1); std::string f1s_before = spot::str_psl(f1);
std::string f1l; std::string f1l;
spot::ltl::formula input_f = f1; spot::formula input_f = f1;
f1 = simp_size->simplify(input_f); f1 = simp_size->simplify(input_f);
if (!simp_size->are_equivalent(input_f, f1)) if (!simp_size->are_equivalent(input_f, f1))
{ {
@ -226,8 +226,8 @@ main(int argc, char** argv)
} }
else else
{ {
spot::ltl::formula maybe_larger = simp->simplify(input_f); spot::formula maybe_larger = simp->simplify(input_f);
f1l = spot::ltl::str_psl(maybe_larger); f1l = spot::str_psl(maybe_larger);
if (!simp->are_equivalent(input_f, maybe_larger)) if (!simp->are_equivalent(input_f, maybe_larger))
{ {
std::cerr << "Incorrect reduction (reduce_size_strictly=0) from `" std::cerr << "Incorrect reduction (reduce_size_strictly=0) from `"
@ -236,15 +236,15 @@ main(int argc, char** argv)
} }
} }
int length_f1_after = spot::ltl::length(f1); int length_f1_after = spot::length(f1);
std::string f1s_after = spot::ltl::str_psl(f1); std::string f1s_after = spot::str_psl(f1);
std::string f2s = ""; std::string f2s = "";
if (f2) if (f2)
{ {
ftmp1 = f2; ftmp1 = f2;
f2 = simp_size->negative_normal_form(f2, false); f2 = simp_size->negative_normal_form(f2, false);
f2s = spot::ltl::str_psl(f2); f2s = spot::str_psl(f2);
} }
sum_before += length_f1_before; sum_before += length_f1_before;
@ -308,6 +308,6 @@ main(int argc, char** argv)
} }
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return exit_code; return exit_code;
} }

View file

@ -45,25 +45,25 @@ main(int argc, char** argv)
int exit_return = 0; int exit_return = 0;
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto ftmp1 = spot::ltl::parse_infix_psl(argv[2], p1); auto ftmp1 = spot::parse_infix_psl(argv[2], p1);
if (spot::ltl::format_parse_errors(std::cerr, argv[2], p1)) if (spot::format_parse_errors(std::cerr, argv[2], p1))
return 2; return 2;
spot::ltl::parse_error_list p2; spot::parse_error_list p2;
auto ftmp2 = spot::ltl::parse_infix_psl(argv[3], p2); auto ftmp2 = spot::parse_infix_psl(argv[3], p2);
if (spot::ltl::format_parse_errors(std::cerr, argv[3], p2)) if (spot::format_parse_errors(std::cerr, argv[3], p2))
return 2; return 2;
spot::ltl::formula f1 = spot::ltl::negative_normal_form(ftmp1); spot::formula f1 = spot::negative_normal_form(ftmp1);
spot::ltl::formula f2 = spot::ltl::negative_normal_form(ftmp2); spot::formula f2 = spot::negative_normal_form(ftmp2);
std::string f1s = spot::ltl::str_psl(f1); std::string f1s = spot::str_psl(f1);
std::string f2s = spot::ltl::str_psl(f2); std::string f2s = spot::str_psl(f2);
spot::ltl::ltl_simplifier* c = new spot::ltl::ltl_simplifier; spot::ltl_simplifier* c = new spot::ltl_simplifier;
switch (opt) switch (opt)
{ {
@ -102,6 +102,6 @@ main(int argc, char** argv)
delete c; delete c;
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return exit_return; return exit_return;
} }

View file

@ -28,8 +28,8 @@ int
main() main()
{ {
{ {
spot::ltl::default_environment& e = spot::default_environment& e =
spot::ltl::default_environment::instance(); spot::default_environment::instance();
auto a = spot::make_taa_tgba_string(spot::make_bdd_dict()); auto a = spot::make_taa_tgba_string(spot::make_bdd_dict());
typedef spot::taa_tgba::transition trans; typedef spot::taa_tgba::transition trans;
@ -48,6 +48,6 @@ main()
spot::print_dot(std::cout, a); spot::print_dot(std::cout, a);
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -40,21 +40,21 @@ main(int argc, char **argv)
syntax(argv[0]); syntax(argv[0]);
{ {
spot::ltl::parse_error_list p1; spot::parse_error_list p1;
auto f1 = spot::ltl::parse_infix_psl(argv[1], p1); auto f1 = spot::parse_infix_psl(argv[1], p1);
if (spot::ltl::format_parse_errors(std::cerr, argv[1], p1)) if (spot::format_parse_errors(std::cerr, argv[1], p1))
return 2; return 2;
// The string generated from an abstract tree should be parsable // The string generated from an abstract tree should be parsable
// again. // again.
std::string f1s = spot::ltl::str_psl(f1); std::string f1s = spot::str_psl(f1);
std::cout << f1s << '\n'; std::cout << f1s << '\n';
auto f2 = spot::ltl::parse_infix_psl(f1s, p1); auto f2 = spot::parse_infix_psl(f1s, p1);
if (spot::ltl::format_parse_errors(std::cerr, f1s, p1)) if (spot::format_parse_errors(std::cerr, f1s, p1))
return 2; return 2;
// This second abstract tree should be equal to the first. // This second abstract tree should be equal to the first.
@ -64,13 +64,13 @@ main(int argc, char **argv)
// It should also map to the same string. // It should also map to the same string.
std::string f2s = spot::ltl::str_psl(f2); std::string f2s = spot::str_psl(f2);
std::cout << f2s << '\n'; std::cout << f2s << '\n';
if (f2s != f1s) if (f2s != f1s)
return 1; return 1;
} }
assert(spot::ltl::fnode::instances_check()); assert(spot::fnode::instances_check());
return 0; return 0;
} }

View file

@ -22,7 +22,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# Check for spot::ltl::tostring. # Check for spot::tostring.
. ./defs || exit 1 . ./defs || exit 1

View file

@ -26,43 +26,40 @@
namespace spot namespace spot
{ {
namespace ltl atomic_prop_set create_atomic_prop_set(unsigned n)
{ {
atomic_prop_set create_atomic_prop_set(unsigned n) atomic_prop_set res;
{ for (unsigned i = 0; i < n; ++i)
atomic_prop_set res; {
for (unsigned i = 0; i < n; ++i) std::ostringstream p;
{ p << 'p' << i;
std::ostringstream p; res.insert(formula::ap(p.str()));
p << 'p' << i; }
res.insert(formula::ap(p.str())); return res;
} }
return res;
}
atomic_prop_set* atomic_prop_set*
atomic_prop_collect(formula f, atomic_prop_set* s) atomic_prop_collect(formula f, atomic_prop_set* s)
{ {
if (!s) if (!s)
s = new atomic_prop_set; s = new atomic_prop_set;
f.traverse([&](const formula& f) f.traverse([&](const formula& f)
{ {
if (f.is(op::ap)) if (f.is(op::ap))
s->insert(f); s->insert(f);
return false; return false;
}); });
return s; return s;
} }
bdd bdd
atomic_prop_collect_as_bdd(formula f, const twa_ptr& a) atomic_prop_collect_as_bdd(formula f, const twa_ptr& a)
{ {
spot::ltl::atomic_prop_set aps; spot::atomic_prop_set aps;
atomic_prop_collect(f, &aps); atomic_prop_collect(f, &aps);
bdd res = bddtrue; bdd res = bddtrue;
for (auto f: aps) for (auto f: aps)
res &= bdd_ithvar(a->register_ap(f)); res &= bdd_ithvar(a->register_ap(f));
return res; return res;
}
} }
} }

View file

@ -29,38 +29,35 @@
namespace spot namespace spot
{ {
namespace ltl /// \addtogroup ltl_misc
{ /// @{
/// \addtogroup ltl_misc
/// @{
/// Set of atomic propositions. /// Set of atomic propositions.
typedef std::set<formula> atomic_prop_set; typedef std::set<formula> atomic_prop_set;
/// \brief construct an atomic_prop_set with n propositions /// \brief construct an atomic_prop_set with n propositions
SPOT_API SPOT_API
atomic_prop_set create_atomic_prop_set(unsigned n); atomic_prop_set create_atomic_prop_set(unsigned n);
/// \brief Return the set of atomic propositions occurring in a formula. /// \brief Return the set of atomic propositions occurring in a formula.
/// ///
/// \param f the formula to inspect /// \param f the formula to inspect
/// \param s an existing set to fill with atomic_propositions discovered, /// \param s an existing set to fill with atomic_propositions discovered,
/// or 0 if the set should be allocated by the function. /// or 0 if the set should be allocated by the function.
/// \return A pointer to the supplied set, \c s, augmented with /// \return A pointer to the supplied set, \c s, augmented with
/// atomic propositions occurring in \c f; or a newly allocated /// atomic propositions occurring in \c f; or a newly allocated
/// set containing all these atomic propositions if \c s is 0. /// set containing all these atomic propositions if \c s is 0.
SPOT_API atomic_prop_set* SPOT_API atomic_prop_set*
atomic_prop_collect(formula f, atomic_prop_set* s = nullptr); atomic_prop_collect(formula f, atomic_prop_set* s = nullptr);
/// \brief Return the set of atomic propositions occurring in a /// \brief Return the set of atomic propositions occurring in a
/// formula, as a BDD. /// formula, as a BDD.
/// ///
/// \param f the formula to inspect /// \param f the formula to inspect
/// \param a that automaton that should register the BDD variables used. /// \param a that automaton that should register the BDD variables used.
/// \return A conjunction the atomic propositions. /// \return A conjunction the atomic propositions.
SPOT_API bdd SPOT_API bdd
atomic_prop_collect_as_bdd(formula f, const twa_ptr& a); atomic_prop_collect_as_bdd(formula f, const twa_ptr& a);
/// @} /// @}
}
} }

View file

@ -27,114 +27,110 @@
namespace spot namespace spot
{ {
namespace ltl language_containment_checker::language_containment_checker
{ (const bdd_dict_ptr& dict, bool exprop, bool symb_merge,
bool branching_postponement, bool fair_loop_approx)
language_containment_checker::language_containment_checker : dict_(dict), exprop_(exprop), symb_merge_(symb_merge),
(const bdd_dict_ptr& dict, bool exprop, bool symb_merge,
bool branching_postponement, bool fair_loop_approx)
: dict_(dict), exprop_(exprop), symb_merge_(symb_merge),
branching_postponement_(branching_postponement), branching_postponement_(branching_postponement),
fair_loop_approx_(fair_loop_approx) fair_loop_approx_(fair_loop_approx)
{ {
} }
language_containment_checker::~language_containment_checker() language_containment_checker::~language_containment_checker()
{ {
clear(); clear();
} }
void void
language_containment_checker::clear() language_containment_checker::clear()
{ {
translated_.clear(); translated_.clear();
} }
bool bool
language_containment_checker::incompatible_(record_* l, record_* g) language_containment_checker::incompatible_(record_* l, record_* g)
{ {
record_::incomp_map::const_iterator i = l->incompatible.find(g); record_::incomp_map::const_iterator i = l->incompatible.find(g);
if (i != l->incompatible.end()) if (i != l->incompatible.end())
return i->second; return i->second;
bool res = product(l->translation, g->translation)->is_empty(); bool res = product(l->translation, g->translation)->is_empty();
l->incompatible[g] = res; l->incompatible[g] = res;
g->incompatible[l] = res; g->incompatible[l] = res;
return res; return res;
} }
// Check whether L(l) is a subset of L(g). // Check whether L(l) is a subset of L(g).
bool bool
language_containment_checker::contained(formula l, language_containment_checker::contained(formula l,
formula g) formula g)
{ {
if (l == g) if (l == g)
return true; return true;
record_* rl = register_formula_(l); record_* rl = register_formula_(l);
record_* rng = register_formula_(formula::Not(g)); record_* rng = register_formula_(formula::Not(g));
return incompatible_(rl, rng); return incompatible_(rl, rng);
} }
// Check whether L(!l) is a subset of L(g). // Check whether L(!l) is a subset of L(g).
bool bool
language_containment_checker::neg_contained(formula l, language_containment_checker::neg_contained(formula l,
formula g) formula g)
{ {
if (l == g) if (l == g)
return false; return false;
formula nl = formula::Not(l); formula nl = formula::Not(l);
record_* rnl = register_formula_(nl); record_* rnl = register_formula_(nl);
record_* rng = register_formula_(formula::Not(g)); record_* rng = register_formula_(formula::Not(g));
if (nl == g) if (nl == g)
return true; return true;
return incompatible_(rnl, rng); return incompatible_(rnl, rng);
} }
// Check whether L(l) is a subset of L(!g). // Check whether L(l) is a subset of L(!g).
bool bool
language_containment_checker::contained_neg(formula l, language_containment_checker::contained_neg(formula l,
formula g) formula g)
{ {
if (l == g) if (l == g)
return false; return false;
record_* rl = register_formula_(l); record_* rl = register_formula_(l);
record_* rg = register_formula_(g); record_* rg = register_formula_(g);
return incompatible_(rl, rg); return incompatible_(rl, rg);
} }
// Check whether L(l) = L(g). // Check whether L(l) = L(g).
bool bool
language_containment_checker::equal(formula l, formula g) language_containment_checker::equal(formula l, formula g)
{ {
return contained(l, g) && contained(g, l); return contained(l, g) && contained(g, l);
} }
language_containment_checker::record_* language_containment_checker::record_*
language_containment_checker::register_formula_(formula f) language_containment_checker::register_formula_(formula f)
{ {
trans_map::iterator i = translated_.find(f); trans_map::iterator i = translated_.find(f);
if (i != translated_.end()) if (i != translated_.end())
return &i->second; return &i->second;
auto e = ltl_to_tgba_fm(f, dict_, exprop_, symb_merge_, auto e = ltl_to_tgba_fm(f, dict_, exprop_, symb_merge_,
branching_postponement_, fair_loop_approx_); branching_postponement_, fair_loop_approx_);
record_& r = translated_[f]; record_& r = translated_[f];
r.translation = e; r.translation = e;
return &r; return &r;
} }
formula formula
reduce_tau03(formula f, bool stronger) reduce_tau03(formula f, bool stronger)
{ {
if (!f.is_psl_formula()) if (!f.is_psl_formula())
return f; return f;
ltl_simplifier_options opt(false, false, false, ltl_simplifier_options opt(false, false, false,
true, stronger); true, stronger);
ltl_simplifier simpl(opt); ltl_simplifier simpl(opt);
return simpl.simplify(f); return simpl.simplify(f);
}
} }
} }

View file

@ -29,54 +29,51 @@
namespace spot namespace spot
{ {
namespace ltl /// Check containment between LTL formulae.
class SPOT_API language_containment_checker
{ {
/// Check containment between LTL formulae. struct record_
class SPOT_API language_containment_checker
{ {
struct record_ const_twa_graph_ptr translation;
{ typedef std::map<const record_*, bool> incomp_map;
const_twa_graph_ptr translation; incomp_map incompatible;
typedef std::map<const record_*, bool> incomp_map;
incomp_map incompatible;
};
typedef std::unordered_map<formula, record_> trans_map;
public:
/// This class uses spot::ltl_to_tgba_fm to translate LTL
/// formulae. See that function for the meaning of these options.
language_containment_checker(const bdd_dict_ptr& dict, bool exprop,
bool symb_merge,
bool branching_postponement,
bool fair_loop_approx);
~language_containment_checker();
/// Clear the cache.
void clear();
/// Check whether L(l) is a subset of L(g).
bool contained(formula l, formula g);
/// Check whether L(!l) is a subset of L(g).
bool neg_contained(formula l, formula g);
/// Check whether L(l) is a subset of L(!g).
bool contained_neg(formula l, formula g);
/// Check whether L(l) = L(g).
bool equal(formula l, formula g);
protected:
bool incompatible_(record_* l, record_* g);
record_* register_formula_(formula f);
/* Translation options */
bdd_dict_ptr dict_;
bool exprop_;
bool symb_merge_;
bool branching_postponement_;
bool fair_loop_approx_;
/* Translation Maps */
trans_map translated_;
}; };
} typedef std::unordered_map<formula, record_> trans_map;
public:
/// This class uses spot::ltl_to_tgba_fm to translate LTL
/// formulae. See that function for the meaning of these options.
language_containment_checker(const bdd_dict_ptr& dict, bool exprop,
bool symb_merge,
bool branching_postponement,
bool fair_loop_approx);
~language_containment_checker();
/// Clear the cache.
void clear();
/// Check whether L(l) is a subset of L(g).
bool contained(formula l, formula g);
/// Check whether L(!l) is a subset of L(g).
bool neg_contained(formula l, formula g);
/// Check whether L(l) is a subset of L(!g).
bool contained_neg(formula l, formula g);
/// Check whether L(l) = L(g).
bool equal(formula l, formula g);
protected:
bool incompatible_(record_* l, record_* g);
record_* register_formula_(formula f);
/* Translation options */
bdd_dict_ptr dict_;
bool exprop_;
bool symb_merge_;
bool branching_postponement_;
bool fair_loop_approx_;
/* Translation Maps */
trans_map translated_;
};
} }

View file

@ -24,42 +24,38 @@
namespace spot namespace spot
{ {
namespace ltl declarative_environment::declarative_environment()
{ {
}
declarative_environment::declarative_environment() bool
{ declarative_environment::declare(const std::string& prop_str)
} {
if (props_.find(prop_str) != props_.end())
return false;
props_[prop_str] = formula::ap(prop_str);
return true;
}
bool formula
declarative_environment::declare(const std::string& prop_str) declarative_environment::require(const std::string& prop_str)
{ {
if (props_.find(prop_str) != props_.end()) prop_map::iterator i = props_.find(prop_str);
return false; if (i == props_.end())
props_[prop_str] = formula::ap(prop_str); return nullptr;
return true; return i->second;
} }
formula const std::string&
declarative_environment::require(const std::string& prop_str) declarative_environment::name() const
{ {
prop_map::iterator i = props_.find(prop_str); static std::string name("declarative environment");
if (i == props_.end()) return name;
return nullptr; }
return i->second;
}
const std::string& const declarative_environment::prop_map&
declarative_environment::name() const declarative_environment::get_prop_map() const
{ {
static std::string name("declarative environment"); return props_;
return name;
}
const declarative_environment::prop_map&
declarative_environment::get_prop_map() const
{
return props_;
}
} }
} }

View file

@ -29,36 +29,32 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_environment
/// \brief A declarative environment.
///
/// This environment recognizes all atomic propositions
/// that have been previously declared. It will reject other.
class SPOT_API declarative_environment : public environment
{ {
public:
declarative_environment();
~declarative_environment() = default;
/// \ingroup ltl_environment /// Declare an atomic proposition. Return false iff the
/// \brief A declarative environment. /// proposition was already declared.
/// bool declare(const std::string& prop_str);
/// This environment recognizes all atomic propositions
/// that have been previously declared. It will reject other.
class SPOT_API declarative_environment : public environment
{
public:
declarative_environment();
~declarative_environment() = default;
/// Declare an atomic proposition. Return false iff the virtual formula require(const std::string& prop_str);
/// proposition was already declared.
bool declare(const std::string& prop_str);
virtual formula require(const std::string& prop_str); /// Get the name of the environment.
virtual const std::string& name() const;
/// Get the name of the environment. typedef std::map<const std::string, formula> prop_map;
virtual const std::string& name() const;
typedef std::map<const std::string, formula> prop_map; /// Get the map of atomic proposition known to this environment.
const prop_map& get_prop_map() const;
/// Get the map of atomic proposition known to this environment. private:
const prop_map& get_prop_map() const; prop_map props_;
};
private:
prop_map props_;
};
}
} }

View file

@ -24,36 +24,31 @@
namespace spot namespace spot
{ {
namespace ltl default_environment::~default_environment()
{ {
}
default_environment::~default_environment() formula
{ default_environment::require(const std::string& s)
} {
return formula::ap(s);
}
formula const std::string&
default_environment::require(const std::string& s) default_environment::name() const
{ {
return formula::ap(s); static std::string name("default environment");
} return name;
}
const std::string& default_environment::default_environment()
default_environment::name() const {
{ }
static std::string name("default environment");
return name;
}
default_environment::default_environment()
{
}
default_environment&
default_environment::instance()
{
static default_environment* singleton = new default_environment();
return *singleton;
}
default_environment&
default_environment::instance()
{
static default_environment* singleton = new default_environment();
return *singleton;
} }
} }

View file

@ -27,27 +27,23 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_environment
/// \brief A laxist environment.
///
/// This environment recognizes all atomic propositions.
///
/// This is a singleton. Use default_environment::instance()
/// to obtain the instance.
class SPOT_API default_environment final: public environment
{ {
public:
virtual ~default_environment();
virtual formula require(const std::string& prop_str);
virtual const std::string& name() const;
/// \ingroup ltl_environment /// Get the sole instance of spot::default_environment.
/// \brief A laxist environment. static default_environment& instance();
/// protected:
/// This environment recognizes all atomic propositions. default_environment();
/// };
/// This is a singleton. Use default_environment::instance()
/// to obtain the instance.
class SPOT_API default_environment final: public environment
{
public:
virtual ~default_environment();
virtual formula require(const std::string& prop_str);
virtual const std::string& name() const;
/// Get the sole instance of spot::ltl::default_environment.
static default_environment& instance();
protected:
default_environment();
};
}
} }

View file

@ -28,110 +28,107 @@
namespace spot namespace spot
{ {
namespace ltl namespace
{ {
namespace struct dot_printer final
{ {
struct dot_printer final std::ostream& os_;
{ std::unordered_map<formula, int> node_;
std::ostream& os_; std::ostringstream* sinks_;
std::unordered_map<formula, int> node_;
std::ostringstream* sinks_;
dot_printer(std::ostream& os, formula f) dot_printer(std::ostream& os, formula f)
: os_(os), sinks_(new std::ostringstream) : os_(os), sinks_(new std::ostringstream)
{ {
os_ << "digraph G {\n"; os_ << "digraph G {\n";
rec(f); rec(f);
os_ << " subgraph atoms {\n rank=sink;\n" os_ << " subgraph atoms {\n rank=sink;\n"
<< sinks_->str() << " }\n}\n"; << sinks_->str() << " }\n}\n";
} }
~dot_printer() ~dot_printer()
{ {
delete sinks_; delete sinks_;
} }
int rec(formula f) int rec(formula f)
{ {
auto i = node_.emplace(f, node_.size()); auto i = node_.emplace(f, node_.size());
int src = i.first->second; int src = i.first->second;
if (!i.second) if (!i.second)
return src;
op o = f.kind();
std::string str = (o == op::ap) ? f.ap_name() : f.kindstr();
if (o == op::ap || f.is_constant())
*sinks_ << " " << src << " [label=\""
<< str << "\", shape=box];\n";
else
os_ << " " << src << " [label=\"" << str << "\"];\n";
int childnum = 0;
switch (o)
{
case op::ff:
case op::tt:
case op::eword:
case op::ap:
case op::Not:
case op::X:
case op::F:
case op::G:
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::Or:
case op::OrRat:
case op::And:
case op::AndRat:
case op::AndNLM:
case op::Star:
case op::FStar:
childnum = 0; // No number for children
break;
case op::Xor:
case op::Implies:
case op::Equiv:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
childnum = -2; // L and R markers
break;
case op::Concat:
case op::Fusion:
childnum = 1; // Numbered children
break;
}
for (auto c: f)
{
os_ << " " << src << " -> " << rec(c);
if (childnum > 0)
os_ << " [taillabel=\"" << childnum << "\"]";
if (childnum == -2)
os_ << " [taillabel=\"L\"]";
else if (childnum == -1)
os_ << " [taillabel=\"R\"]";
os_ << ";\n";
++childnum;
}
return src; return src;
}
};
}
std::ostream& op o = f.kind();
print_dot_psl(std::ostream& os, formula f) std::string str = (o == op::ap) ? f.ap_name() : f.kindstr();
{
dot_printer p(os, f); if (o == op::ap || f.is_constant())
return os; *sinks_ << " " << src << " [label=\""
} << str << "\", shape=box];\n";
else
os_ << " " << src << " [label=\"" << str << "\"];\n";
int childnum = 0;
switch (o)
{
case op::ff:
case op::tt:
case op::eword:
case op::ap:
case op::Not:
case op::X:
case op::F:
case op::G:
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::Or:
case op::OrRat:
case op::And:
case op::AndRat:
case op::AndNLM:
case op::Star:
case op::FStar:
childnum = 0; // No number for children
break;
case op::Xor:
case op::Implies:
case op::Equiv:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
childnum = -2; // L and R markers
break;
case op::Concat:
case op::Fusion:
childnum = 1; // Numbered children
break;
}
for (auto c: f)
{
os_ << " " << src << " -> " << rec(c);
if (childnum > 0)
os_ << " [taillabel=\"" << childnum << "\"]";
if (childnum == -2)
os_ << " [taillabel=\"L\"]";
else if (childnum == -1)
os_ << " [taillabel=\"R\"]";
os_ << ";\n";
++childnum;
}
return src;
}
};
}
std::ostream&
print_dot_psl(std::ostream& os, formula f)
{
dot_printer p(os, f);
return os;
} }
} }

View file

@ -26,16 +26,13 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_io
{ /// \brief Write a formula tree using dot's syntax.
/// \ingroup ltl_io /// \param os The stream where it should be output.
/// \brief Write a formula tree using dot's syntax. /// \param f The formula to translate.
/// \param os The stream where it should be output. ///
/// \param f The formula to translate. /// \c dot is part of the GraphViz package
/// /// http://www.graphviz.org/
/// \c dot is part of the GraphViz package SPOT_API
/// http://www.graphviz.org/ std::ostream& print_dot_psl(std::ostream& os, formula f);
SPOT_API
std::ostream& print_dot_psl(std::ostream& os, formula f);
}
} }

View file

@ -27,34 +27,30 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_essential
/// \brief An environment that describes atomic propositions.
class environment
{ {
/// \ingroup ltl_essential public:
/// \brief An environment that describes atomic propositions. /// \brief Obtain the formula associated to \a prop_str
class environment ///
/// Usually \a prop_str, is the name of an atomic proposition,
/// and spot::require simply returns the associated
/// spot::formula.
///
/// Note this is not a \c const method. Some environments will
/// "create" the atomic proposition when requested.
///
/// \return 0 iff \a prop_str is not part of the environment,
/// or the associated spot::formula otherwise.
virtual formula require(const std::string& prop_str) = 0;
/// Get the name of the environment.
virtual const std::string& name() const = 0;
virtual
~environment()
{ {
public: }
/// \brief Obtain the formula associated to \a prop_str };
///
/// Usually \a prop_str, is the name of an atomic proposition,
/// and spot::ltl::require simply returns the associated
/// spot::ltl::formula.
///
/// Note this is not a \c const method. Some environments will
/// "create" the atomic proposition when requested.
///
/// \return 0 iff \a prop_str is not part of the environment,
/// or the associated spot::ltl::formula otherwise.
virtual formula require(const std::string& prop_str) = 0;
/// Get the name of the environment.
virtual const std::string& name() const = 0;
virtual
~environment()
{
}
};
}
} }

View file

@ -27,10 +27,10 @@ namespace spot
{ {
namespace namespace
{ {
static const std::vector<ltl::formula> static const std::vector<formula>
split_aps(const char* arg) split_aps(const char* arg)
{ {
std::vector<ltl::formula> group; std::vector<formula> group;
auto start = arg; auto start = arg;
while (*start) while (*start)
{ {
@ -61,7 +61,7 @@ namespace spot
throw std::invalid_argument(s); throw std::invalid_argument(s);
} }
std::string ap(start, end - start); std::string ap(start, end - start);
group.emplace_back(ltl::formula::ap(ap)); group.emplace_back(formula::ap(ap));
do do
++end; ++end;
while (*end == ' ' || *end == '\t'); while (*end == ' ' || *end == '\t');
@ -86,7 +86,7 @@ namespace spot
while (rend > start && (rend[-1] == ' ' || rend[-1] == '\t')) while (rend > start && (rend[-1] == ' ' || rend[-1] == '\t'))
--rend; --rend;
std::string ap(start, rend - start); std::string ap(start, rend - start);
group.emplace_back(ltl::formula::ap(ap)); group.emplace_back(formula::ap(ap));
if (*end == ',') if (*end == ',')
start = end + 1; start = end + 1;
else else
@ -102,27 +102,27 @@ namespace spot
add_group(split_aps(ap_csv)); add_group(split_aps(ap_csv));
} }
void exclusive_ap::add_group(std::vector<ltl::formula> ap) void exclusive_ap::add_group(std::vector<formula> ap)
{ {
groups.push_back(ap); groups.push_back(ap);
} }
namespace namespace
{ {
ltl::formula formula
nand(ltl::formula lhs, ltl::formula rhs) nand(formula lhs, formula rhs)
{ {
return ltl::formula::Not(ltl::formula::And({lhs, rhs})); return formula::Not(formula::And({lhs, rhs}));
} }
} }
ltl::formula formula
exclusive_ap::constrain(ltl::formula f) const exclusive_ap::constrain(formula f) const
{ {
auto* s = atomic_prop_collect(f); auto* s = atomic_prop_collect(f);
std::vector<ltl::formula> group; std::vector<formula> group;
std::vector<ltl::formula> v; std::vector<formula> v;
for (auto& g: groups) for (auto& g: groups)
{ {
@ -139,7 +139,7 @@ namespace spot
}; };
delete s; delete s;
return ltl::formula::And({f, ltl::formula::G(ltl::formula::And(v))}); return formula::And({f, formula::G(formula::And(v))});
} }
twa_graph_ptr exclusive_ap::constrain(const_twa_graph_ptr aut, twa_graph_ptr exclusive_ap::constrain(const_twa_graph_ptr aut,

View file

@ -27,10 +27,10 @@ namespace spot
{ {
class SPOT_API exclusive_ap final class SPOT_API exclusive_ap final
{ {
std::vector<std::vector<ltl::formula>> groups; std::vector<std::vector<formula>> groups;
public: public:
#ifndef SWIG #ifndef SWIG
void add_group(std::vector<ltl::formula> ap); void add_group(std::vector<formula> ap);
#endif #endif
void add_group(const char* ap_csv); void add_group(const char* ap_csv);
@ -39,7 +39,7 @@ namespace spot
return groups.empty(); return groups.empty();
} }
ltl::formula constrain(ltl::formula f) const; formula constrain(formula f) const;
twa_graph_ptr constrain(const_twa_graph_ptr aut, twa_graph_ptr constrain(const_twa_graph_ptr aut,
bool simplify_guards = false) const; bool simplify_guards = false) const;
}; };

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -25,56 +25,53 @@
namespace spot namespace spot
{ {
namespace ltl int
length(formula f)
{ {
int int len = 0;
length(formula f) f.traverse([&len](const formula& x)
{ {
int len = 0; auto s = x.size();
f.traverse([&len](const formula& x) if (s > 1)
{ len += s - 1;
auto s = x.size(); else
if (s > 1) ++len;
len += s - 1; return false;
else });
++len; return len;
return false;
});
return len;
}
int
length_boolone(formula f)
{
int len = 0;
f.traverse([&len](const formula& x)
{
if (x.is_boolean())
{
++len;
return true;
}
auto s = x.size();
if (s > 2)
{
int b = 0;
for (const auto& y: x)
if (y.is_boolean())
++b;
len += s - b * 2 + 1;
}
else if (s > 1)
{
len += s - 1;
}
else
{
++len;
}
return false;
});
return len;
}
} }
int
length_boolone(formula f)
{
int len = 0;
f.traverse([&len](const formula& x)
{
if (x.is_boolean())
{
++len;
return true;
}
auto s = x.size();
if (s > 2)
{
int b = 0;
for (const auto& y: x)
if (y.is_boolean())
++b;
len += s - b * 2 + 1;
}
else if (s > 1)
{
len += s - 1;
}
else
{
++len;
}
return false;
});
return len;
}
} }

View file

@ -26,28 +26,25 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_misc
{ /// \brief Compute the length of a formula.
/// \ingroup ltl_misc ///
/// \brief Compute the length of a formula. /// The length of a formula is the number of atomic propositions,
/// /// constants, and operators (logical and temporal) occurring in
/// The length of a formula is the number of atomic propositions, /// the formula. n-ary operators count for n-1; for instance
/// constants, and operators (logical and temporal) occurring in /// <code>a | b | c</code> has length 5, even if there is only as
/// the formula. n-ary operators count for n-1; for instance /// single <code>|</code> node internally.
/// <code>a | b | c</code> has length 5, even if there is only as ///
/// single <code>|</code> node internally. /// If squash_boolean is set, all Boolean formulae are assumed
/// /// to have length one.
/// If squash_boolean is set, all Boolean formulae are assumed SPOT_API
/// to have length one. int length(formula f);
SPOT_API
int length(formula f);
/// \ingroup ltl_misc /// \ingroup ltl_misc
/// \brief Compute the length of a formula, squashing Boolean formulae /// \brief Compute the length of a formula, squashing Boolean formulae
/// ///
/// This is similar to spot::ltl::length(), except all Boolean /// This is similar to spot::length(), except all Boolean
/// formulae are assumed to have length one. /// formulae are assumed to have length one.
SPOT_API SPOT_API
int length_boolone(formula f); int length_boolone(formula f);
}
} }

View file

@ -25,170 +25,166 @@
namespace spot namespace spot
{ {
namespace ltl formula
mark_tools::mark_concat_ops(formula f)
{ {
formula f2f_map::iterator i = markops_.find(f);
mark_tools::mark_concat_ops(formula f) if (i != markops_.end())
{ return i->second;
f2f_map::iterator i = markops_.find(f);
if (i != markops_.end())
return i->second;
ltl::formula res; formula res;
switch (f.kind()) switch (f.kind())
{
case op::ff:
case op::tt:
case op::eword:
case op::ap:
case op::Not:
case op::X:
case op::F:
case op::G:
case op::Closure:
case op::NegClosureMarked:
case op::OrRat:
case op::AndRat:
case op::AndNLM:
case op::Star:
case op::FStar:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcatMarked:
case op::UConcat:
case op::Concat:
case op::Fusion:
res = f;
break;
case op::NegClosure:
res = formula::NegClosureMarked(f[0]);
break;
case op::EConcat:
res = formula::EConcatMarked(f[0], f[1]);
break;
case op::Or:
case op::And:
res = f.map([this](formula f)
{
return this->mark_concat_ops(f);
});
break;
case op::Xor:
case op::Implies:
case op::Equiv:
SPOT_UNIMPLEMENTED();
}
markops_[f] = res;
return res;
}
formula
mark_tools::simplify_mark(formula f)
{
if (!f.is_marked())
return f;
f2f_map::iterator i = simpmark_.find(f);
if (i != simpmark_.end())
return i->second;
auto recurse = [this](formula f)
{
return this->simplify_mark(f);
};
formula res;
switch (f.kind())
{
case op::ff:
case op::tt:
case op::eword:
case op::ap:
case op::Not:
case op::X:
case op::F:
case op::G:
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
res = f;
break;
case op::Or:
res = f.map(recurse);
break;
case op::And:
{ {
case op::ff: std::set<std::pair<formula, formula>> empairs;
case op::tt: std::set<formula> nmset;
case op::eword: std::vector<formula> elist;
case op::ap: std::vector<formula> nlist;
case op::Not: std::vector<formula> v;
case op::X:
case op::F: for (auto c: f)
case op::G: {
case op::Closure: if (c.is(op::EConcatMarked))
case op::NegClosureMarked: {
case op::OrRat: empairs.emplace(c[0], c[1]);
case op::AndRat: v.push_back(c.map(recurse));
case op::AndNLM: }
case op::Star: else if (c.is(op::EConcat))
case op::FStar: {
case op::U: elist.push_back(c);
case op::R: }
case op::W: else if (c.is(op::NegClosureMarked))
case op::M: {
case op::EConcatMarked: nmset.insert(c[0]);
case op::UConcat: v.push_back(c.map(recurse));
case op::Concat: }
case op::Fusion: else if (c.is(op::NegClosure))
res = f; {
break; nlist.push_back(c);
case op::NegClosure: }
res = ltl::formula::NegClosureMarked(f[0]); else
break; {
case op::EConcat: v.push_back(c);
res = ltl::formula::EConcatMarked(f[0], f[1]); }
break; }
case op::Or: // Keep only the non-marked EConcat for which we
case op::And: // have not seen a similar EConcatMarked.
res = f.map([this](formula f) for (auto e: elist)
{ if (empairs.find(std::make_pair(e[0], e[1]))
return this->mark_concat_ops(f); == empairs.end())
}); v.push_back(e);
break; // Keep only the non-marked NegClosure for which we
case op::Xor: // have not seen a similar NegClosureMarked.
case op::Implies: for (auto n: nlist)
case op::Equiv: if (nmset.find(n[0]) == nmset.end())
SPOT_UNIMPLEMENTED(); v.push_back(n);
res = formula::And(v);
} }
break;
case op::Xor:
case op::Implies:
case op::Equiv:
case op::OrRat:
case op::AndRat:
case op::AndNLM:
case op::Star:
case op::FStar:
case op::Concat:
case op::Fusion:
SPOT_UNIMPLEMENTED();
}
markops_[f] = res; simpmark_[f] = res;
return res; return res;
}
formula
mark_tools::simplify_mark(formula f)
{
if (!f.is_marked())
return f;
f2f_map::iterator i = simpmark_.find(f);
if (i != simpmark_.end())
return i->second;
auto recurse = [this](formula f)
{
return this->simplify_mark(f);
};
ltl::formula res;
switch (f.kind())
{
case op::ff:
case op::tt:
case op::eword:
case op::ap:
case op::Not:
case op::X:
case op::F:
case op::G:
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
res = f;
break;
case op::Or:
res = f.map(recurse);
break;
case op::And:
{
std::set<std::pair<formula, formula>> empairs;
std::set<formula> nmset;
std::vector<formula> elist;
std::vector<formula> nlist;
std::vector<formula> v;
for (auto c: f)
{
if (c.is(op::EConcatMarked))
{
empairs.emplace(c[0], c[1]);
v.push_back(c.map(recurse));
}
else if (c.is(op::EConcat))
{
elist.push_back(c);
}
else if (c.is(op::NegClosureMarked))
{
nmset.insert(c[0]);
v.push_back(c.map(recurse));
}
else if (c.is(op::NegClosure))
{
nlist.push_back(c);
}
else
{
v.push_back(c);
}
}
// Keep only the non-marked EConcat for which we
// have not seen a similar EConcatMarked.
for (auto e: elist)
if (empairs.find(std::make_pair(e[0], e[1]))
== empairs.end())
v.push_back(e);
// Keep only the non-marked NegClosure for which we
// have not seen a similar NegClosureMarked.
for (auto n: nlist)
if (nmset.find(n[0]) == nmset.end())
v.push_back(n);
res = ltl::formula::And(v);
}
break;
case op::Xor:
case op::Implies:
case op::Equiv:
case op::OrRat:
case op::AndRat:
case op::AndNLM:
case op::Star:
case op::FStar:
case op::Concat:
case op::Fusion:
SPOT_UNIMPLEMENTED();
}
simpmark_[f] = res;
return res;
}
} }
} }

View file

@ -24,24 +24,20 @@
namespace spot namespace spot
{ {
namespace ltl class mark_tools final
{ {
class mark_tools final public:
{ /// \ingroup ltl_rewriting
public: /// \brief Mark operators NegClosure and EConcat.
/// \ingroup ltl_rewriting ///
/// \brief Mark operators NegClosure and EConcat. /// \param f The formula to rewrite.
/// formula mark_concat_ops(formula f);
/// \param f The formula to rewrite.
formula mark_concat_ops(formula f);
formula simplify_mark(formula f); formula simplify_mark(formula f);
private: private:
typedef std::unordered_map<formula, formula> f2f_map; typedef std::unordered_map<formula, formula> f2f_map;
f2f_map simpmark_; f2f_map simpmark_;
f2f_map markops_; f2f_map markops_;
}; };
}
} }

View file

@ -32,340 +32,337 @@
namespace spot namespace spot
{ {
namespace ltl namespace
{ {
namespace formula substitute_ap(formula f, formula ap_src, formula ap_dst)
{ {
formula substitute_ap(formula f, formula ap_src, formula ap_dst) return f.map([&](formula f)
{
if (f == ap_src)
return ap_dst;
else
return substitute_ap(f, ap_src, ap_dst);
});
}
typedef std::vector<formula> vec;
class mutator final
{
int mutation_counter_ = 0;
formula f_;
unsigned opts_;
public:
mutator(formula f, unsigned opts) : f_(f), opts_(opts)
{ {
return f.map([&](formula f)
{
if (f == ap_src)
return ap_dst;
else
return substitute_ap(f, ap_src, ap_dst);
});
} }
typedef std::vector<formula> vec; formula mutate(formula f)
class mutator final
{ {
int mutation_counter_ = 0; auto recurse = [this](formula f)
formula f_; {
unsigned opts_; return this->mutate(f);
public: };
mutator(formula f, unsigned opts) : f_(f), opts_(opts)
{
}
formula mutate(formula f) switch (f.kind())
{ {
auto recurse = [this](formula f) case op::ff:
{ case op::tt:
return this->mutate(f); case op::eword:
}; return f;
case op::ap:
switch (f.kind()) if (opts_ & Mut_Ap2Const)
{ {
case op::ff: if (mutation_counter_-- == 0)
case op::tt: return formula::tt();
case op::eword: if (mutation_counter_-- == 0)
return formula::ff();
}
return f;
case op::Not:
case op::X:
case op::F:
case op::G:
if ((opts_ & Mut_Remove_Ops)
&& mutation_counter_-- == 0)
return f[0];
// fall through
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
if (mutation_counter_ < 0)
return f; return f;
case op::ap: else
if (opts_ & Mut_Ap2Const) return f.map(recurse);
case op::Or:
case op::OrRat:
case op::And:
case op::AndRat:
case op::AndNLM:
case op::Concat:
case op::Fusion:
{
int mos = f.size();
if (opts_ & Mut_Remove_Multop_Operands)
{ {
if (mutation_counter_-- == 0) for (int i = 0; i < mos; ++i)
return formula::tt(); if (mutation_counter_-- == 0)
if (mutation_counter_-- == 0) return f.all_but(i);
return formula::ff();
} }
return f;
case op::Not: if (opts_ & Mut_Split_Ops && f.is(op::AndNLM))
case op::X: {
case op::F: if (mutation_counter_ >= 0
case op::G: && mutation_counter_ < 2 * (mos - 1))
if ((opts_ & Mut_Remove_Ops) {
&& mutation_counter_-- == 0) vec v1;
return f[0]; vec v2;
// fall through v1.push_back(f[0]);
case op::Closure: bool reverse = false;
case op::NegClosure: int i = 1;
case op::NegClosureMarked: while (i < mos)
{
if (mutation_counter_-- == 0)
break;
if (mutation_counter_-- == 0)
{
reverse = true;
break;
}
v1.push_back(f[i++]);
}
for (; i < mos; ++i)
v2.push_back(f[i]);
formula first = AndNLM_(v1);
formula second = AndNLM_(v2);
formula ost = formula::one_star();
if (!reverse)
return AndRat_(Concat_(first, ost), second);
else
return AndRat_(Concat_(second, ost), first);
}
else
{
mutation_counter_ -= 2 * (mos - 1);
}
}
if (mutation_counter_ < 0) if (mutation_counter_ < 0)
return f; return f;
else else
return f.map(recurse); return f.map(recurse);
case op::Or:
case op::OrRat:
case op::And:
case op::AndRat:
case op::AndNLM:
case op::Concat:
case op::Fusion:
{
int mos = f.size();
if (opts_ & Mut_Remove_Multop_Operands)
{
for (int i = 0; i < mos; ++i)
if (mutation_counter_-- == 0)
return f.all_but(i);
}
if (opts_ & Mut_Split_Ops && f.is(op::AndNLM))
{
if (mutation_counter_ >= 0
&& mutation_counter_ < 2 * (mos - 1))
{
vec v1;
vec v2;
v1.push_back(f[0]);
bool reverse = false;
int i = 1;
while (i < mos)
{
if (mutation_counter_-- == 0)
break;
if (mutation_counter_-- == 0)
{
reverse = true;
break;
}
v1.push_back(f[i++]);
}
for (; i < mos; ++i)
v2.push_back(f[i]);
formula first = AndNLM_(v1);
formula second = AndNLM_(v2);
formula ost = formula::one_star();
if (!reverse)
return AndRat_(Concat_(first, ost), second);
else
return AndRat_(Concat_(second, ost), first);
}
else
{
mutation_counter_ -= 2 * (mos - 1);
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
case op::Xor:
case op::Implies:
case op::Equiv:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
{
formula first = f[0];
formula second = f[1];
op o = f.kind();
bool left_is_sere = o == op::EConcat
|| o == op::EConcatMarked
|| o == op::UConcat;
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
{
if (!left_is_sere)
return first;
else if (o == op::UConcat)
return formula::NegClosure(first);
else // EConcat or EConcatMarked
return formula::Closure(first);
}
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
return second;
if (opts_ & Mut_Rewrite_Ops)
{
switch (o)
{
case op::U:
if (mutation_counter_-- == 0)
return formula::W(first, second);
break;
case op::M:
if (mutation_counter_-- == 0)
return formula::R(first, second);
if (mutation_counter_-- == 0)
return formula::U(second, first);
break;
case op::R:
if (mutation_counter_-- == 0)
return formula::W(second, first);
break;
default:
break;
}
}
if (opts_ & Mut_Split_Ops)
{
switch (o)
{
case op::Equiv:
if (mutation_counter_-- == 0)
return formula::Implies(first, second);
if (mutation_counter_-- == 0)
return formula::Implies(second, first);
if (mutation_counter_-- == 0)
return formula::And({first, second});
if (mutation_counter_-- == 0)
{
// Negate the two argument sequentially (in this
// case right before left, otherwise different
// compilers will make different choices.
auto right = formula::Not(second);
return formula::And({formula::Not(first), right});
}
break;
case op::Xor:
if (mutation_counter_-- == 0)
return formula::And({first, formula::Not(second)});
if (mutation_counter_-- == 0)
return formula::And({formula::Not(first), second});
break;
default:
break;
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
case op::Star:
case op::FStar:
{
formula c = f[0];
op o = f.kind();
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
return c;
if (opts_ & Mut_Simplify_Bounds)
{
auto min = f.min();
auto max = f.max();
if (min > 0)
{
if (mutation_counter_-- == 0)
return formula::bunop(o, c, min - 1, max);
if (mutation_counter_-- == 0)
return formula::bunop(o, c, 0, max);
}
if (max != formula::unbounded())
{
if (max > min && mutation_counter_-- == 0)
return formula::bunop(o, c, min, max - 1);
if (mutation_counter_-- == 0)
return formula::bunop(o, c, min,
formula::unbounded());
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
} }
SPOT_UNREACHABLE(); case op::Xor:
} case op::Implies:
case op::Equiv:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
{
formula first = f[0];
formula second = f[1];
op o = f.kind();
bool left_is_sere = o == op::EConcat
|| o == op::EConcatMarked
|| o == op::UConcat;
formula if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
get_mutation(int n)
{
mutation_counter_ = n;
formula mut = mutate(f_);
if (mut == f_)
return nullptr;
return mut;
}
};
bool
formula_length_less_than(formula left, formula right)
{
assert(left != nullptr);
assert(right != nullptr);
if (left == right)
return false;
auto ll = length(left);
auto lr = length(right);
if (ll < lr)
return true;
if (ll > lr)
return false;
return left < right;
}
typedef std::set<formula> fset_t;
void
single_mutation_rec(formula f, fset_t& mutations, unsigned opts,
unsigned& n, unsigned m)
{
if (m == 0)
{
if (mutations.insert(f).second)
--n;
}
else
{
formula mut;
int i = 0;
mutator mv(f, opts);
while (n > 0 && ((mut = mv.get_mutation(i++)) != nullptr))
single_mutation_rec(mut, mutations, opts, n, m - 1);
}
}
void
replace_ap_rec(formula f, fset_t& mutations, unsigned opts,
unsigned& n, unsigned m)
{
if (m == 0)
{
if (mutations.insert(f).second)
--n;
}
else
{
if (!n)
return;
auto aps =
std::unique_ptr<atomic_prop_set>(atomic_prop_collect(f));
for (auto ap1: *aps)
for (auto ap2: *aps)
{ {
if (ap1 == ap2) if (!left_is_sere)
continue; return first;
auto mut = substitute_ap(f, ap1, ap2); else if (o == op::UConcat)
replace_ap_rec(mut, mutations, opts, n, m - 1); return formula::NegClosure(first);
if (!n) else // EConcat or EConcatMarked
return; return formula::Closure(first);
} }
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
return second;
if (opts_ & Mut_Rewrite_Ops)
{
switch (o)
{
case op::U:
if (mutation_counter_-- == 0)
return formula::W(first, second);
break;
case op::M:
if (mutation_counter_-- == 0)
return formula::R(first, second);
if (mutation_counter_-- == 0)
return formula::U(second, first);
break;
case op::R:
if (mutation_counter_-- == 0)
return formula::W(second, first);
break;
default:
break;
}
}
if (opts_ & Mut_Split_Ops)
{
switch (o)
{
case op::Equiv:
if (mutation_counter_-- == 0)
return formula::Implies(first, second);
if (mutation_counter_-- == 0)
return formula::Implies(second, first);
if (mutation_counter_-- == 0)
return formula::And({first, second});
if (mutation_counter_-- == 0)
{
// Negate the two argument sequentially (in this
// case right before left, otherwise different
// compilers will make different choices.
auto right = formula::Not(second);
return formula::And({formula::Not(first), right});
}
break;
case op::Xor:
if (mutation_counter_-- == 0)
return formula::And({first, formula::Not(second)});
if (mutation_counter_-- == 0)
return formula::And({formula::Not(first), second});
break;
default:
break;
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
case op::Star:
case op::FStar:
{
formula c = f[0];
op o = f.kind();
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
return c;
if (opts_ & Mut_Simplify_Bounds)
{
auto min = f.min();
auto max = f.max();
if (min > 0)
{
if (mutation_counter_-- == 0)
return formula::bunop(o, c, min - 1, max);
if (mutation_counter_-- == 0)
return formula::bunop(o, c, 0, max);
}
if (max != formula::unbounded())
{
if (max > min && mutation_counter_-- == 0)
return formula::bunop(o, c, min, max - 1);
if (mutation_counter_-- == 0)
return formula::bunop(o, c, min,
formula::unbounded());
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
} }
SPOT_UNREACHABLE();
} }
formula
get_mutation(int n)
{
mutation_counter_ = n;
formula mut = mutate(f_);
if (mut == f_)
return nullptr;
return mut;
}
};
bool
formula_length_less_than(formula left, formula right)
{
assert(left != nullptr);
assert(right != nullptr);
if (left == right)
return false;
auto ll = length(left);
auto lr = length(right);
if (ll < lr)
return true;
if (ll > lr)
return false;
return left < right;
} }
std::vector<formula> typedef std::set<formula> fset_t;
mutate(formula f, unsigned opts, unsigned max_output,
unsigned mutation_count, bool sort)
{
fset_t mutations;
single_mutation_rec(f, mutations, opts, max_output, mutation_count);
if (opts & Mut_Remove_One_Ap)
replace_ap_rec(f, mutations, opts, max_output, mutation_count);
vec res(mutations.begin(), mutations.end()); void
if (sort) single_mutation_rec(formula f, fset_t& mutations, unsigned opts,
std::sort(res.begin(), res.end(), formula_length_less_than); unsigned& n, unsigned m)
return res; {
if (m == 0)
{
if (mutations.insert(f).second)
--n;
}
else
{
formula mut;
int i = 0;
mutator mv(f, opts);
while (n > 0 && ((mut = mv.get_mutation(i++)) != nullptr))
single_mutation_rec(mut, mutations, opts, n, m - 1);
}
}
void
replace_ap_rec(formula f, fset_t& mutations, unsigned opts,
unsigned& n, unsigned m)
{
if (m == 0)
{
if (mutations.insert(f).second)
--n;
}
else
{
if (!n)
return;
auto aps =
std::unique_ptr<atomic_prop_set>(atomic_prop_collect(f));
for (auto ap1: *aps)
for (auto ap2: *aps)
{
if (ap1 == ap2)
continue;
auto mut = substitute_ap(f, ap1, ap2);
replace_ap_rec(mut, mutations, opts, n, m - 1);
if (!n)
return;
}
}
} }
} }
std::vector<formula>
mutate(formula f, unsigned opts, unsigned max_output,
unsigned mutation_count, bool sort)
{
fset_t mutations;
single_mutation_rec(f, mutations, opts, max_output, mutation_count);
if (opts & Mut_Remove_One_Ap)
replace_ap_rec(f, mutations, opts, max_output, mutation_count);
vec res(mutations.begin(), mutations.end());
if (sort)
std::sort(res.begin(), res.end(), formula_length_less_than);
return res;
}
} }

View file

@ -24,25 +24,22 @@
namespace spot namespace spot
{ {
namespace ltl enum mut_opts
{ {
enum mut_opts Mut_Ap2Const = 1U<<0,
{ Mut_Simplify_Bounds = 1U<<1,
Mut_Ap2Const = 1U<<0, Mut_Remove_Multop_Operands = 1U<<2,
Mut_Simplify_Bounds = 1U<<1, Mut_Remove_Ops = 1U<<3,
Mut_Remove_Multop_Operands = 1U<<2, Mut_Split_Ops = 1U<<4,
Mut_Remove_Ops = 1U<<3, Mut_Rewrite_Ops = 1U<<5,
Mut_Split_Ops = 1U<<4, Mut_Remove_One_Ap = 1U<<6,
Mut_Rewrite_Ops = 1U<<5, Mut_All = -1U
Mut_Remove_One_Ap = 1U<<6, };
Mut_All = -1U
};
SPOT_API SPOT_API
std::vector<formula> mutate(formula f, std::vector<formula> mutate(formula f,
unsigned opts = Mut_All, unsigned opts = Mut_All,
unsigned max_output = -1U, unsigned max_output = -1U,
unsigned mutation_count = 1, unsigned mutation_count = 1,
bool sort = true); bool sort = true);
}
} }

View file

@ -25,17 +25,13 @@
namespace spot namespace spot
{ {
namespace ltl formula
negative_normal_form(formula f, bool negated)
{ {
formula if (!negated && f.is_in_nenoform())
negative_normal_form(formula f, bool negated) return f;
{
if (!negated && f.is_in_nenoform())
return f;
ltl_simplifier s;
return s.negative_normal_form(f, negated);
}
ltl_simplifier s;
return s.negative_normal_form(f, negated);
} }
} }

View file

@ -26,24 +26,21 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_rewriting
{ /// \brief Build the negative normal form of \a f.
/// \ingroup ltl_rewriting ///
/// \brief Build the negative normal form of \a f. /// All negations of the formula are pushed in front of the
/// /// atomic propositions.
/// All negations of the formula are pushed in front of the ///
/// atomic propositions. /// \param f The formula to normalize.
/// /// \param negated If \c true, return the negative normal form of
/// \param f The formula to normalize. /// \c !f
/// \param negated If \c true, return the negative normal form of ///
/// \c !f /// Note that this will not remove abbreviated operators. If you
/// /// want to remove abbreviations, call spot::unabbreviate
/// Note that this will not remove abbreviated operators. If you /// first. (Calling this function after
/// want to remove abbreviations, call spot::ltl::unabbreviate /// spot::negative_normal_form would likely produce a formula
/// first. (Calling this function after /// which is not in negative normal form.)
/// spot::ltl::negative_normal_form would likely produce a formula SPOT_API formula
/// which is not in negative normal form.) negative_normal_form(formula f, bool negated = false);
SPOT_API formula
negative_normal_form(formula f, bool negated = false);
}
} }

File diff suppressed because it is too large Load diff

View file

@ -27,198 +27,195 @@
namespace spot namespace spot
{ {
namespace ltl /// \addtogroup ltl_io
{ /// @{
/// \addtogroup ltl_io
/// @{
/// \brief Output a PSL formula as a string which is parsable. /// \brief Output a PSL formula as a string which is parsable.
/// \param os The stream where it should be output. /// \param os The stream where it should be output.
/// \param f The formula to translate. /// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully /// \param full_parent Whether or not the string should by fully
/// parenthesized. /// parenthesized.
SPOT_API std::ostream& SPOT_API std::ostream&
print_psl(std::ostream& os, formula f, bool full_parent = false); print_psl(std::ostream& os, formula f, bool full_parent = false);
/// \brief Convert a PSL formula into a string which is parsable /// \brief Convert a PSL formula into a string which is parsable
/// \param f The formula to translate. /// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully /// \param full_parent Whether or not the string should by fully
/// parenthesized. /// parenthesized.
SPOT_API std::string SPOT_API std::string
str_psl(formula f, bool full_parent = false); str_psl(formula f, bool full_parent = false);
/// \brief Output a PSL formula as an utf-8 string which is parsable. /// \brief Output a PSL formula as an utf-8 string which is parsable.
/// \param os The stream where it should be output. /// \param os The stream where it should be output.
/// \param f The formula to translate. /// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully /// \param full_parent Whether or not the string should by fully
/// parenthesized. /// parenthesized.
SPOT_API std::ostream& SPOT_API std::ostream&
print_utf8_psl(std::ostream& os, formula f, print_utf8_psl(std::ostream& os, formula f,
bool full_parent = false);
/// \brief Convert a PSL formula into a utf-8 string which is parsable
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_utf8_psl(formula f, bool full_parent = false);
/// \brief Output a SERE formula as a string which is parsable.
/// \param f The formula to translate.
/// \param os The stream where it should be output.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_sere(std::ostream& os, formula f, bool full_parent = false);
/// \brief Convert a SERE formula into a string which is parsable
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_sere(formula f, bool full_parent = false);
/// \brief Output a SERE formula as a utf-8 string which is parsable.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_utf8_sere(std::ostream& os, formula f,
bool full_parent = false);
/// \brief Convert a SERE formula into a string which is parsable
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_utf8_sere(formula f, bool full_parent = false);
/// \brief Output an LTL formula as a string parsable by Spin.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_spin_ltl(std::ostream& os, formula f,
bool full_parent = false);
/// \brief Convert an LTL formula into a string parsable by Spin.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_spin_ltl(formula f, bool full_parent = false);
/// \brief Output an LTL formula as a string parsable by Wring.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
SPOT_API std::ostream&
print_wring_ltl(std::ostream& os, formula f);
/// \brief Convert a formula into a string parsable by Wring
/// \param f The formula to translate.
SPOT_API std::string
str_wring_ltl(formula f);
/// \brief Output a PSL formula as a LaTeX string.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_latex_psl(std::ostream& os, formula f,
bool full_parent = false);
/// \brief Output a formula as a LaTeX string which is parsable.
/// unless the formula contains automaton operators (used in ELTL formulae).
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_latex_psl(formula f, bool full_parent = false);
/// \brief Output a SERE formula as a LaTeX string.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_latex_sere(std::ostream& os, formula f,
bool full_parent = false); bool full_parent = false);
/// \brief Convert a PSL formula into a utf-8 string which is parsable /// \brief Output a SERE formula as a LaTeX string which is parsable.
/// \param f The formula to translate. /// unless the formula contains automaton operators (used in ELTL formulae).
/// \param full_parent Whether or not the string should by fully /// \param f The formula to translate.
/// parenthesized. /// \param full_parent Whether or not the string should by fully
SPOT_API std::string /// parenthesized.
str_utf8_psl(formula f, bool full_parent = false); SPOT_API std::string
str_latex_sere(formula f, bool full_parent = false);
/// \brief Output a SERE formula as a string which is parsable. /// \brief Output a PSL formula as a self-contained LaTeX string.
/// \param f The formula to translate. ///
/// \param os The stream where it should be output. /// The result cannot be parsed back.
/// \param full_parent Whether or not the string should by fully /// \param os The stream where it should be output.
/// parenthesized. /// \param f The formula to translate.
SPOT_API std::ostream& /// \param full_parent Whether or not the string should by fully
print_sere(std::ostream& os, formula f, bool full_parent = false); /// parenthesized.
SPOT_API std::ostream&
/// \brief Convert a SERE formula into a string which is parsable print_sclatex_psl(std::ostream& os, formula f,
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_sere(formula f, bool full_parent = false);
/// \brief Output a SERE formula as a utf-8 string which is parsable.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_utf8_sere(std::ostream& os, formula f,
bool full_parent = false); bool full_parent = false);
/// \brief Convert a SERE formula into a string which is parsable /// \brief Output a PSL formula as a self-contained LaTeX string.
/// \param f The formula to translate. ///
/// \param full_parent Whether or not the string should by fully /// The result cannot be parsed bacl.
/// parenthesized. /// \param f The formula to translate.
SPOT_API std::string /// \param full_parent Whether or not the string should by fully
str_utf8_sere(formula f, bool full_parent = false); /// parenthesized.
SPOT_API std::string
str_sclatex_psl(formula f, bool full_parent = false);
/// \brief Output an LTL formula as a string parsable by Spin. /// \brief Output a SERE formula as a self-contained LaTeX string.
/// \param os The stream where it should be output. ///
/// \param f The formula to translate. /// The result cannot be parsed back.
/// \param full_parent Whether or not the string should by fully /// \param os The stream where it should be output.
/// parenthesized. /// \param f The formula to translate.
SPOT_API std::ostream& /// \param full_parent Whether or not the string should by fully
print_spin_ltl(std::ostream& os, formula f, /// parenthesized.
bool full_parent = false); SPOT_API std::ostream&
print_sclatex_sere(std::ostream& os, formula f,
/// \brief Convert an LTL formula into a string parsable by Spin.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_spin_ltl(formula f, bool full_parent = false);
/// \brief Output an LTL formula as a string parsable by Wring.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
SPOT_API std::ostream&
print_wring_ltl(std::ostream& os, formula f);
/// \brief Convert a formula into a string parsable by Wring
/// \param f The formula to translate.
SPOT_API std::string
str_wring_ltl(formula f);
/// \brief Output a PSL formula as a LaTeX string.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_latex_psl(std::ostream& os, formula f,
bool full_parent = false);
/// \brief Output a formula as a LaTeX string which is parsable.
/// unless the formula contains automaton operators (used in ELTL formulae).
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_latex_psl(formula f, bool full_parent = false);
/// \brief Output a SERE formula as a LaTeX string.
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_latex_sere(std::ostream& os, formula f,
bool full_parent = false); bool full_parent = false);
/// \brief Output a SERE formula as a LaTeX string which is parsable. /// \brief Output a SERE formula as a self-contained LaTeX string.
/// unless the formula contains automaton operators (used in ELTL formulae). ///
/// \param f The formula to translate. /// The result cannot be parsed bacl.
/// \param full_parent Whether or not the string should by fully /// \param f The formula to translate.
/// parenthesized. /// \param full_parent Whether or not the string should by fully
SPOT_API std::string /// parenthesized.
str_latex_sere(formula f, bool full_parent = false); SPOT_API std::string
str_sclatex_sere(formula f, bool full_parent = false);
/// \brief Output a PSL formula as a self-contained LaTeX string. /// \brief Output an LTL formula as a string in LBT's format.
/// ///
/// The result cannot be parsed back. /// The formula must be an LTL formula (ELTL and PSL operators
/// \param os The stream where it should be output. /// are not supported). The M and W operator will be output
/// \param f The formula to translate. /// as-is, because this is accepted by LBTT, however if you
/// \param full_parent Whether or not the string should by fully /// plan to use the output with other tools, you should probably
/// parenthesized. /// rewrite these two operators using unabbreviate_wm().
SPOT_API std::ostream& ///
print_sclatex_psl(std::ostream& os, formula f, /// \param f The formula to translate.
bool full_parent = false); /// \param os The stream where it should be output.
SPOT_API std::ostream&
print_lbt_ltl(std::ostream& os, formula f);
/// \brief Output a PSL formula as a self-contained LaTeX string. /// \brief Output an LTL formula as a string in LBT's format.
/// ///
/// The result cannot be parsed bacl. /// The formula must be an LTL formula (ELTL and PSL operators
/// \param f The formula to translate. /// are not supported). The M and W operator will be output
/// \param full_parent Whether or not the string should by fully /// as-is, because this is accepted by LBTT, however if you
/// parenthesized. /// plan to use the output with other tools, you should probably
SPOT_API std::string /// rewrite these two operators using unabbreviate_wm().
str_sclatex_psl(formula f, bool full_parent = false); ///
/// \param f The formula to translate.
/// \brief Output a SERE formula as a self-contained LaTeX string. SPOT_API std::string
/// str_lbt_ltl(formula f);
/// The result cannot be parsed back. /// @}
/// \param os The stream where it should be output.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::ostream&
print_sclatex_sere(std::ostream& os, formula f,
bool full_parent = false);
/// \brief Output a SERE formula as a self-contained LaTeX string.
///
/// The result cannot be parsed bacl.
/// \param f The formula to translate.
/// \param full_parent Whether or not the string should by fully
/// parenthesized.
SPOT_API std::string
str_sclatex_sere(formula f, bool full_parent = false);
/// \brief Output an LTL formula as a string in LBT's format.
///
/// The formula must be an LTL formula (ELTL and PSL operators
/// are not supported). The M and W operator will be output
/// as-is, because this is accepted by LBTT, however if you
/// plan to use the output with other tools, you should probably
/// rewrite these two operators using unabbreviate_wm().
///
/// \param f The formula to translate.
/// \param os The stream where it should be output.
SPOT_API std::ostream&
print_lbt_ltl(std::ostream& os, formula f);
/// \brief Output an LTL formula as a string in LBT's format.
///
/// The formula must be an LTL formula (ELTL and PSL operators
/// are not supported). The M and W operator will be output
/// as-is, because this is accepted by LBTT, however if you
/// plan to use the output with other tools, you should probably
/// rewrite these two operators using unabbreviate_wm().
///
/// \param f The formula to translate.
SPOT_API std::string
str_lbt_ltl(formula f);
/// @}
}
} }

File diff suppressed because it is too large Load diff

View file

@ -38,316 +38,312 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_io
/// \brief Base class for random formula generators
class SPOT_API random_formula
{ {
public:
/// \ingroup ltl_io random_formula(unsigned proba_size,
/// \brief Base class for random formula generators const atomic_prop_set* ap):
class SPOT_API random_formula proba_size_(proba_size), proba_(new op_proba[proba_size_]), ap_(ap)
{ {
public: }
random_formula(unsigned proba_size,
const atomic_prop_set* ap):
proba_size_(proba_size), proba_(new op_proba[proba_size_]), ap_(ap)
{
}
virtual ~random_formula() virtual ~random_formula()
{ {
delete[] proba_; delete[] proba_;
} }
/// Return the set of atomic proposition used to build formulae. /// Return the set of atomic proposition used to build formulae.
const atomic_prop_set* const atomic_prop_set*
ap() const ap() const
{
return ap_;
}
/// \brief Generate a formula of size \a n.
///
/// It is possible to obtain formulae that are smaller than \a
/// n, because some simple simplifications are performed by the
/// AST. (For instance the formula <code>a | a</code> is
/// automatically reduced to <code>a</code> by spot::ltl::multop.)
formula generate(int n) const;
/// \brief Print the priorities of each operator, constants,
/// and atomic propositions.
std::ostream& dump_priorities(std::ostream& os) const;
/// \brief Update the priorities used to generate the formulae.
///
/// \a options should be comma-separated list of KEY=VALUE
/// assignments, using keys from the above list.
/// For instance <code>"xor=0, F=3"</code> will prevent \c xor
/// from being used, and will raise the relative probability of
/// occurrences of the \c F operator.
const char* parse_options(char* options);
protected:
void update_sums();
struct op_proba
{
const char* name;
int min_n;
double proba;
typedef formula (*builder)(const random_formula* rl, int n);
builder build;
void setup(const char* name, int min_n, builder build);
};
unsigned proba_size_;
op_proba* proba_;
double total_1_;
op_proba* proba_2_;
double total_2_;
op_proba* proba_2_or_more_;
double total_2_and_more_;
const atomic_prop_set* ap_;
};
/// \ingroup ltl_io
/// \brief Generate random LTL formulae.
///
/// This class recursively constructs LTL formulae of a given
/// size. The formulae will use the use atomic propositions from
/// the set of propositions passed to the constructor, in addition
/// to the constant and all LTL operators supported by Spot.
///
/// By default each operator has equal chance to be selected.
/// Also, each atomic proposition has as much chance as each
/// constant (i.e., true and false) to be picked. This can be
/// tuned using parse_options().
class SPOT_API random_ltl: public random_formula
{ {
public: return ap_;
/// Create a random LTL generator using atomic propositions from \a ap. }
///
/// The default priorities are defined as follows:
///
/** \verbatim
ap n
false 1
true 1
not 1
F 1
G 1
X 1
equiv 1
implies 1
xor 1
R 1
U 1
W 1
M 1
and 1
or 1
\endverbatim */
///
/// Where \c n is the number of atomic propositions in the
/// set passed to the constructor.
///
/// This means that each operator has equal chance to be
/// selected. Also, each atomic proposition has as much chance
/// as each constant (i.e., true and false) to be picked.
///
/// These priorities can be changed use the parse_options method.
random_ltl(const atomic_prop_set* ap);
protected: /// \brief Generate a formula of size \a n.
void setup_proba_(); ///
random_ltl(int size, const atomic_prop_set* ap); /// It is possible to obtain formulae that are smaller than \a
}; /// n, because some simple simplifications are performed by the
/// AST. (For instance the formula <code>a | a</code> is
/// automatically reduced to <code>a</code> by spot::multop.)
formula generate(int n) const;
/// \ingroup ltl_io /// \brief Print the priorities of each operator, constants,
/// \brief Generate random Boolean formulae. /// and atomic propositions.
std::ostream& dump_priorities(std::ostream& os) const;
/// \brief Update the priorities used to generate the formulae.
/// ///
/// This class recursively constructs Boolean formulae of a given size. /// \a options should be comma-separated list of KEY=VALUE
/// The formulae will use the use atomic propositions from the /// assignments, using keys from the above list.
/// set of propositions passed to the constructor, in addition to the /// For instance <code>"xor=0, F=3"</code> will prevent \c xor
/// constant and all Boolean operators supported by Spot. /// from being used, and will raise the relative probability of
/// /// occurrences of the \c F operator.
/// By default each operator has equal chance to be selected. const char* parse_options(char* options);
class SPOT_API random_boolean: public random_formula
protected:
void update_sums();
struct op_proba
{ {
public: const char* name;
/// Create a random Boolean formula generator using atomic int min_n;
/// propositions from \a ap. double proba;
/// typedef formula (*builder)(const random_formula* rl, int n);
/// The default priorities are defined as follows: builder build;
/// void setup(const char* name, int min_n, builder build);
/** \verbatim
ap n
false 1
true 1
not 1
equiv 1
implies 1
xor 1
and 1
or 1
\endverbatim */
///
/// Where \c n is the number of atomic propositions in the
/// set passed to the constructor.
///
/// This means that each operator has equal chance to be
/// selected. Also, each atomic proposition has as much chance
/// as each constant (i.e., true and false) to be picked.
///
/// These priorities can be changed use the parse_options method.
random_boolean(const atomic_prop_set* ap);
}; };
unsigned proba_size_;
op_proba* proba_;
double total_1_;
op_proba* proba_2_;
double total_2_;
op_proba* proba_2_or_more_;
double total_2_and_more_;
const atomic_prop_set* ap_;
};
/// \ingroup ltl_io
/// \brief Generate random SERE. /// \ingroup ltl_io
/// \brief Generate random LTL formulae.
///
/// This class recursively constructs LTL formulae of a given
/// size. The formulae will use the use atomic propositions from
/// the set of propositions passed to the constructor, in addition
/// to the constant and all LTL operators supported by Spot.
///
/// By default each operator has equal chance to be selected.
/// Also, each atomic proposition has as much chance as each
/// constant (i.e., true and false) to be picked. This can be
/// tuned using parse_options().
class SPOT_API random_ltl: public random_formula
{
public:
/// Create a random LTL generator using atomic propositions from \a ap.
/// ///
/// This class recursively constructs SERE of a given size. /// The default priorities are defined as follows:
/// The formulae will use the use atomic propositions from the
/// set of propositions passed to the constructor, in addition to the
/// constant and all SERE operators supported by Spot.
/// ///
/// By default each operator has equal chance to be selected. /** \verbatim
class SPOT_API random_sere: public random_formula ap n
{ false 1
public: true 1
/// Create a random SERE genere using atomic propositions from \a ap. not 1
/// F 1
/// The default priorities are defined as follows: G 1
/// X 1
/** \verbatim equiv 1
eword 1 implies 1
boolform 1 xor 1
star 1 R 1
star_b 1 U 1
equal_b 1 W 1
goto_b 1 M 1
and 1 and 1
andNLM 1 or 1
or 1 \endverbatim */
concat 1
fusion 1
\endverbatim */
///
/// Where "boolfrom" designates a Boolean formula generated
/// by random_boolean.
///
/// These priorities can be changed use the parse_options method.
///
/// In addition, you can set the properties of the Boolean
/// formula generator used to build Boolean subformulae using
/// the parse_options method of the \c rb attribute.
random_sere(const atomic_prop_set* ap);
random_boolean rb;
};
/// \ingroup ltl_io
/// \brief Generate random PSL formulae.
/// ///
/// This class recursively constructs PSL formulae of a given size. /// Where \c n is the number of atomic propositions in the
/// The formulae will use the use atomic propositions from the /// set passed to the constructor.
/// set of propositions passed to the constructor, in addition to the ///
/// constant and all PSL operators supported by Spot. /// This means that each operator has equal chance to be
class SPOT_API random_psl: public random_ltl /// selected. Also, each atomic proposition has as much chance
{ /// as each constant (i.e., true and false) to be picked.
public: ///
/// Create a random PSL generator using atomic propositions from \a ap. /// These priorities can be changed use the parse_options method.
/// random_ltl(const atomic_prop_set* ap);
/// PSL formulae are built by combining LTL operators, plus
/// three operators (EConcat, UConcat, Closure) taking a SERE
/// as parameter.
///
/// The default priorities are defined as follows:
///
/** \verbatim
ap n
false 1
true 1
not 1
F 1
G 1
X 1
Closure 1
equiv 1
implies 1
xor 1
R 1
U 1
W 1
M 1
and 1
or 1
EConcat 1
UConcat 1
\endverbatim */
///
/// Where \c n is the number of atomic propositions in the
/// set passed to the constructor.
///
/// This means that each operator has equal chance to be
/// selected. Also, each atomic proposition has as much chance
/// as each constant (i.e., true and false) to be picked.
///
/// These priorities can be changed use the parse_options method.
///
/// In addition, you can set the properties of the SERE generator
/// used to build SERE subformulae using the parse_options method
/// of the \c rs attribute.
random_psl(const atomic_prop_set* ap);
/// The SERE generator used to generate SERE subformulae. protected:
random_sere rs; void setup_proba_();
}; random_ltl(int size, const atomic_prop_set* ap);
};
class SPOT_API randltlgenerator /// \ingroup ltl_io
{ /// \brief Generate random Boolean formulae.
typedef std::unordered_set<formula> fset_t; ///
/// This class recursively constructs Boolean formulae of a given size.
/// The formulae will use the use atomic propositions from the
/// set of propositions passed to the constructor, in addition to the
/// constant and all Boolean operators supported by Spot.
///
/// By default each operator has equal chance to be selected.
class SPOT_API random_boolean: public random_formula
{
public:
/// Create a random Boolean formula generator using atomic
/// propositions from \a ap.
///
/// The default priorities are defined as follows:
///
/** \verbatim
ap n
false 1
true 1
not 1
equiv 1
implies 1
xor 1
and 1
or 1
\endverbatim */
///
/// Where \c n is the number of atomic propositions in the
/// set passed to the constructor.
///
/// This means that each operator has equal chance to be
/// selected. Also, each atomic proposition has as much chance
/// as each constant (i.e., true and false) to be picked.
///
/// These priorities can be changed use the parse_options method.
random_boolean(const atomic_prop_set* ap);
};
/// \ingroup ltl_io
/// \brief Generate random SERE.
///
/// This class recursively constructs SERE of a given size.
/// The formulae will use the use atomic propositions from the
/// set of propositions passed to the constructor, in addition to the
/// constant and all SERE operators supported by Spot.
///
/// By default each operator has equal chance to be selected.
class SPOT_API random_sere: public random_formula
{
public:
/// Create a random SERE genere using atomic propositions from \a ap.
///
/// The default priorities are defined as follows:
///
/** \verbatim
eword 1
boolform 1
star 1
star_b 1
equal_b 1
goto_b 1
and 1
andNLM 1
or 1
concat 1
fusion 1
\endverbatim */
///
/// Where "boolfrom" designates a Boolean formula generated
/// by random_boolean.
///
/// These priorities can be changed use the parse_options method.
///
/// In addition, you can set the properties of the Boolean
/// formula generator used to build Boolean subformulae using
/// the parse_options method of the \c rb attribute.
random_sere(const atomic_prop_set* ap);
random_boolean rb;
};
/// \ingroup ltl_io
/// \brief Generate random PSL formulae.
///
/// This class recursively constructs PSL formulae of a given size.
/// The formulae will use the use atomic propositions from the
/// set of propositions passed to the constructor, in addition to the
/// constant and all PSL operators supported by Spot.
class SPOT_API random_psl: public random_ltl
{
public:
/// Create a random PSL generator using atomic propositions from \a ap.
///
/// PSL formulae are built by combining LTL operators, plus
/// three operators (EConcat, UConcat, Closure) taking a SERE
/// as parameter.
///
/// The default priorities are defined as follows:
///
/** \verbatim
ap n
false 1
true 1
not 1
F 1
G 1
X 1
Closure 1
equiv 1
implies 1
xor 1
R 1
U 1
W 1
M 1
and 1
or 1
EConcat 1
UConcat 1
\endverbatim */
///
/// Where \c n is the number of atomic propositions in the
/// set passed to the constructor.
///
/// This means that each operator has equal chance to be
/// selected. Also, each atomic proposition has as much chance
/// as each constant (i.e., true and false) to be picked.
///
/// These priorities can be changed use the parse_options method.
///
/// In addition, you can set the properties of the SERE generator
/// used to build SERE subformulae using the parse_options method
/// of the \c rs attribute.
random_psl(const atomic_prop_set* ap);
/// The SERE generator used to generate SERE subformulae.
random_sere rs;
};
class SPOT_API randltlgenerator
{
typedef std::unordered_set<formula> fset_t;
public: public:
randltlgenerator(int aprops_n, const option_map& opts, randltlgenerator(int aprops_n, const option_map& opts,
char* opt_pL = nullptr, char* opt_pL = nullptr,
char* opt_pS = nullptr, char* opt_pS = nullptr,
char* opt_pB = nullptr); char* opt_pB = nullptr);
randltlgenerator(atomic_prop_set aprops, const option_map& opts, randltlgenerator(atomic_prop_set aprops, const option_map& opts,
char* opt_pL = nullptr, char* opt_pL = nullptr,
char* opt_pS = nullptr, char* opt_pS = nullptr,
char* opt_pB = nullptr); char* opt_pB = nullptr);
~randltlgenerator(); ~randltlgenerator();
formula next(); formula next();
void dump_ltl_priorities(std::ostream& os); void dump_ltl_priorities(std::ostream& os);
void dump_bool_priorities(std::ostream& os); void dump_bool_priorities(std::ostream& os);
void dump_psl_priorities(std::ostream& os); void dump_psl_priorities(std::ostream& os);
void dump_sere_priorities(std::ostream& os); void dump_sere_priorities(std::ostream& os);
void dump_sere_bool_priorities(std::ostream& os); void dump_sere_bool_priorities(std::ostream& os);
void remove_some_props(atomic_prop_set& s); void remove_some_props(atomic_prop_set& s);
formula GF_n(); formula GF_n();
private: private:
fset_t unique_set_; fset_t unique_set_;
atomic_prop_set aprops_; atomic_prop_set aprops_;
int opt_seed_; int opt_seed_;
int opt_tree_size_min_; int opt_tree_size_min_;
int opt_tree_size_max_; int opt_tree_size_max_;
bool opt_unique_; bool opt_unique_;
bool opt_wf_; bool opt_wf_;
int opt_simpl_level_; int opt_simpl_level_;
ltl_simplifier simpl_; ltl_simplifier simpl_;
int output_; int output_;
random_formula* rf_ = nullptr; random_formula* rf_ = nullptr;
random_psl* rp_ = nullptr; random_psl* rp_ = nullptr;
random_sere* rs_ = nullptr; random_sere* rs_ = nullptr;
}; };
}
} }

View file

@ -27,461 +27,457 @@
namespace spot namespace spot
{ {
namespace ltl //////////////////////////////////////////////////////////////////////
// Basic relabeler
//////////////////////////////////////////////////////////////////////
namespace
{ {
struct ap_generator
//////////////////////////////////////////////////////////////////////
// Basic relabeler
//////////////////////////////////////////////////////////////////////
namespace
{ {
struct ap_generator virtual formula next() = 0;
{ virtual ~ap_generator() {}
virtual formula next() = 0; };
virtual ~ap_generator() {}
};
struct pnn_generator final: ap_generator struct pnn_generator final: ap_generator
{
unsigned nn;
pnn_generator()
: nn(0)
{
}
formula next()
{
std::ostringstream s;
s << 'p' << nn++;
return formula::ap(s.str());
}
};
struct abc_generator final: ap_generator
{
public:
abc_generator()
: nn(0)
{
}
unsigned nn;
formula next()
{
std::string s;
unsigned n = nn++;
do
{
s.push_back('a' + (n % 26));
n /= 26;
}
while (n);
return formula::ap(s);
}
};
class relabeler
{
public:
typedef std::unordered_map<formula, formula> map;
map newname;
ap_generator* gen;
relabeling_map* oldnames;
relabeler(ap_generator* gen, relabeling_map* m)
: gen(gen), oldnames(m)
{
}
~relabeler()
{
delete gen;
}
formula rename(formula old)
{
auto r = newname.emplace(old, nullptr);
if (!r.second)
{
return r.first->second;
}
else
{
formula res = gen->next();
r.first->second = res;
if (oldnames)
(*oldnames)[res] = old;
return res;
}
}
formula
visit(formula f)
{
if (f.is(op::ap))
return rename(f);
else
return f.map([this](formula f)
{
return this->visit(f);
});
}
};
}
formula
relabel(formula f, relabeling_style style, relabeling_map* m)
{ {
ap_generator* gen = nullptr; unsigned nn;
switch (style) pnn_generator()
: nn(0)
{ {
case Pnn:
gen = new pnn_generator;
break;
case Abc:
gen = new abc_generator;
break;
} }
relabeler r(gen, m); formula next()
return r.visit(f);
}
//////////////////////////////////////////////////////////////////////
// Boolean-subexpression relabeler
//////////////////////////////////////////////////////////////////////
// Here we want to rewrite a formula such as
// "a & b & X(c & d) & GF(c & d)" into "p0 & Xp1 & GFp1"
// where Boolean subexpressions are replaced by fresh propositions.
//
// Detecting Boolean subexpressions is not a problem.
// Furthermore, because we are already representing LTL formulas
// with sharing of identical sub-expressions we can easily rename
// a subexpression (such as c&d above) only once. However this
// scheme has two problems:
//
// 1. It will not detect inter-dependent Boolean subexpressions.
// For instance it will mistakenly relabel "(a & b) U (a & !b)"
// as "p0 U p1", hiding the dependency between a&b and a&!b.
//
// 2. Because of our n-ary operators, it will fail to
// notice that (a & b) is a sub-expression of (a & b & c).
//
// The code below only addresses point 1 so that interdependent
// subexpressions are not relabeled. Point 2 could be improved in
// a future version of somebody feels inclined to do so.
//
// The way we compute the subexpressions that can be relabeled is
// by transforming the formula syntax tree into an undirected
// graph, and computing the cut points of this graph. The cut
// points (or articulation points) are the nodes whose removal
// would split the graph in two components. To ensure that a
// Boolean operator is only considered as a cut point if it would
// separate all of its children from the rest of the graph, we
// connect all the children of Boolean operators.
//
// For instance (a & b) U (c & d) has two (Boolean) cut points
// corresponding to the two AND operators:
//
// (a&b)U(c&d)
//
// a&b c&d
//
// a─────b c─────d
//
// (The root node is also a cut-point, but we only consider Boolean
// cut-points for relabeling.)
//
// On the other hand, (a & b) U (b & !c) has only one Boolean
// cut-point which corresponds to the NOT operator:
//
// (a&b)U(b&!c)
//
// a&b b&c
//
// a─────b────!c
// │
// c
//
// Note that if the children of a&b and b&c were not connected,
// a&b and b&c would be considered as cut points because they
// separate "a" or "!c" from the rest of the graph.
//
// The relabeling of a formula is therefore done in 3 passes:
// 1. convert the formula's syntax tree into an undirected graph,
// adding links between children of Boolean operators
// 2. compute the (Boolean) cut points of that graph, using the
// Hopcroft-Tarjan algorithm (see below for a reference)
// 3. recursively scan the formula's tree until we reach
// either a (Boolean) cut point or an atomic proposition, and
// replace that node by a fresh atomic proposition.
//
// In the example above (a&b)U(b&!c), the last recursion
// stop a, b, and !c, producing (p0&p1)U(p1&p2).
namespace
{
typedef std::vector<formula> succ_vec;
typedef std::map<formula, succ_vec> fgraph;
// Convert the formula's syntax tree into an undirected graph
// labeled by subformulas.
class formula_to_fgraph final
{ {
public: std::ostringstream s;
fgraph& g; s << 'p' << nn++;
std::stack<formula> s; return formula::ap(s.str());
}
};
formula_to_fgraph(fgraph& g): struct abc_generator final: ap_generator
g(g) {
public:
abc_generator()
: nn(0)
{ {
} }
~formula_to_fgraph() unsigned nn;
{
}
void formula next()
visit(formula f) {
{ std::string s;
unsigned n = nn++;
do
{ {
// Connect to parent s.push_back('a' + (n % 26));
auto in = g.emplace(f, succ_vec()); n /= 26;
if (!s.empty())
{
formula top = s.top();
in.first->second.push_back(top);
g[top].push_back(f);
if (!in.second)
return;
}
else
{
assert(in.second);
}
} }
s.push(f); while (n);
return formula::ap(s);
}
};
unsigned sz = f.size();
unsigned i = 0; class relabeler
if (sz > 2 && !f.is_boolean()) {
public:
typedef std::unordered_map<formula, formula> map;
map newname;
ap_generator* gen;
relabeling_map* oldnames;
relabeler(ap_generator* gen, relabeling_map* m)
: gen(gen), oldnames(m)
{
}
~relabeler()
{
delete gen;
}
formula rename(formula old)
{
auto r = newname.emplace(old, nullptr);
if (!r.second)
{
return r.first->second;
}
else
{
formula res = gen->next();
r.first->second = res;
if (oldnames)
(*oldnames)[res] = old;
return res;
}
}
formula
visit(formula f)
{
if (f.is(op::ap))
return rename(f);
else
return f.map([this](formula f)
{
return this->visit(f);
});
}
};
}
formula
relabel(formula f, relabeling_style style, relabeling_map* m)
{
ap_generator* gen = nullptr;
switch (style)
{
case Pnn:
gen = new pnn_generator;
break;
case Abc:
gen = new abc_generator;
break;
}
relabeler r(gen, m);
return r.visit(f);
}
//////////////////////////////////////////////////////////////////////
// Boolean-subexpression relabeler
//////////////////////////////////////////////////////////////////////
// Here we want to rewrite a formula such as
// "a & b & X(c & d) & GF(c & d)" into "p0 & Xp1 & GFp1"
// where Boolean subexpressions are replaced by fresh propositions.
//
// Detecting Boolean subexpressions is not a problem.
// Furthermore, because we are already representing LTL formulas
// with sharing of identical sub-expressions we can easily rename
// a subexpression (such as c&d above) only once. However this
// scheme has two problems:
//
// 1. It will not detect inter-dependent Boolean subexpressions.
// For instance it will mistakenly relabel "(a & b) U (a & !b)"
// as "p0 U p1", hiding the dependency between a&b and a&!b.
//
// 2. Because of our n-ary operators, it will fail to
// notice that (a & b) is a sub-expression of (a & b & c).
//
// The code below only addresses point 1 so that interdependent
// subexpressions are not relabeled. Point 2 could be improved in
// a future version of somebody feels inclined to do so.
//
// The way we compute the subexpressions that can be relabeled is
// by transforming the formula syntax tree into an undirected
// graph, and computing the cut points of this graph. The cut
// points (or articulation points) are the nodes whose removal
// would split the graph in two components. To ensure that a
// Boolean operator is only considered as a cut point if it would
// separate all of its children from the rest of the graph, we
// connect all the children of Boolean operators.
//
// For instance (a & b) U (c & d) has two (Boolean) cut points
// corresponding to the two AND operators:
//
// (a&b)U(c&d)
//
// a&b c&d
//
// a─────b c─────d
//
// (The root node is also a cut-point, but we only consider Boolean
// cut-points for relabeling.)
//
// On the other hand, (a & b) U (b & !c) has only one Boolean
// cut-point which corresponds to the NOT operator:
//
// (a&b)U(b&!c)
//
// a&b b&c
//
// a─────b────!c
// │
// c
//
// Note that if the children of a&b and b&c were not connected,
// a&b and b&c would be considered as cut points because they
// separate "a" or "!c" from the rest of the graph.
//
// The relabeling of a formula is therefore done in 3 passes:
// 1. convert the formula's syntax tree into an undirected graph,
// adding links between children of Boolean operators
// 2. compute the (Boolean) cut points of that graph, using the
// Hopcroft-Tarjan algorithm (see below for a reference)
// 3. recursively scan the formula's tree until we reach
// either a (Boolean) cut point or an atomic proposition, and
// replace that node by a fresh atomic proposition.
//
// In the example above (a&b)U(b&!c), the last recursion
// stop a, b, and !c, producing (p0&p1)U(p1&p2).
namespace
{
typedef std::vector<formula> succ_vec;
typedef std::map<formula, succ_vec> fgraph;
// Convert the formula's syntax tree into an undirected graph
// labeled by subformulas.
class formula_to_fgraph final
{
public:
fgraph& g;
std::stack<formula> s;
formula_to_fgraph(fgraph& g):
g(g)
{
}
~formula_to_fgraph()
{
}
void
visit(formula f)
{
{
// Connect to parent
auto in = g.emplace(f, succ_vec());
if (!s.empty())
{ {
/// If we have a formula like (a & b & Xc), consider formula top = s.top();
/// it as ((a & b) & Xc) in the graph to isolate the in.first->second.push_back(top);
/// Boolean operands as a single node. g[top].push_back(f);
formula b = f.boolean_operands(&i); if (!in.second)
if (b) return;
visit(b);
} }
for (; i < sz; ++i) else
visit(f[i]);
if (sz > 1 && f.is_boolean())
{ {
// For Boolean nodes, connect all children in a assert(in.second);
// loop. This way the node can only be a cut-point }
// if it separates all children from the reset of }
// the graph (not only one). s.push(f);
formula pred = f[0];
for (i = 1; i < sz; ++i) unsigned sz = f.size();
unsigned i = 0;
if (sz > 2 && !f.is_boolean())
{
/// If we have a formula like (a & b & Xc), consider
/// it as ((a & b) & Xc) in the graph to isolate the
/// Boolean operands as a single node.
formula b = f.boolean_operands(&i);
if (b)
visit(b);
}
for (; i < sz; ++i)
visit(f[i]);
if (sz > 1 && f.is_boolean())
{
// For Boolean nodes, connect all children in a
// loop. This way the node can only be a cut-point
// if it separates all children from the reset of
// the graph (not only one).
formula pred = f[0];
for (i = 1; i < sz; ++i)
{
formula next = f[i];
// Note that we only add an edge in one
// direction, because we are building a cycle
// between all children anyway.
g[pred].push_back(next);
pred = next;
}
g[pred].push_back(f[0]);
}
s.pop();
}
};
typedef std::set<formula> fset;
struct data_entry // for each node of the graph
{
unsigned num; // serial number, in pre-order
unsigned low; // lowest number accessible via unstacked descendants
data_entry(unsigned num = 0, unsigned low = 0)
: num(num), low(low)
{
}
};
typedef std::unordered_map<formula, data_entry> fmap_t;
struct stack_entry
{
formula grand_parent;
formula parent; // current node
succ_vec::const_iterator current_child;
succ_vec::const_iterator last_child;
};
typedef std::stack<stack_entry> stack_t;
// Fill c with the Boolean cutpoints of g, starting from start.
//
// This is based no "Efficient Algorithms for Graph
// Manipulation", J. Hopcroft & R. Tarjan, in Communications of
// the ACM, 16 (6), June 1973.
//
// It differs from the original algorithm by returning only the
// Boolean cutpoints, and not dealing with the initial state
// properly (our initial state will always be considered as a
// cut-point, but since we only return Boolean cut-points it's
// OK: if the top-most formula is Boolean we want to replace it
// as a whole).
void cut_points(const fgraph& g, fset& c, formula start)
{
stack_t s;
unsigned num = 0;
fmap_t data;
data_entry d = { num, num };
data[start] = d;
++num;
const succ_vec& children = g.find(start)->second;
stack_entry e = { start, start, children.begin(), children.end() };
s.push(e);
while (!s.empty())
{
stack_entry& e = s.top();
if (e.current_child != e.last_child)
{
// Skip the edge if it is just the reverse of the one
// we took.
formula child = *e.current_child;
if (child == e.grand_parent)
{ {
formula next = f[i]; ++e.current_child;
// Note that we only add an edge in one continue;
// direction, because we are building a cycle
// between all children anyway.
g[pred].push_back(next);
pred = next;
} }
g[pred].push_back(f[0]); auto i = data.emplace(std::piecewise_construct,
} std::forward_as_tuple(child),
s.pop(); std::forward_as_tuple(num, num));
} if (i.second) // New destination.
}; {
++num;
const succ_vec& children = g.find(child)->second;
typedef std::set<formula> fset; stack_entry newe = { e.parent, child,
struct data_entry // for each node of the graph children.begin(), children.end() };
{ s.push(newe);
unsigned num; // serial number, in pre-order }
unsigned low; // lowest number accessible via unstacked descendants else // Destination exists.
data_entry(unsigned num = 0, unsigned low = 0) {
: num(num), low(low) data_entry& dparent = data[e.parent];
{ data_entry& dchild = i.first->second;
} // If this is a back-edge, update
}; // the low field of the parent.
typedef std::unordered_map<formula, data_entry> fmap_t; if (dchild.num <= dparent.num)
struct stack_entry if (dparent.low > dchild.num)
{ dparent.low = dchild.num;
formula grand_parent; }
formula parent; // current node ++e.current_child;
succ_vec::const_iterator current_child;
succ_vec::const_iterator last_child;
};
typedef std::stack<stack_entry> stack_t;
// Fill c with the Boolean cutpoints of g, starting from start.
//
// This is based no "Efficient Algorithms for Graph
// Manipulation", J. Hopcroft & R. Tarjan, in Communications of
// the ACM, 16 (6), June 1973.
//
// It differs from the original algorithm by returning only the
// Boolean cutpoints, and not dealing with the initial state
// properly (our initial state will always be considered as a
// cut-point, but since we only return Boolean cut-points it's
// OK: if the top-most formula is Boolean we want to replace it
// as a whole).
void cut_points(const fgraph& g, fset& c, formula start)
{
stack_t s;
unsigned num = 0;
fmap_t data;
data_entry d = { num, num };
data[start] = d;
++num;
const succ_vec& children = g.find(start)->second;
stack_entry e = { start, start, children.begin(), children.end() };
s.push(e);
while (!s.empty())
{
stack_entry& e = s.top();
if (e.current_child != e.last_child)
{
// Skip the edge if it is just the reverse of the one
// we took.
formula child = *e.current_child;
if (child == e.grand_parent)
{
++e.current_child;
continue;
}
auto i = data.emplace(std::piecewise_construct,
std::forward_as_tuple(child),
std::forward_as_tuple(num, num));
if (i.second) // New destination.
{
++num;
const succ_vec& children = g.find(child)->second;
stack_entry newe = { e.parent, child,
children.begin(), children.end() };
s.push(newe);
}
else // Destination exists.
{
data_entry& dparent = data[e.parent];
data_entry& dchild = i.first->second;
// If this is a back-edge, update
// the low field of the parent.
if (dchild.num <= dparent.num)
if (dparent.low > dchild.num)
dparent.low = dchild.num;
}
++e.current_child;
}
else
{
formula grand_parent = e.grand_parent;
formula parent = e.parent;
s.pop();
if (!s.empty())
{
data_entry& dparent = data[parent];
data_entry& dgrand_parent = data[grand_parent];
if (dparent.low >= dgrand_parent.num // cut-point
&& grand_parent.is_boolean())
c.insert(grand_parent);
if (dparent.low < dgrand_parent.low)
dgrand_parent.low = dparent.low;
}
}
}
}
class bse_relabeler final: public relabeler
{
public:
fset& c;
bse_relabeler(ap_generator* gen, fset& c,
relabeling_map* m)
: relabeler(gen, m), c(c)
{
}
using relabeler::visit;
formula
visit(formula f)
{
if (f.is(op::ap) || (c.find(f) != c.end()))
return rename(f);
unsigned sz = f.size();
if (sz <= 2)
return f.map([this](formula f)
{
return visit(f);
});
unsigned i = 0;
std::vector<formula> res;
/// If we have a formula like (a & b & Xc), consider
/// it as ((a & b) & Xc) in the graph to isolate the
/// Boolean operands as a single node.
formula b = f.boolean_operands(&i);
if (b)
{
res.reserve(sz - i + 1);
res.push_back(visit(b));
} }
else else
{ {
res.reserve(sz); formula grand_parent = e.grand_parent;
formula parent = e.parent;
s.pop();
if (!s.empty())
{
data_entry& dparent = data[parent];
data_entry& dgrand_parent = data[grand_parent];
if (dparent.low >= dgrand_parent.num // cut-point
&& grand_parent.is_boolean())
c.insert(grand_parent);
if (dparent.low < dgrand_parent.low)
dgrand_parent.low = dparent.low;
}
} }
for (; i < sz; ++i)
res.push_back(visit(f[i]));
return formula::multop(f.kind(), res);
} }
};
} }
formula class bse_relabeler final: public relabeler
relabel_bse(formula f, relabeling_style style, relabeling_map* m)
{ {
fgraph g; public:
fset& c;
// Build the graph g from the formula f. bse_relabeler(ap_generator* gen, fset& c,
relabeling_map* m)
: relabeler(gen, m), c(c)
{ {
formula_to_fgraph conv(g);
conv.visit(f);
} }
// Compute its cut-points using relabeler::visit;
fset c;
cut_points(g, c, f);
// Relabel the formula recursively, stopping formula
// at cut-points or atomic propositions. visit(formula f)
ap_generator* gen = nullptr; {
switch (style) if (f.is(op::ap) || (c.find(f) != c.end()))
{ return rename(f);
case Pnn:
gen = new pnn_generator; unsigned sz = f.size();
break; if (sz <= 2)
case Abc: return f.map([this](formula f)
gen = new abc_generator; {
break; return visit(f);
} });
bse_relabeler rel(gen, c, m);
return rel.visit(f); unsigned i = 0;
std::vector<formula> res;
/// If we have a formula like (a & b & Xc), consider
/// it as ((a & b) & Xc) in the graph to isolate the
/// Boolean operands as a single node.
formula b = f.boolean_operands(&i);
if (b)
{
res.reserve(sz - i + 1);
res.push_back(visit(b));
}
else
{
res.reserve(sz);
}
for (; i < sz; ++i)
res.push_back(visit(f[i]));
return formula::multop(f.kind(), res);
}
};
}
formula
relabel_bse(formula f, relabeling_style style, relabeling_map* m)
{
fgraph g;
// Build the graph g from the formula f.
{
formula_to_fgraph conv(g);
conv.visit(f);
} }
// Compute its cut-points
fset c;
cut_points(g, c, f);
// Relabel the formula recursively, stopping
// at cut-points or atomic propositions.
ap_generator* gen = nullptr;
switch (style)
{
case Pnn:
gen = new pnn_generator;
break;
case Abc:
gen = new abc_generator;
break;
}
bse_relabeler rel(gen, c, m);
return rel.visit(f);
} }
} }

View file

@ -25,30 +25,27 @@
namespace spot namespace spot
{ {
namespace ltl enum relabeling_style { Abc, Pnn };
{
enum relabeling_style { Abc, Pnn };
typedef std::map<formula, formula> relabeling_map; typedef std::map<formula, formula> relabeling_map;
/// \ingroup ltl_rewriting /// \ingroup ltl_rewriting
/// \brief Relabel the atomic propositions in a formula. /// \brief Relabel the atomic propositions in a formula.
/// ///
/// If \a m is non-null, it is filled with correspondence /// If \a m is non-null, it is filled with correspondence
/// between the new names (keys) and the old names (values). /// between the new names (keys) and the old names (values).
SPOT_API SPOT_API
formula relabel(formula f, relabeling_style style, formula relabel(formula f, relabeling_style style,
relabeling_map* m = nullptr); relabeling_map* m = nullptr);
/// \ingroup ltl_rewriting /// \ingroup ltl_rewriting
/// \brief Relabel Boolean subexpressions in a formula using /// \brief Relabel Boolean subexpressions in a formula using
/// atomic propositions. /// atomic propositions.
/// ///
/// If \a m is non-null, it is filled with correspondence /// If \a m is non-null, it is filled with correspondence
/// between the new names (keys) and the old names (values). /// between the new names (keys) and the old names (values).
SPOT_API SPOT_API
formula relabel_bse(formula f, relabeling_style style, formula relabel_bse(formula f, relabeling_style style,
relabeling_map* m = nullptr); relabeling_map* m = nullptr);
}
} }

View file

@ -23,80 +23,77 @@
namespace spot namespace spot
{ {
namespace ltl namespace
{ {
namespace static formula
{ remove_x_rec(formula f, atomic_prop_set& aps)
static formula
remove_x_rec(formula f, atomic_prop_set& aps)
{
if (f.is_syntactic_stutter_invariant())
return f;
auto rec = [&aps](formula f)
{
return remove_x_rec(f, aps);
};
if (!f.is(op::X))
return f.map(rec);
formula c = rec(f[0]);
std::vector<formula> vo;
for (auto i: aps)
{
// First line
std::vector<formula> va1;
formula npi = formula::Not(i);
va1.push_back(i);
va1.push_back(formula::U(i, formula::And({npi, c})));
for (auto j: aps)
if (j != i)
{
// make sure the arguments of OR are created in a
// deterministic order
auto tmp = formula::U(formula::Not(j), npi);
va1.push_back(formula::Or({formula::U(j, npi), tmp}));
}
vo.push_back(formula::And(va1));
// Second line
std::vector<formula> va2;
va2.push_back(npi);
va2.push_back(formula::U(npi, formula::And({i, c})));
for (auto j: aps)
if (j != i)
{
// make sure the arguments of OR are created in a
// deterministic order
auto tmp = formula::U(formula::Not(j), i);
va2.push_back(formula::Or({formula::U(j, i), tmp}));
}
vo.push_back(formula::And(va2));
}
// Third line
std::vector<formula> va3;
for (auto i: aps)
{
// make sure the arguments of OR are created in a
// deterministic order
auto tmp = formula::G(formula::Not(i));
va3.push_back(formula::Or({formula::G(i), tmp}));
}
va3.push_back(c);
vo.push_back(formula::And(va3));
return formula::Or(vo);
}
}
formula remove_x(formula f)
{ {
if (f.is_syntactic_stutter_invariant()) if (f.is_syntactic_stutter_invariant())
return f; return f;
atomic_prop_set aps;
atomic_prop_collect(f, &aps); auto rec = [&aps](formula f)
return remove_x_rec(f, aps); {
return remove_x_rec(f, aps);
};
if (!f.is(op::X))
return f.map(rec);
formula c = rec(f[0]);
std::vector<formula> vo;
for (auto i: aps)
{
// First line
std::vector<formula> va1;
formula npi = formula::Not(i);
va1.push_back(i);
va1.push_back(formula::U(i, formula::And({npi, c})));
for (auto j: aps)
if (j != i)
{
// make sure the arguments of OR are created in a
// deterministic order
auto tmp = formula::U(formula::Not(j), npi);
va1.push_back(formula::Or({formula::U(j, npi), tmp}));
}
vo.push_back(formula::And(va1));
// Second line
std::vector<formula> va2;
va2.push_back(npi);
va2.push_back(formula::U(npi, formula::And({i, c})));
for (auto j: aps)
if (j != i)
{
// make sure the arguments of OR are created in a
// deterministic order
auto tmp = formula::U(formula::Not(j), i);
va2.push_back(formula::Or({formula::U(j, i), tmp}));
}
vo.push_back(formula::And(va2));
}
// Third line
std::vector<formula> va3;
for (auto i: aps)
{
// make sure the arguments of OR are created in a
// deterministic order
auto tmp = formula::G(formula::Not(i));
va3.push_back(formula::Or({formula::G(i), tmp}));
}
va3.push_back(c);
vo.push_back(formula::And(va3));
return formula::Or(vo);
} }
} }
formula remove_x(formula f)
{
if (f.is_syntactic_stutter_invariant())
return f;
atomic_prop_set aps;
atomic_prop_collect(f, &aps);
return remove_x_rec(f, aps);
}
} }

View file

@ -23,27 +23,24 @@
namespace spot namespace spot
{ {
namespace ltl /// \brief Rewrite a stutter-insensitive formula \a f without
{ /// using the X operator.
/// \brief Rewrite a stutter-insensitive formula \a f without ///
/// using the X operator. /// This function may also be applied to stutter-sensitive formulas,
/// /// but in that case the resulting formula is not equivalent.
/// This function may also be applied to stutter-sensitive formulas, ///
/// but in that case the resulting formula is not equivalent. /** \verbatim
/// @Article{ etessami.00.ipl,
/** \verbatim author = {Kousha Etessami},
@Article{ etessami.00.ipl, title = {A note on a question of {P}eled and {W}ilke regarding
author = {Kousha Etessami}, stutter-invariant {LTL}},
title = {A note on a question of {P}eled and {W}ilke regarding journal = {Information Processing Letters},
stutter-invariant {LTL}}, volume = {75},
journal = {Information Processing Letters}, number = {6},
volume = {75}, year = {2000},
number = {6}, pages = {261--263}
year = {2000}, }
pages = {261--263} \endverbatim */
} SPOT_API
\endverbatim */ formula remove_x(formula f);
SPOT_API
formula remove_x(formula f);
}
} }

View file

@ -24,24 +24,20 @@
namespace spot namespace spot
{ {
namespace ltl formula simplify_f_g(formula p)
{ {
formula simplify_f_g(formula p) // 1 U p = Fp
{ if (p.is(op::U) && p[0].is_tt())
// 1 U p = Fp return formula::F(p[1]);
if (p.is(op::U) && p[0].is_tt()) // 0 R p = Gp
return formula::F(p[1]); if (p.is(op::R) && p[0].is_ff())
// 0 R p = Gp return formula::G(p[1]);
if (p.is(op::R) && p[0].is_ff()) // p W 0 = Gp
return formula::G(p[1]); if (p.is(op::W) && p[1].is_ff())
// p W 0 = Gp return formula::G(p[0]);
if (p.is(op::W) && p[1].is_ff()) // p M 1 = Fp
return formula::G(p[0]); if (p.is(op::M) && p[1].is_tt())
// p M 1 = Fp return formula::F(p[0]);
if (p.is(op::M) && p[1].is_tt()) return p.map(simplify_f_g);
return formula::F(p[0]);
return p.map(simplify_f_g);
}
} }
} }

View file

@ -26,19 +26,16 @@
namespace spot namespace spot
{ {
namespace ltl /// \ingroup ltl_rewriting
{ /// \brief Replace <code>true U f</code> and <code>false R g</code> by
/// \ingroup ltl_rewriting /// <code>F f</code> and <code>G g</code>.
/// \brief Replace <code>true U f</code> and <code>false R g</code> by ///
/// <code>F f</code> and <code>G g</code>. /// Perform the following rewriting (from left to right):
/// ///
/// Perform the following rewriting (from left to right): /// - true U a = F a
/// /// - a M true = F a
/// - true U a = F a /// - false R a = G a
/// - a M true = F a /// - a W false = G a
/// - false R a = G a ///
/// - a W false = G a SPOT_API formula simplify_f_g(formula f);
///
SPOT_API formula simplify_f_g(formula f);
}
} }

File diff suppressed because it is too large Load diff

View file

@ -26,179 +26,176 @@
namespace spot namespace spot
{ {
namespace ltl class ltl_simplifier_options
{ {
class ltl_simplifier_options public:
ltl_simplifier_options(bool basics = true,
bool synt_impl = true,
bool event_univ = true,
bool containment_checks = false,
bool containment_checks_stronger = false,
bool nenoform_stop_on_boolean = false,
bool reduce_size_strictly = false,
bool boolean_to_isop = false,
bool favor_event_univ = false)
: reduce_basics(basics),
synt_impl(synt_impl),
event_univ(event_univ),
containment_checks(containment_checks),
containment_checks_stronger(containment_checks_stronger),
nenoform_stop_on_boolean(nenoform_stop_on_boolean),
reduce_size_strictly(reduce_size_strictly),
boolean_to_isop(boolean_to_isop),
favor_event_univ(favor_event_univ)
{ {
public: }
ltl_simplifier_options(bool basics = true,
bool synt_impl = true,
bool event_univ = true,
bool containment_checks = false,
bool containment_checks_stronger = false,
bool nenoform_stop_on_boolean = false,
bool reduce_size_strictly = false,
bool boolean_to_isop = false,
bool favor_event_univ = false)
: reduce_basics(basics),
synt_impl(synt_impl),
event_univ(event_univ),
containment_checks(containment_checks),
containment_checks_stronger(containment_checks_stronger),
nenoform_stop_on_boolean(nenoform_stop_on_boolean),
reduce_size_strictly(reduce_size_strictly),
boolean_to_isop(boolean_to_isop),
favor_event_univ(favor_event_univ)
{
}
ltl_simplifier_options(int level) : ltl_simplifier_options(int level) :
ltl_simplifier_options(false, false, false) ltl_simplifier_options(false, false, false)
{
switch (level)
{
case 3:
containment_checks = true;
containment_checks_stronger = true;
// fall through
case 2:
synt_impl = true;
// fall through
case 1:
reduce_basics = true;
event_univ = true;
// fall through
default:
break;
}
}
bool reduce_basics;
bool synt_impl;
bool event_univ;
bool containment_checks;
bool containment_checks_stronger;
// If true, Boolean subformulae will not be put into
// negative normal form.
bool nenoform_stop_on_boolean;
// If true, some rules that produce slightly larger formulae
// will be disabled. Those larger formulae are normally easier
// to translate, so we recommend to set this to false.
bool reduce_size_strictly;
// If true, Boolean subformulae will be rewritten in ISOP form.
bool boolean_to_isop;
// Try to isolate subformulae that are eventual and universal.
bool favor_event_univ;
};
// fwd declaration to hide technical details.
class ltl_simplifier_cache;
/// \ingroup ltl_rewriting
/// \brief Rewrite or simplify \a f in various ways.
class SPOT_API ltl_simplifier
{ {
public: switch (level)
ltl_simplifier(const bdd_dict_ptr& dict = make_bdd_dict()); {
ltl_simplifier(const ltl_simplifier_options& opt, case 3:
bdd_dict_ptr dict = make_bdd_dict()); containment_checks = true;
~ltl_simplifier(); containment_checks_stronger = true;
// fall through
case 2:
synt_impl = true;
// fall through
case 1:
reduce_basics = true;
event_univ = true;
// fall through
default:
break;
}
}
/// Simplify the formula \a f (using options supplied to the bool reduce_basics;
/// constructor). bool synt_impl;
formula simplify(formula f); bool event_univ;
bool containment_checks;
bool containment_checks_stronger;
// If true, Boolean subformulae will not be put into
// negative normal form.
bool nenoform_stop_on_boolean;
// If true, some rules that produce slightly larger formulae
// will be disabled. Those larger formulae are normally easier
// to translate, so we recommend to set this to false.
bool reduce_size_strictly;
// If true, Boolean subformulae will be rewritten in ISOP form.
bool boolean_to_isop;
// Try to isolate subformulae that are eventual and universal.
bool favor_event_univ;
};
/// Build the negative normal form of formula \a f. // fwd declaration to hide technical details.
/// All negations of the formula are pushed in front of the class ltl_simplifier_cache;
/// atomic propositions. Operators <=>, =>, xor are all removed
/// (calling spot::ltl::unabbreviate_ltl is not needed). /// \ingroup ltl_rewriting
/// /// \brief Rewrite or simplify \a f in various ways.
/// \param f The formula to normalize. class SPOT_API ltl_simplifier
/// \param negated If \c true, return the negative normal form of {
/// \c !f public:
formula ltl_simplifier(const bdd_dict_ptr& dict = make_bdd_dict());
ltl_simplifier(const ltl_simplifier_options& opt,
bdd_dict_ptr dict = make_bdd_dict());
~ltl_simplifier();
/// Simplify the formula \a f (using options supplied to the
/// constructor).
formula simplify(formula f);
/// Build the negative normal form of formula \a f.
/// All negations of the formula are pushed in front of the
/// atomic propositions. Operators <=>, =>, xor are all removed
/// (calling spot::unabbreviate_ltl is not needed).
///
/// \param f The formula to normalize.
/// \param negated If \c true, return the negative normal form of
/// \c !f
formula
negative_normal_form(formula f, bool negated = false); negative_normal_form(formula f, bool negated = false);
/// \brief Syntactic implication. /// \brief Syntactic implication.
/// ///
/// Returns whether \a f syntactically implies \a g. /// Returns whether \a f syntactically implies \a g.
/// ///
/// This is adapted from /// This is adapted from
/** \verbatim /** \verbatim
@InProceedings{ somenzi.00.cav, @InProceedings{ somenzi.00.cav,
author = {Fabio Somenzi and Roderick Bloem}, author = {Fabio Somenzi and Roderick Bloem},
title = {Efficient {B\"u}chi Automata for {LTL} Formulae}, title = {Efficient {B\"u}chi Automata for {LTL} Formulae},
booktitle = {Proceedings of the 12th International Conference on booktitle = {Proceedings of the 12th International Conference on
Computer Aided Verification (CAV'00)}, Computer Aided Verification (CAV'00)},
pages = {247--263}, pages = {247--263},
year = {2000}, year = {2000},
volume = {1855}, volume = {1855},
series = {Lecture Notes in Computer Science}, series = {Lecture Notes in Computer Science},
publisher = {Springer-Verlag} publisher = {Springer-Verlag}
} }
\endverbatim */ \endverbatim */
/// ///
bool syntactic_implication(formula f, formula g); bool syntactic_implication(formula f, formula g);
/// \brief Syntactic implication with one negated argument. /// \brief Syntactic implication with one negated argument.
/// ///
/// If \a right is true, this method returns whether /// If \a right is true, this method returns whether
/// \a f implies !\a g. If \a right is false, this returns /// \a f implies !\a g. If \a right is false, this returns
/// whether !\a f implies \a g. /// whether !\a f implies \a g.
bool syntactic_implication_neg(formula f, formula g, bool syntactic_implication_neg(formula f, formula g,
bool right); bool right);
/// \brief check whether two formulae are equivalent. /// \brief check whether two formulae are equivalent.
/// ///
/// This costly check performs up to four translations, /// This costly check performs up to four translations,
/// two products, and two emptiness checks. /// two products, and two emptiness checks.
bool are_equivalent(formula f, formula g); bool are_equivalent(formula f, formula g);
/// \brief Check whether \a f implies \a g. /// \brief Check whether \a f implies \a g.
/// ///
/// This operation is costlier than syntactic_implication() /// This operation is costlier than syntactic_implication()
/// because it requires two translation, one product and one /// because it requires two translation, one product and one
/// emptiness check. /// emptiness check.
bool implication(formula f, formula g); bool implication(formula f, formula g);
/// \brief Convert a Boolean formula as a BDD. /// \brief Convert a Boolean formula as a BDD.
/// ///
/// If you plan to use this method, be sure to pass a bdd_dict /// If you plan to use this method, be sure to pass a bdd_dict
/// to the constructor. /// to the constructor.
bdd as_bdd(formula f); bdd as_bdd(formula f);
/// \brief Clear the as_bdd() cache. /// \brief Clear the as_bdd() cache.
/// ///
/// Calling this function is recommended before running other /// Calling this function is recommended before running other
/// algorithms that create BDD variables in a more natural /// algorithms that create BDD variables in a more natural
/// order. For instance ltl_to_tgba_fm() will usually be more /// order. For instance ltl_to_tgba_fm() will usually be more
/// efficient if the BDD variables for atomic propositions have /// efficient if the BDD variables for atomic propositions have
/// not been ordered before hand. /// not been ordered before hand.
/// ///
/// This also clears the language containment cache. /// This also clears the language containment cache.
void clear_as_bdd_cache(); void clear_as_bdd_cache();
/// Return the bdd_dict used. /// Return the bdd_dict used.
bdd_dict_ptr get_dict() const; bdd_dict_ptr get_dict() const;
/// Cached version of spot::ltl::star_normal_form(). /// Cached version of spot::star_normal_form().
formula star_normal_form(formula f); formula star_normal_form(formula f);
/// \brief Rewrite a Boolean formula \a f into as an irredundant /// \brief Rewrite a Boolean formula \a f into as an irredundant
/// sum of product. /// sum of product.
/// ///
/// This uses a cache, so it is OK to call this with identical /// This uses a cache, so it is OK to call this with identical
/// arguments. /// arguments.
formula boolean_to_isop(formula f); formula boolean_to_isop(formula f);
/// Dump statistics about the caches. /// Dump statistics about the caches.
void print_stats(std::ostream& os) const; void print_stats(std::ostream& os) const;
private: private:
ltl_simplifier_cache* cache_; ltl_simplifier_cache* cache_;
// Copy disallowed. // Copy disallowed.
ltl_simplifier(const ltl_simplifier&) SPOT_DELETED; ltl_simplifier(const ltl_simplifier&) SPOT_DELETED;
void operator=(const ltl_simplifier&) SPOT_DELETED; void operator=(const ltl_simplifier&) SPOT_DELETED;
}; };
}
} }

View file

@ -21,129 +21,125 @@
namespace spot namespace spot
{ {
namespace ltl namespace
{ {
namespace // E° if bounded=false
// E^□ if nounded=true
template<bool bounded>
class snf_visitor
{ {
// E° if bounded=false protected:
// E^□ if nounded=true formula result_;
template<bool bounded> snf_cache* cache_;
class snf_visitor public:
snf_visitor(snf_cache* c)
: cache_(c)
{ {
protected: }
formula result_;
snf_cache* cache_;
public:
snf_visitor(snf_cache* c)
: cache_(c)
{
}
formula visit(formula f) formula visit(formula f)
{ {
if (!f.accepts_eword()) if (!f.accepts_eword())
return f; return f;
snf_cache::const_iterator i = cache_->find(f); snf_cache::const_iterator i = cache_->find(f);
if (i != cache_->end()) if (i != cache_->end())
return i->second; return i->second;
formula out; formula out;
switch (f.kind()) switch (f.kind())
{ {
case op::eword: case op::eword:
out = formula::ff(); out = formula::ff();
break; break;
case op::Star: case op::Star:
if (!bounded) if (!bounded)
out = visit(f[0]); // Strip the star. out = visit(f[0]); // Strip the star.
else else
out = formula::Star(visit(f[0]), out = formula::Star(visit(f[0]),
std::max(unsigned(f.min()), 1U), f.max()); std::max(unsigned(f.min()), 1U), f.max());
break; break;
case op::Concat: case op::Concat:
if (bounded) if (bounded)
{
out = f;
break;
}
// Fall through
case op::OrRat:
case op::AndNLM:
// Let F designate expressions that accept [*0],
// and G designate expressions that do not.
// (G₁;G₂;G₃)° = G₁;G₂;G₃
// (G₁;F₂;G₃)° = (G₁°);F₂;(G₃°) = G₁;F₂;G₃
// because there is nothing to do recursively on a G.
//
// AndNLM can be dealt with similarly.
//
// The above cases are already handled by the
// accepts_eword() tests at the top of this method. So
// we reach this switch, we only have to deal with...
//
// (F₁;F₂;F₃)° = (F₁°)|(F₂°)|(F₃°)
// (F₁&F₂&F₃)° = (F₁°)|(F₂°)|(F₃°)
// (F₁|G₂|F₃)° = (F₁°)|(G₂°)|(F₃°)
{ {
unsigned s = f.size(); out = f;
std::vector<formula> v;
v.reserve(s);
for (unsigned pos = 0; pos < s; ++pos)
v.emplace_back(visit(f[pos]));
out = formula::OrRat(v);
break; break;
} }
case op::ff: // Fall through
case op::tt: case op::OrRat:
case op::ap: case op::AndNLM:
case op::Not: // Let F designate expressions that accept [*0],
case op::X: // and G designate expressions that do not.
case op::F:
case op::G: // (G₁;G₂;G₃)° = G₁;G₂;G₃
case op::Closure: // (G₁;F₂;G₃)° = (G₁°);F₂;(G₃°) = G₁;F₂;G₃
case op::NegClosure: // because there is nothing to do recursively on a G.
case op::NegClosureMarked: //
case op::Xor: // AndNLM can be dealt with similarly.
case op::Implies: //
case op::Equiv: // The above cases are already handled by the
case op::U: // accepts_eword() tests at the top of this method. So
case op::R: // we reach this switch, we only have to deal with...
case op::W: //
case op::M: // (F₁;F₂;F₃)° = (F₁°)|(F₂°)|(F₃°)
case op::EConcat: // (F₁&F₂&F₃)° = (F₁°)|(F₂°)|(F₃°)
case op::EConcatMarked: // (F₁|G₂|F₃)° = (F₁°)|(G₂°)|(F₃°)
case op::UConcat: {
case op::Fusion: unsigned s = f.size();
case op::Or: std::vector<formula> v;
case op::And: v.reserve(s);
SPOT_UNREACHABLE(); for (unsigned pos = 0; pos < s; ++pos)
case op::AndRat: // Can AndRat be handled better? v.emplace_back(visit(f[pos]));
case op::FStar: // Can FStar be handled better? out = formula::OrRat(v);
out = f;
break; break;
} }
case op::ff:
case op::tt:
case op::ap:
case op::Not:
case op::X:
case op::F:
case op::G:
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::Xor:
case op::Implies:
case op::Equiv:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
case op::Fusion:
case op::Or:
case op::And:
SPOT_UNREACHABLE();
case op::AndRat: // Can AndRat be handled better?
case op::FStar: // Can FStar be handled better?
out = f;
break;
}
return (*cache_)[f] = out; return (*cache_)[f] = out;
} }
}; };
} }
formula formula
star_normal_form(formula sere, snf_cache* cache) star_normal_form(formula sere, snf_cache* cache)
{ {
snf_visitor<false> v(cache); snf_visitor<false> v(cache);
return v.visit(sere); return v.visit(sere);
} }
formula
star_normal_form_bounded(formula sere, snf_cache* cache)
{
snf_visitor<true> v(cache);
return v.visit(sere);
}
formula
star_normal_form_bounded(formula sere, snf_cache* cache)
{
snf_visitor<true> v(cache);
return v.visit(sere);
} }
} }

View file

@ -24,35 +24,31 @@
namespace spot namespace spot
{ {
namespace ltl typedef std::unordered_map<formula, formula> snf_cache;
{
typedef std::unordered_map<formula, formula> snf_cache; /// Helper to rewrite a sere in Star Normal Form.
///
/// This should only be called on children of a Star operator. It
/// corresponds to the E° operation defined in the following
/// paper.
///
/** \verbatim
@Article{ bruggeman.96.tcs,
author = {Anne Br{\"u}ggemann-Klein},
title = {Regular Expressions into Finite Automata},
journal = {Theoretical Computer Science},
year = {1996},
volume = {120},
pages = {87--98}
}
\endverbatim */
///
/// \param sere the SERE to rewrite
/// \param cache an optional cache
SPOT_API formula
star_normal_form(formula sere, snf_cache* cache = nullptr);
/// Helper to rewrite a sere in Star Normal Form. /// A variant of star_normal_form() for r[*0..j] where j < ω.
/// SPOT_API formula
/// This should only be called on children of a Star operator. It star_normal_form_bounded(formula sere, snf_cache* cache = nullptr);
/// corresponds to the E° operation defined in the following
/// paper.
///
/** \verbatim
@Article{ bruggeman.96.tcs,
author = {Anne Br{\"u}ggemann-Klein},
title = {Regular Expressions into Finite Automata},
journal = {Theoretical Computer Science},
year = {1996},
volume = {120},
pages = {87--98}
}
\endverbatim */
///
/// \param sere the SERE to rewrite
/// \param cache an optional cache
SPOT_API formula
star_normal_form(formula sere, snf_cache* cache = nullptr);
/// A variant of star_normal_form() for r[*0..j] where j < ω.
SPOT_API formula
star_normal_form_bounded(formula sere, snf_cache* cache = nullptr);
}
} }

View file

@ -22,232 +22,229 @@
namespace spot namespace spot
{ {
namespace ltl unabbreviator::unabbreviator(const char* opt)
{ {
unabbreviator::unabbreviator(const char* opt) while (*opt)
{ switch (char c = *opt++)
while (*opt) {
switch (char c = *opt++) case 'e':
re_e_ = true;
re_some_bool_ = true;
break;
case 'F':
re_f_ = true;
re_some_f_g_ = true;
break;
case 'G':
re_g_ = true;
re_some_f_g_ = true;
break;
case 'i':
re_i_ = true;
re_some_bool_ = true;
break;
case 'M':
re_m_ = true;
re_some_other_ = true;
break;
case 'R':
re_r_ = true;
re_some_other_ = true;
break;
case 'W':
re_w_ = true;
re_some_other_ = true;
break;
case '^':
re_xor_ = true;
re_some_bool_ = true;
break;
default:
throw std::runtime_error
(std::string("unknown unabbreviation option: ")
+ c);
}
}
formula unabbreviator::run(formula in)
{
auto entry = cache_.emplace(in, nullptr);
if (!entry.second)
return entry.first->second;
// Skip recursion whenever possible
bool no_boolean_rewrite = !re_some_bool_ || in.is_sugar_free_boolean();
bool no_f_g_rewrite = !re_some_f_g_ || in.is_sugar_free_ltl();
if (no_boolean_rewrite
&& (in.is_boolean() || (no_f_g_rewrite && !re_some_other_)))
return entry.first->second = in;
auto rec = [this](formula f)
{
return this->run(f);
};
formula out = in;
if (in.size() > 0)
out = in.map(rec);
switch (out.kind())
{
case op::ff:
case op::tt:
case op::eword:
case op::ap:
case op::Not:
case op::X:
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
case op::U:
case op::Or:
case op::OrRat:
case op::And:
case op::AndRat:
case op::AndNLM:
case op::Concat:
case op::Fusion:
case op::Star:
case op::FStar:
break;
case op::F:
// F f = true U f
if (!re_f_)
break;
out = formula::U(formula::tt(), out[0]);
break;
case op::G:
// G f = false R f
// G f = f W false
// G f = !F!f
// G f = !(true U !f)
if (!re_g_)
break;
if (!re_r_)
{ {
case 'e': out = formula::R(formula::ff(), out[0]);
re_e_ = true; break;
re_some_bool_ = true; }
if (!re_w_)
{
out = formula::W(out[0], formula::ff());
break; break;
case 'F':
re_f_ = true;
re_some_f_g_ = true;
break;
case 'G':
re_g_ = true;
re_some_f_g_ = true;
break;
case 'i':
re_i_ = true;
re_some_bool_ = true;
break;
case 'M':
re_m_ = true;
re_some_other_ = true;
break;
case 'R':
re_r_ = true;
re_some_other_ = true;
break;
case 'W':
re_w_ = true;
re_some_other_ = true;
break;
case '^':
re_xor_ = true;
re_some_bool_ = true;
break;
default:
throw std::runtime_error
(std::string("unknown unabbreviation option: ")
+ c);
} }
}
formula unabbreviator::run(formula in)
{
auto entry = cache_.emplace(in, nullptr);
if (!entry.second)
return entry.first->second;
// Skip recursion whenever possible
bool no_boolean_rewrite = !re_some_bool_ || in.is_sugar_free_boolean();
bool no_f_g_rewrite = !re_some_f_g_ || in.is_sugar_free_ltl();
if (no_boolean_rewrite
&& (in.is_boolean() || (no_f_g_rewrite && !re_some_other_)))
return entry.first->second = in;
auto rec = [this](formula f)
{ {
return this->run(f); auto nc = formula::Not(out[0]);
}; if (!re_f_)
{
formula out = in; out = formula::Not(formula::F(nc));
if (in.size() > 0) break;
out = in.map(rec); }
out = formula::Not(formula::U(formula::tt(), nc));
switch (out.kind()) break;
}
case op::Xor:
// f1 ^ f2 == !(f1 <-> f2)
// f1 ^ f2 == (f1 & !f2) | (f2 & !f1)
if (!re_xor_)
break;
{ {
case op::ff: auto f1 = out[0];
case op::tt: auto f2 = out[1];
case op::eword: if (!re_e_)
case op::ap:
case op::Not:
case op::X:
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
case op::U:
case op::Or:
case op::OrRat:
case op::And:
case op::AndRat:
case op::AndNLM:
case op::Concat:
case op::Fusion:
case op::Star:
case op::FStar:
break;
case op::F:
// F f = true U f
if (!re_f_)
break;
out = formula::U(formula::tt(), out[0]);
break;
case op::G:
// G f = false R f
// G f = f W false
// G f = !F!f
// G f = !(true U !f)
if (!re_g_)
break;
if (!re_r_)
{
out = formula::R(formula::ff(), out[0]);
break;
}
if (!re_w_)
{
out = formula::W(out[0], formula::ff());
break;
}
{ {
auto nc = formula::Not(out[0]); out = formula::Not(formula::Equiv(f1, f2));
if (!re_f_)
{
out = formula::Not(formula::F(nc));
break;
}
out = formula::Not(formula::U(formula::tt(), nc));
break;
} }
case op::Xor: else
// f1 ^ f2 == !(f1 <-> f2)
// f1 ^ f2 == (f1 & !f2) | (f2 & !f1)
if (!re_xor_)
break;
{ {
auto f1 = out[0]; auto a = formula::And({f1, formula::Not(f2)});
auto f2 = out[1]; auto b = formula::And({f2, formula::Not(f1)});
if (!re_e_) out = formula::Or({a, b});
{
out = formula::Not(formula::Equiv(f1, f2));
}
else
{
auto a = formula::And({f1, formula::Not(f2)});
auto b = formula::And({f2, formula::Not(f1)});
out = formula::Or({a, b});
}
}
break;
case op::Implies:
// f1 => f2 == !f1 | f2
if (!re_i_)
break;
out = formula::Or({formula::Not(out[0]), out[1]});
break;
case op::Equiv:
// f1 <=> f2 == (f1 & f2) | (!f1 & !f2)
if (!re_e_)
break;
{
auto f1 = out[0];
auto f2 = out[1];
auto nf1 = formula::Not(f1);
auto nf2 = formula::Not(f2);
auto term1 = formula::And({f1, f2});
auto term2 = formula::And({nf1, nf2});
out = formula::Or({term1, term2});
break;
}
case op::R:
// f1 R f2 = f2 W (f1 & f2)
// f1 R f2 = f2 U ((f1 & f2) | Gf2)
// f1 R f2 = f2 U ((f1 & f2) | !F!f2)
// f1 R f2 = f2 U ((f1 & f2) | !(1 U !f2))
if (!re_r_)
break;
{
auto f1 = out[0];
auto f2 = out[1];
auto f12 = formula::And({f1, f2});
if (!re_w_)
{
out = formula::W(f2, f12);
break;
}
auto gf2 = formula::G(f2);
if (re_g_)
gf2 = run(gf2);
out = formula::U(f2, formula::Or({f12, out}));
break;
}
case op::W:
// f1 W f2 = f2 R (f2 | f1)
// f1 W f2 = f1 U (f2 | G f1)
// f1 W f2 = f1 U (f2 | !F !f1)
// f1 W f2 = f1 U (f2 | !(1 U !f1))
if (!re_w_)
break;
{
auto f1 = out[0];
auto f2 = out[1];
if (!re_r_)
{
out = formula::R(f2, formula::Or({f2, f1}));
break;
}
auto gf1 = formula::G(f1);
if (re_g_)
gf1 = rec(gf1);
out = formula::U(f1, formula::Or({f2, out}));
break;
}
case op::M:
// f1 M f2 = f2 U (g2 & f1)
if (!re_m_)
break;
{
auto f2 = out[1];
out = formula::U(f2, formula::And({f2, out[0]}));
break;
} }
} }
return entry.first->second = out; break;
} case op::Implies:
// f1 => f2 == !f1 | f2
if (!re_i_)
break;
out = formula::Or({formula::Not(out[0]), out[1]});
break;
case op::Equiv:
// f1 <=> f2 == (f1 & f2) | (!f1 & !f2)
if (!re_e_)
break;
{
auto f1 = out[0];
auto f2 = out[1];
auto nf1 = formula::Not(f1);
auto nf2 = formula::Not(f2);
auto term1 = formula::And({f1, f2});
auto term2 = formula::And({nf1, nf2});
out = formula::Or({term1, term2});
break;
}
case op::R:
// f1 R f2 = f2 W (f1 & f2)
// f1 R f2 = f2 U ((f1 & f2) | Gf2)
// f1 R f2 = f2 U ((f1 & f2) | !F!f2)
// f1 R f2 = f2 U ((f1 & f2) | !(1 U !f2))
if (!re_r_)
break;
{
auto f1 = out[0];
auto f2 = out[1];
auto f12 = formula::And({f1, f2});
if (!re_w_)
{
out = formula::W(f2, f12);
break;
}
auto gf2 = formula::G(f2);
if (re_g_)
gf2 = run(gf2);
out = formula::U(f2, formula::Or({f12, out}));
break;
}
case op::W:
// f1 W f2 = f2 R (f2 | f1)
// f1 W f2 = f1 U (f2 | G f1)
// f1 W f2 = f1 U (f2 | !F !f1)
// f1 W f2 = f1 U (f2 | !(1 U !f1))
if (!re_w_)
break;
{
auto f1 = out[0];
auto f2 = out[1];
if (!re_r_)
{
out = formula::R(f2, formula::Or({f2, f1}));
break;
}
auto gf1 = formula::G(f1);
if (re_g_)
gf1 = rec(gf1);
out = formula::U(f1, formula::Or({f2, out}));
break;
}
case op::M:
// f1 M f2 = f2 U (g2 & f1)
if (!re_m_)
break;
{
auto f2 = out[1];
out = formula::U(f2, formula::And({f2, out[0]}));
break;
}
}
return entry.first->second = out;
}
formula unabbreviate(formula in, const char* opt) formula unabbreviate(formula in, const char* opt)
{ {
unabbreviator un(opt); unabbreviator un(opt);
return un.run(in); return un.run(in);
}
} }
} }

Some files were not shown because too many files have changed in this diff Show more