revamp the formula hierarchy (montro-patch)
Flatten the formula ltl::formula hiearchy into a single ltl::vnode that has an enumerator to distinguish the types of node, and a common interface to access children, update reference counts, etc. The ltl::formula class is now a thin wrapper around an ltl::vnode pointer to keep track of reference counts automatically. Visitor are not used anymore; we now have map() and traversor() methods that are more concise. This basically fixes #43, but should be followed by some fine tuning that should now be localized to the formula.hh and formula.cc files. Some statistics about this patch. I started working on it on Sep 9, had a first compiling version two weeks later on Sep 22, and it then took 5 days to fixes the ~70 distincts bugs that were introduced during the conversion. About 13200 lines were modified, and one third of those were removed. * src/ltlast/formula.cc, src/ltlast/formula.hh: Complete rewrite, including what was in separate nearby files. * src/ltlast/allnodes.hh, src/ltlast/atomic_prop.cc, src/ltlast/atomic_prop.hh, src/ltlast/binop.cc, src/ltlast/binop.hh, src/ltlast/bunop.cc, src/ltlast/bunop.hh, src/ltlast/constant.cc, src/ltlast/constant.hh, src/ltlast/multop.cc, src/ltlast/multop.hh, src/ltlast/unop.cc, src/ltlast/unop.hh, src/ltlvisit/dump.cc, src/ltlvisit/dump.hh, src/ltlast/predecl.hh: Delete these files. Their feature have been merged in formula.hh and formula.cc. * src/ltlast/visitor.hh, src/ltlvisit/clone.cc, src/ltlvisit/clone.hh, src/ltlvisit/dump.hh, src/ltlvisit/postfix.cc, src/ltlvisit/postfix.hh: Delete these files, as we do not use visitors anymore. * bench/stutter/stutter_invariance_formulas.cc, bench/stutter/stutter_invariance_randomgraph.cc, doc/org/tut01.org, doc/org/tut02.org, doc/org/tut10.org, doc/org/tut22.org, 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_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/ltlast/Makefile.am, src/ltlenv/declenv.cc, src/ltlenv/declenv.hh, src/ltlenv/defaultenv.cc, src/ltlenv/defaultenv.hh, src/ltlenv/environment.hh, src/ltlparse/ltlparse.yy, src/ltlparse/public.hh, src/ltlvisit/Makefile.am, src/ltlvisit/apcollect.cc, src/ltlvisit/apcollect.hh, src/ltlvisit/contain.cc, src/ltlvisit/contain.hh, src/ltlvisit/dot.cc, src/ltlvisit/dot.hh, src/ltlvisit/exclusive.cc, src/ltlvisit/exclusive.hh, src/ltlvisit/length.cc, src/ltlvisit/length.hh, src/ltlvisit/mark.cc, src/ltlvisit/mark.hh, src/ltlvisit/mutation.cc, src/ltlvisit/mutation.hh, src/ltlvisit/nenoform.cc, src/ltlvisit/nenoform.hh, src/ltlvisit/print.cc, src/ltlvisit/print.hh, src/ltlvisit/randomltl.cc, src/ltlvisit/randomltl.hh, src/ltlvisit/relabel.cc, src/ltlvisit/relabel.hh, src/ltlvisit/remove_x.cc, src/ltlvisit/remove_x.hh, src/ltlvisit/simpfg.cc, src/ltlvisit/simpfg.hh, src/ltlvisit/simplify.cc, src/ltlvisit/simplify.hh, src/ltlvisit/snf.cc, src/ltlvisit/snf.hh, src/ltlvisit/unabbrev.cc, src/ltlvisit/unabbrev.hh, src/parseaut/parseaut.yy, src/ta/taexplicit.cc, src/ta/tgtaexplicit.cc, src/taalgos/minimize.cc, src/taalgos/tgba2ta.cc, src/tests/bare.test, 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/isop.test, src/tests/kind.cc, src/tests/length.cc, src/tests/ltldo.test, src/tests/ltlfilt.test, src/tests/ltlgrind.test, src/tests/ltlprod.cc, src/tests/ltlrel.cc, src/tests/parse_print_test.cc, src/tests/parseaut.test, src/tests/parseerr.test, 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/twagraph.cc, src/tests/utf8.test, src/twa/acc.cc, 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.cc, src/twa/twa.hh src/twa/twagraph.cc, src/twa/twagraph.hh, src/twa/twasafracomplement.cc, src/twaalgos/compsusp.cc, src/twaalgos/compsusp.hh, src/twaalgos/dtgbasat.cc, src/twaalgos/hoa.cc, src/twaalgos/lbtt.cc, 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/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/ajax/spotcgi.in, wrap/python/spot.py, wrap/python/spot_impl.i, wrap/python/Makefile.am, wrap/python/tests/automata-io.ipynb, wrap/python/tests/formulas.ipynb, wrap/python/tests/ltl2tgba.py, wrap/python/tests/ltlparse.py, wrap/python/tests/ltlsimple.py, wrap/python/tests/randltl.ipynb: Adjust to use the new interface. * src/sanity/style.test: Accept more C++11 patterns. * NEWS: Mention the change.
This commit is contained in:
parent
1628b188fe
commit
b77f7e24c3
177 changed files with 8295 additions and 13332 deletions
18
NEWS
18
NEWS
|
|
@ -15,6 +15,24 @@ New in spot 1.99.3a (not yet released)
|
||||||
(But dstar2tgba does not offer all the filtering and
|
(But dstar2tgba does not offer all the filtering and
|
||||||
transformations options of autfilt.)
|
transformations options of autfilt.)
|
||||||
|
|
||||||
|
* The class hierarchy for temporal formulas has been entirely
|
||||||
|
rewritten. This change is actually quite massive (~13200 lines
|
||||||
|
removed, ~8200 lines added), and brings some nice benefits:
|
||||||
|
- LTL/PSL formulas are now represented by lightweight
|
||||||
|
ltl::formula objects (instead of ltl::formula* pointers)
|
||||||
|
that perform reference counting automatically.
|
||||||
|
- There is no hierachy anymore: all operators are represented
|
||||||
|
by a single type of node in the syntax tree, and an
|
||||||
|
enumerator is used to distinguish between operators.
|
||||||
|
- Visitors have been replaced by member functions such
|
||||||
|
as map() or traverse(), that take a function (usually
|
||||||
|
written as a lambda function) and apply it to the
|
||||||
|
nodes of the tree.
|
||||||
|
- As a consequence, writing algorithms that manipulate
|
||||||
|
formula is more friendly, and several functions
|
||||||
|
algorithms that spanned a few pages have been
|
||||||
|
reduced to a few lines.
|
||||||
|
|
||||||
New in spot 1.99.3 (2015-08-26)
|
New in spot 1.99.3 (2015-08-26)
|
||||||
|
|
||||||
* The CGI script for LTL translation offers a HOA download link
|
* The CGI script for LTL translation offers a HOA download link
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
#include "twaalgos/stutter.hh"
|
#include "twaalgos/stutter.hh"
|
||||||
#include "twaalgos/dupexp.hh"
|
#include "twaalgos/dupexp.hh"
|
||||||
#include "twaalgos/stats.hh"
|
#include "twaalgos/stats.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "ltlvisit/apcollect.hh"
|
#include "ltlvisit/apcollect.hh"
|
||||||
#include "ltlvisit/length.hh"
|
#include "ltlvisit/length.hh"
|
||||||
#include "misc/timer.hh"
|
#include "misc/timer.hh"
|
||||||
|
|
@ -64,14 +63,10 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula* f,
|
process_formula(spot::ltl::formula f, const char*, int)
|
||||||
const char*, int)
|
|
||||||
{
|
{
|
||||||
const spot::ltl::formula* nf =
|
|
||||||
spot::ltl::unop::instance(spot::ltl::unop::Not,
|
|
||||||
f->clone());
|
|
||||||
spot::twa_graph_ptr a = trans.run(f);
|
spot::twa_graph_ptr a = trans.run(f);
|
||||||
spot::twa_graph_ptr na = trans.run(nf);
|
spot::twa_graph_ptr na = trans.run(spot::ltl::formula::Not(f));
|
||||||
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f);
|
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f);
|
||||||
bdd apdict = spot::ltl::atomic_prop_collect_as_bdd(f, a);
|
bdd apdict = spot::ltl::atomic_prop_collect_as_bdd(f, a);
|
||||||
|
|
||||||
|
|
@ -103,9 +98,6 @@ namespace
|
||||||
prev = res;
|
prev = res;
|
||||||
}
|
}
|
||||||
std::cout << prev << '\n';
|
std::cout << prev << '\n';
|
||||||
|
|
||||||
f->destroy();
|
|
||||||
nf->destroy();
|
|
||||||
delete ap;
|
delete ap;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,5 @@ main(int argc, char** argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dict->unregister_all_my_variables(&ap);
|
dict->unregister_all_my_variables(&ap);
|
||||||
spot::ltl::destroy_atomic_prop_set(ap);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,9 @@ exceptions.
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
print_latex_psl(std::cout, spot::ltl::parse_formula("[]<>p0 || <>[]p1")) << '\n';
|
print_latex_psl(std::cout, spot::ltl::parse_formula("[]<>p0 || <>[]p1")) << '\n';
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_formula("& & G p0 p1 p2");
|
spot::ltl::formula f = spot::ltl::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';
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -90,12 +89,6 @@ syntax the output, and the type of formula they can output. Here we
|
||||||
are only using LTL formulas for demonstration, so those three
|
are only using LTL formulas for demonstration, so those three
|
||||||
functions are OK with that.
|
functions are OK with that.
|
||||||
|
|
||||||
Did you notice the calls to =f->destroy()= at the end? The LTL
|
|
||||||
formula objects are implemented as DAG with sharing of subformulas.
|
|
||||||
Each (sub)formula is therefore reference counted, and currently this
|
|
||||||
is done manually by calling =f->clone()= and =f->destroy()= (do not
|
|
||||||
ever =delete= a formula, always call =f->destroy()=).
|
|
||||||
|
|
||||||
We do not recommend using this =parse_formula()= interface because of
|
We do not recommend using this =parse_formula()= interface because of
|
||||||
the potential formulas (like =f= or =t=) that have different meanings
|
the potential formulas (like =f= or =t=) that have different meanings
|
||||||
in the two parsers that are tried.
|
in the two parsers that are tried.
|
||||||
|
|
@ -118,15 +111,10 @@ Here is how to call the infix parser explicitly,:
|
||||||
{
|
{
|
||||||
std::string input = "[]<>p0 || <>[]p1";
|
std::string input = "[]<>p0 || <>[]p1";
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_infix_psl(input, pel);
|
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
||||||
{
|
return 1;
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
print_latex_psl(std::cout, f) << '\n';
|
print_latex_psl(std::cout, f) << '\n';
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -165,14 +153,14 @@ with the "fixed" formula if you wish. Here is an example:
|
||||||
{
|
{
|
||||||
std::string input = "(a U b))";
|
std::string input = "(a U b))";
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_infix_psl(input, pel);
|
spot::ltl::formula f = spot::ltl::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::ltl::format_parse_errors(std::cout, input, pel);
|
||||||
if (f == nullptr)
|
if (f == nullptr)
|
||||||
return 1;
|
return 1;
|
||||||
print_latex_psl(std::cout, f) << '\n';
|
std::cout << "Parsed formula: ";
|
||||||
f->destroy();
|
print_psl(std::cout, f) << '\n';
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -186,7 +174,7 @@ with the "fixed" formula if you wish. Here is an example:
|
||||||
: ^
|
: ^
|
||||||
: ignoring trailing garbage
|
: ignoring trailing garbage
|
||||||
:
|
:
|
||||||
: a \U b
|
: Parsed formula: a U b
|
||||||
|
|
||||||
|
|
||||||
The formula =f= is only returned as null when the parser really cannot
|
The formula =f= is only returned as null when the parser really cannot
|
||||||
|
|
@ -207,16 +195,11 @@ of =parse_infix_psl()=.
|
||||||
{
|
{
|
||||||
std::string input = "& & G p0 p1 p2";
|
std::string input = "& & G p0 p1 p2";
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_prefix_ltl(input, pel);
|
spot::ltl::formula f = spot::ltl::parse_prefix_ltl(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
||||||
{
|
return 1;
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
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';
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -254,15 +237,10 @@ For instance, let's see what happens if a PSL formulas is passed to
|
||||||
{
|
{
|
||||||
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::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_infix_psl(input, pel);
|
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
||||||
{
|
return 1;
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
print_spin_ltl(std::cout, f) << '\n';
|
print_spin_ltl(std::cout, f) << '\n';
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -289,21 +267,15 @@ The first is to simply diagnose non-LTL formulas.
|
||||||
{
|
{
|
||||||
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::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_infix_psl(input, pel);
|
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
||||||
|
return 1;
|
||||||
|
if (!f.is_ltl_formula())
|
||||||
{
|
{
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!f->is_ltl_formula())
|
|
||||||
{
|
|
||||||
f->destroy();
|
|
||||||
std::cerr << "Only LTL formulas are supported.\n";
|
std::cerr << "Only LTL formulas are supported.\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
print_spin_ltl(std::cout, f) << '\n';
|
print_spin_ltl(std::cout, f) << '\n';
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -314,7 +286,7 @@ equivalent LTL formula. This does not always work, so you need to be
|
||||||
prepared to reject the formula any way. In our example, we are lucky
|
prepared to reject the formula any way. In our example, we are lucky
|
||||||
(maybe because it was carefully chosen...):
|
(maybe because it was carefully chosen...):
|
||||||
|
|
||||||
#+BEGIN_SRC C++ :results verbatim :exports code
|
#+BEGIN_SRC C++ :results verbatim :exports both
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "ltlparse/public.hh"
|
#include "ltlparse/public.hh"
|
||||||
|
|
@ -325,28 +297,20 @@ prepared to reject the formula any way. In our example, we are lucky
|
||||||
{
|
{
|
||||||
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::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_infix_psl(input, pel);
|
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
||||||
{
|
return 1;
|
||||||
if (f)
|
if (!f.is_ltl_formula())
|
||||||
f->destroy();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!f->is_ltl_formula())
|
|
||||||
{
|
{
|
||||||
spot::ltl::ltl_simplifier simp;
|
spot::ltl::ltl_simplifier simp;
|
||||||
const formula* g = simp.simplify(f);
|
f = simp.simplify(f);
|
||||||
f->destroy();
|
|
||||||
f = g;
|
|
||||||
}
|
}
|
||||||
if (!f->is_ltl_formula())
|
if (!f.is_ltl_formula())
|
||||||
{
|
{
|
||||||
f->destroy();
|
|
||||||
std::cerr << "Only LTL formulas are supported.\n";
|
std::cerr << "Only LTL formulas are supported.\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
print_spin_ltl(std::cout, f) << '\n';
|
print_spin_ltl(std::cout, f) << '\n';
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ ltlfilt -ps --relabel=pnn --define -f '"Proc@Here" U ("var > 10" | "var < 4")'
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: #define p0 ((Proc@Here))
|
: #define p0 (Proc@Here)
|
||||||
: #define p1 ((var < 4))
|
: #define p1 (var < 4)
|
||||||
: #define p2 ((var > 10))
|
: #define p2 (var > 10)
|
||||||
: (p0) U ((p1) || (p2))
|
: (p0) U ((p1) || (p2))
|
||||||
|
|
||||||
When is this output interesting, you may ask? It is useful for
|
When is this output interesting, you may ask? It is useful for
|
||||||
|
|
@ -34,9 +34,9 @@ rm tmp.defs tmp.ltl
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
#+begin_example
|
#+begin_example
|
||||||
#define p0 ((Proc@Here))
|
#define p0 (Proc@Here)
|
||||||
#define p1 ((var < 4))
|
#define p1 (var < 4)
|
||||||
#define p2 ((var > 10))
|
#define p2 (var > 10)
|
||||||
never { /* (p0) U ((p1) || (p2))
|
never { /* (p0) U ((p1) || (p2))
|
||||||
*/
|
*/
|
||||||
T0_init:
|
T0_init:
|
||||||
|
|
@ -88,32 +88,26 @@ destructor.
|
||||||
{
|
{
|
||||||
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::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_infix_psl(input, pel);
|
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
||||||
{
|
return 1;
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
spot::ltl::relabeling_map m;
|
spot::ltl::relabeling_map m;
|
||||||
const spot::ltl::formula* g = spot::ltl::relabel(f, spot::ltl::Pnn, &m);
|
f = spot::ltl::relabel(f, spot::ltl::Pnn, &m);
|
||||||
for (auto& i: m)
|
for (auto& i: m)
|
||||||
{
|
{
|
||||||
std::cout << "#define ";
|
std::cout << "#define ";
|
||||||
print_psl(std::cout, i.first) << " (";
|
print_psl(std::cout, i.first) << " (";
|
||||||
print_spin_ltl(std::cout, i.second, true) << ")\n";
|
print_spin_ltl(std::cout, i.second, true) << ")\n";
|
||||||
}
|
}
|
||||||
print_spin_ltl(std::cout, g, true) << '\n';
|
print_spin_ltl(std::cout, f, true) << '\n';
|
||||||
g->destroy();
|
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: #define p0 ((Proc@Here))
|
: #define p0 (Proc@Here)
|
||||||
: #define p1 ((var < 4))
|
: #define p1 (var < 4)
|
||||||
: #define p2 ((var > 10))
|
: #define p2 (var > 10)
|
||||||
: (p0) U ((p1) || (p2))
|
: (p0) U ((p1) || (p2))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -135,7 +129,7 @@ ltlfilt -ps --relabel-bool=pnn --define -f '"Proc@Here" U ("var > 10" | "var < 4
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: #define p0 ((Proc@Here))
|
: #define p0 (Proc@Here)
|
||||||
: #define p1 ((var < 4) || (var > 10))
|
: #define p1 ((var < 4) || (var > 10))
|
||||||
: (p0) U (p1)
|
: (p0) U (p1)
|
||||||
|
|
||||||
|
|
@ -151,8 +145,8 @@ ltlfilt -ps --relabel-bool=pnn --define -f 'a U (a & b)'
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: #define p0 ((a))
|
: #define p0 (a)
|
||||||
: #define p1 ((b))
|
: #define p1 (b)
|
||||||
: (p0) U ((p0) && (p1))
|
: (p0) U ((p0) && (p1))
|
||||||
|
|
||||||
This "Boolean sub-expression" relabeling is available in Python and
|
This "Boolean sub-expression" relabeling is available in Python and
|
||||||
|
|
|
||||||
|
|
@ -138,18 +138,13 @@ never claim is done via the =print_never_claim= function.
|
||||||
{
|
{
|
||||||
std::string input = "[]<>p0 || <>[]p1";
|
std::string input = "[]<>p0 || <>[]p1";
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = spot::ltl::parse_infix_psl(input, pel);
|
spot::ltl::formula f = spot::ltl::parse_infix_psl(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
||||||
{
|
return 1;
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
spot::translator trans;
|
spot::translator trans;
|
||||||
trans.set_type(spot::postprocessor::BA);
|
trans.set_type(spot::postprocessor::BA);
|
||||||
spot::twa_graph_ptr aut = trans.run(f);
|
spot::twa_graph_ptr aut = trans.run(f);
|
||||||
print_never_claim(std::cout, aut) << '\n';
|
print_never_claim(std::cout, aut) << '\n';
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
#+HTML_LINK_UP: tut.html
|
#+HTML_LINK_UP: tut.html
|
||||||
|
|
||||||
This example demonstrates how to create an automaton in C++, and then print it.
|
This example demonstrates how to create an automaton in C++, and then print it.
|
||||||
The interface
|
|
||||||
|
|
||||||
#+BEGIN_SRC C++ :results verbatim :exports both
|
#+BEGIN_SRC C++ :results verbatim :exports both
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2011, 2012, 2014 Laboratoire de Recherche et Développement
|
// Copyright (C) 2011, 2012, 2014, 2015 Laboratoire de Recherche et
|
||||||
// de l'Epita (LRDE)
|
// Développement de l'Epita (LRDE)
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -326,7 +326,7 @@ namespace spot
|
||||||
convert_aps(const ltl::atomic_prop_set* aps,
|
convert_aps(const ltl::atomic_prop_set* aps,
|
||||||
const spins_interface* d,
|
const spins_interface* d,
|
||||||
bdd_dict_ptr dict,
|
bdd_dict_ptr dict,
|
||||||
const ltl::formula* dead,
|
ltl::formula dead,
|
||||||
prop_set& out)
|
prop_set& out)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
@ -359,7 +359,7 @@ namespace spot
|
||||||
if (*ap == dead)
|
if (*ap == dead)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string str = (*ap)->name();
|
const std::string& str = ap->ap_name();
|
||||||
const char* s = str.c_str();
|
const char* s = str.c_str();
|
||||||
|
|
||||||
// Skip any leading blank.
|
// Skip any leading blank.
|
||||||
|
|
@ -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, const ltl::formula* dead,
|
const spot::prop_set* ps, ltl::formula dead,
|
||||||
int compress)
|
int compress)
|
||||||
: kripke(dict),
|
: kripke(dict),
|
||||||
d_(d),
|
d_(d),
|
||||||
|
|
@ -646,12 +646,12 @@ namespace spot
|
||||||
// appropriately. ALIVE_PROP is the bdd that should be ANDed
|
// appropriately. ALIVE_PROP is the bdd that should be ANDed
|
||||||
// to all transitions leaving a live state, while DEAD_PROP should
|
// to all transitions leaving a live state, while DEAD_PROP should
|
||||||
// be ANDed to all transitions leaving a dead state.
|
// be ANDed to all transitions leaving a dead state.
|
||||||
if (dead == ltl::constant::false_instance())
|
if (dead.is_false())
|
||||||
{
|
{
|
||||||
alive_prop = bddtrue;
|
alive_prop = bddtrue;
|
||||||
dead_prop = bddfalse;
|
dead_prop = bddfalse;
|
||||||
}
|
}
|
||||||
else if (dead == ltl::constant::true_instance())
|
else if (dead.is_true())
|
||||||
{
|
{
|
||||||
alive_prop = bddtrue;
|
alive_prop = bddtrue;
|
||||||
dead_prop = bddtrue;
|
dead_prop = bddtrue;
|
||||||
|
|
@ -1016,7 +1016,7 @@ 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 ltl::atomic_prop_set* to_observe,
|
||||||
const ltl::formula* dead, int compress, bool verbose)
|
const ltl::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)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2011, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2011, 2013, 2014, 2015 Laboratoire de Recherche et
|
||||||
// Developpement de l'Epita (LRDE)
|
// Developpement de l'Epita (LRDE)
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include "kripke/kripke.hh"
|
#include "kripke/kripke.hh"
|
||||||
#include "ltlvisit/apcollect.hh"
|
#include "ltlvisit/apcollect.hh"
|
||||||
#include "ltlast/constant.hh"
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -59,6 +58,6 @@ namespace spot
|
||||||
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 ltl::atomic_prop_set* to_observe,
|
||||||
const ltl::formula* dead = ltl::constant::true_instance(),
|
ltl::formula dead = ltl::formula::tt(),
|
||||||
int compress = 0, bool verbose = true);
|
int compress = 0, bool verbose = true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
#include "ltsmin.hh"
|
#include "ltsmin.hh"
|
||||||
#include "twaalgos/dot.hh"
|
#include "twaalgos/dot.hh"
|
||||||
#include "ltlenv/defaultenv.hh"
|
#include "ltlenv/defaultenv.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "ltlparse/public.hh"
|
#include "ltlparse/public.hh"
|
||||||
#include "twaalgos/translate.hh"
|
#include "twaalgos/translate.hh"
|
||||||
#include "twaalgos/emptiness.hh"
|
#include "twaalgos/emptiness.hh"
|
||||||
|
|
@ -163,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;
|
||||||
const spot::ltl::formula* deadf = nullptr;
|
spot::ltl::formula deadf = nullptr;
|
||||||
const spot::ltl::formula* f = nullptr;
|
spot::ltl::formula f = nullptr;
|
||||||
|
|
||||||
if (!dead || !strcasecmp(dead, "true"))
|
if (!dead || !strcasecmp(dead, "true"))
|
||||||
{
|
{
|
||||||
deadf = spot::ltl::constant::true_instance();
|
deadf = spot::ltl::formula::tt();
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(dead, "false"))
|
else if (!strcasecmp(dead, "false"))
|
||||||
{
|
{
|
||||||
deadf = spot::ltl::constant::false_instance();
|
deadf = spot::ltl::formula::ff();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -355,11 +354,6 @@ checked_main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
safe_exit:
|
safe_exit:
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
|
|
||||||
deadf->destroy();
|
|
||||||
|
|
||||||
if (use_timer)
|
if (use_timer)
|
||||||
tm.print(std::cout);
|
tm.print(std::cout);
|
||||||
tm.reset_all(); // This helps valgrind.
|
tm.reset_all(); // This helps valgrind.
|
||||||
|
|
@ -372,15 +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.
|
||||||
spot::ltl::atomic_prop::dump_instances(std::cerr);
|
assert(spot::ltl::fnode::instances_check());
|
||||||
spot::ltl::unop::dump_instances(std::cerr);
|
|
||||||
spot::ltl::binop::dump_instances(std::cerr);
|
|
||||||
spot::ltl::multop::dump_instances(std::cerr);
|
|
||||||
spot::ltl::bunop::dump_instances(std::cerr);
|
|
||||||
assert(spot::ltl::atomic_prop::instance_count() == 0);
|
|
||||||
assert(spot::ltl::unop::instance_count() == 0);
|
|
||||||
assert(spot::ltl::binop::instance_count() == 0);
|
|
||||||
assert(spot::ltl::multop::instance_count() == 0);
|
|
||||||
assert(spot::ltl::bunop::instance_count() == 0);
|
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -487,7 +487,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula*, const char*, int)
|
process_formula(spot::ltl::formula, const char*, int)
|
||||||
{
|
{
|
||||||
SPOT_UNREACHABLE();
|
SPOT_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,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,
|
||||||
const spot::ltl::formula* f,
|
spot::ltl::formula f,
|
||||||
// Input location for errors and statistics.
|
// Input location for errors and statistics.
|
||||||
const char* filename,
|
const char* filename,
|
||||||
int loc,
|
int loc,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
const spot::ltl::formula* f,
|
spot::ltl::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,
|
||||||
const spot::ltl::formula* f = nullptr,
|
spot::ltl::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,
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ parse_opt_finput(int key, char* arg, struct argp_state*)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const spot::ltl::formula*
|
spot::ltl::formula
|
||||||
parse_formula(const std::string& s, spot::ltl::parse_error_list& pel)
|
parse_formula(const std::string& s, spot::ltl::parse_error_list& pel)
|
||||||
{
|
{
|
||||||
if (lbt_input)
|
if (lbt_input)
|
||||||
|
|
@ -108,15 +108,13 @@ job_processor::process_string(const std::string& input,
|
||||||
int linenum)
|
int linenum)
|
||||||
{
|
{
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* 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::ltl::format_parse_errors(std::cerr, input, pel);
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return process_formula(f, filename, linenum);
|
return process_formula(f, filename, linenum);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Développement
|
// Copyright (C) 2012, 2013, 2015 Laboratoire de Recherche et
|
||||||
// de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -44,7 +44,7 @@ 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);
|
||||||
|
|
||||||
const spot::ltl::formula*
|
spot::ltl::formula
|
||||||
parse_formula(const std::string& s, spot::ltl::parse_error_list& error_list);
|
parse_formula(const std::string& s, spot::ltl::parse_error_list& error_list);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ public:
|
||||||
virtual ~job_processor();
|
virtual ~job_processor();
|
||||||
|
|
||||||
virtual int
|
virtual int
|
||||||
process_formula(const spot::ltl::formula* f,
|
process_formula(spot::ltl::formula f,
|
||||||
const char* filename = 0, int linenum = 0) = 0;
|
const char* filename = 0, int linenum = 0) = 0;
|
||||||
|
|
||||||
virtual int
|
virtual int
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ const struct argp output_argp = { options, parse_opt_output, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
report_not_ltl(const spot::ltl::formula* f,
|
report_not_ltl(spot::ltl::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::ltl::str_psl(f);
|
||||||
|
|
@ -82,12 +82,12 @@ report_not_ltl(const spot::ltl::formula* f,
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
stream_formula(std::ostream& out,
|
stream_formula(std::ostream& out,
|
||||||
const spot::ltl::formula* f, const char* filename, int linenum)
|
spot::ltl::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::ltl::print_lbt_ltl(out, f);
|
||||||
else
|
else
|
||||||
report_not_ltl(f, filename, linenum, "LBT");
|
report_not_ltl(f, filename, linenum, "LBT");
|
||||||
|
|
@ -96,13 +96,13 @@ stream_formula(std::ostream& out,
|
||||||
spot::ltl::print_psl(out, f, full_parenth);
|
spot::ltl::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::ltl::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::ltl::print_wring_ltl(out, f);
|
||||||
else
|
else
|
||||||
report_not_ltl(f, filename, linenum, "Wring");
|
report_not_ltl(f, filename, linenum, "Wring");
|
||||||
|
|
@ -122,7 +122,7 @@ stream_formula(std::ostream& out,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stream_escapable_formula(std::ostream& os,
|
stream_escapable_formula(std::ostream& os,
|
||||||
const spot::ltl::formula* f,
|
spot::ltl::formula f,
|
||||||
const char* filename, int linenum)
|
const char* filename, int linenum)
|
||||||
{
|
{
|
||||||
if (escape_csv)
|
if (escape_csv)
|
||||||
|
|
@ -144,7 +144,7 @@ namespace
|
||||||
{
|
{
|
||||||
struct formula_with_location
|
struct formula_with_location
|
||||||
{
|
{
|
||||||
const spot::ltl::formula* f;
|
spot::ltl::formula f;
|
||||||
const char* filename;
|
const char* filename;
|
||||||
int line;
|
int line;
|
||||||
const char* prefix;
|
const char* prefix;
|
||||||
|
|
@ -258,7 +258,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,
|
||||||
const spot::ltl::formula* f,
|
spot::ltl::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)
|
||||||
{
|
{
|
||||||
|
|
@ -284,7 +284,7 @@ void
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
output_formula_checked(const spot::ltl::formula* f,
|
output_formula_checked(spot::ltl::formula f,
|
||||||
const char* filename, int linenum,
|
const char* filename, int linenum,
|
||||||
const char* prefix, const char* suffix)
|
const char* prefix, const char* suffix)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,19 @@ 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,
|
||||||
const spot::ltl::formula* f, const char* filename, int linenum);
|
spot::ltl::formula f, const char* filename, int linenum);
|
||||||
|
|
||||||
void output_formula_checked(const spot::ltl::formula* f,
|
void output_formula_checked(spot::ltl::formula f,
|
||||||
const char* filename = 0, int linenum = 0,
|
const char* filename = 0, int linenum = 0,
|
||||||
const char* prefix = 0, const char* suffix = 0);
|
const char* prefix = 0, const char* suffix = 0);
|
||||||
|
|
||||||
|
|
||||||
class printable_formula:
|
class printable_formula:
|
||||||
public spot::printable_value<const spot::ltl::formula*>
|
public spot::printable_value<spot::ltl::formula>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
printable_formula&
|
printable_formula&
|
||||||
operator=(const spot::ltl::formula* new_val)
|
operator=(spot::ltl::formula new_val)
|
||||||
{
|
{
|
||||||
val_ = new_val;
|
val_ = new_val;
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -78,7 +78,7 @@ public:
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
print(const spot::const_twa_graph_ptr& aut,
|
print(const spot::const_twa_graph_ptr& aut,
|
||||||
const spot::ltl::formula* f = 0,
|
spot::ltl::formula f = 0,
|
||||||
double run_time = -1.)
|
double run_time = -1.)
|
||||||
{
|
{
|
||||||
formula_ = f;
|
formula_ = f;
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ translator_runner::formula() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
translator_runner::round_formula(const spot::ltl::formula* f, unsigned serial)
|
translator_runner::round_formula(spot::ltl::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::ltl::str_psl(f, true);
|
||||||
|
|
|
||||||
|
|
@ -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(const spot::ltl::formula* f, unsigned serial);
|
void round_formula(spot::ltl::formula f, unsigned serial);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula*, const char*, int)
|
process_formula(spot::ltl::formula, const char*, int)
|
||||||
{
|
{
|
||||||
SPOT_UNREACHABLE();
|
SPOT_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "ltlast/allnodes.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "ltlenv/defaultenv.hh"
|
|
||||||
#include "ltlvisit/relabel.hh"
|
#include "ltlvisit/relabel.hh"
|
||||||
|
|
||||||
using namespace spot;
|
using namespace spot;
|
||||||
|
|
@ -270,37 +269,31 @@ parse_opt(int key, char* arg, struct argp_state*)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
environment& env(default_environment::instance());
|
#define G_(x) formula::G(x)
|
||||||
|
#define F_(x) formula::F(x)
|
||||||
|
#define X_(x) formula::X(x)
|
||||||
|
#define Not_(x) formula::Not(x)
|
||||||
|
|
||||||
#define G_(x) spot::ltl::unop::instance(spot::ltl::unop::G, (x))
|
#define Implies_(x, y) formula::Implies((x), (y))
|
||||||
#define F_(x) spot::ltl::unop::instance(spot::ltl::unop::F, (x))
|
#define Equiv_(x, y) formula::Equiv((x), (y))
|
||||||
#define X_(x) spot::ltl::unop::instance(spot::ltl::unop::X, (x))
|
#define And_(x, y) formula::And({(x), (y)})
|
||||||
#define Not_(x) spot::ltl::unop::instance(spot::ltl::unop::Not, (x))
|
#define Or_(x, y) formula::Or({(x), (y)})
|
||||||
#define Implies_(x, y) \
|
#define U_(x, y) formula::U((x), (y))
|
||||||
spot::ltl::binop::instance(spot::ltl::binop::Implies, (x), (y))
|
|
||||||
#define Equiv_(x, y) \
|
|
||||||
spot::ltl::binop::instance(spot::ltl::binop::Equiv, (x), (y))
|
|
||||||
#define And_(x, y) \
|
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::And, (x), (y))
|
|
||||||
#define Or_(x, y) \
|
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::Or, (x), (y))
|
|
||||||
#define U_(x, y) \
|
|
||||||
spot::ltl::binop::instance(spot::ltl::binop::U, (x), (y))
|
|
||||||
|
|
||||||
// F(p_1 & F(p_2 & F(p_3 & ... F(p_n))))
|
// F(p_1 & F(p_2 & F(p_3 & ... F(p_n))))
|
||||||
static const formula*
|
static formula
|
||||||
E_n(std::string name, int n)
|
E_n(std::string name, int n)
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return constant::true_instance();
|
return formula::tt();
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
|
|
||||||
for (; n > 0; --n)
|
for (; n > 0; --n)
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << n;
|
p << name << n;
|
||||||
const formula* f = env.require(p.str());
|
formula f = formula::ap(p.str());
|
||||||
if (result)
|
if (result)
|
||||||
result = And_(f, result);
|
result = And_(f, result);
|
||||||
else
|
else
|
||||||
|
|
@ -311,43 +304,43 @@ E_n(std::string name, int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// p & X(p & X(p & ... X(p)))
|
// p & X(p & X(p & ... X(p)))
|
||||||
static const formula*
|
static formula
|
||||||
phi_n(std::string name, int n)
|
phi_n(std::string name, int n)
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return constant::true_instance();
|
return formula::tt();
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
const formula* p = env.require(name);
|
formula p = formula::ap(name);
|
||||||
for (; n > 0; --n)
|
for (; n > 0; --n)
|
||||||
{
|
{
|
||||||
if (result)
|
if (result)
|
||||||
result = And_(p->clone(), X_(result));
|
result = And_(p, X_(result));
|
||||||
else
|
else
|
||||||
result = p;
|
result = p;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* N_n(std::string name, int n)
|
formula N_n(std::string name, int n)
|
||||||
{
|
{
|
||||||
return unop::instance(unop::F, phi_n(name, n));
|
return formula::F(phi_n(name, n));
|
||||||
}
|
}
|
||||||
|
|
||||||
// p & X(p) & XX(p) & XXX(p) & ... X^n(p)
|
// p & X(p) & XX(p) & XXX(p) & ... X^n(p)
|
||||||
static const formula*
|
static formula
|
||||||
phi_prime_n(std::string name, int n)
|
phi_prime_n(std::string name, int n)
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return constant::true_instance();
|
return formula::tt();
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
const formula* p = env.require(name);
|
formula p = formula::ap(name);
|
||||||
for (; n > 0; --n)
|
for (; n > 0; --n)
|
||||||
{
|
{
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
p = X_(p->clone());
|
p = X_(p);
|
||||||
result = And_(result, p);
|
result = And_(result, p);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -358,7 +351,7 @@ phi_prime_n(std::string name, int n)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const formula*
|
static formula
|
||||||
N_prime_n(std::string name, int n)
|
N_prime_n(std::string name, int n)
|
||||||
{
|
{
|
||||||
return F_(phi_prime_n(name, n));
|
return F_(phi_prime_n(name, n));
|
||||||
|
|
@ -367,24 +360,24 @@ N_prime_n(std::string name, int n)
|
||||||
|
|
||||||
// GF(p_1) & GF(p_2) & ... & GF(p_n) if conj == true
|
// GF(p_1) & GF(p_2) & ... & GF(p_n) if conj == true
|
||||||
// GF(p_1) | GF(p_2) | ... | GF(p_n) if conj == false
|
// GF(p_1) | GF(p_2) | ... | GF(p_n) if conj == false
|
||||||
static const formula*
|
static formula
|
||||||
GF_n(std::string name, int n, bool conj = true)
|
GF_n(std::string name, int n, bool conj = true)
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return conj ? constant::true_instance() : constant::false_instance();
|
return conj ? formula::tt() : formula::ff();
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
|
|
||||||
multop::type op = conj ? multop::And : multop::Or;
|
op o = conj ? op::And : op::Or;
|
||||||
|
|
||||||
for (int i = 1; i <= n; ++i)
|
for (int i = 1; i <= n; ++i)
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << i;
|
p << name << i;
|
||||||
const formula* f = G_(F_(env.require(p.str())));
|
formula f = G_(F_(formula::ap(p.str())));
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
result = multop::instance(op, f, result);
|
result = formula::multop(o, {f, result});
|
||||||
else
|
else
|
||||||
result = f;
|
result = f;
|
||||||
}
|
}
|
||||||
|
|
@ -393,24 +386,24 @@ GF_n(std::string name, int n, bool conj = true)
|
||||||
|
|
||||||
// FG(p_1) | FG(p_2) | ... | FG(p_n) if conj == false
|
// FG(p_1) | FG(p_2) | ... | FG(p_n) if conj == false
|
||||||
// FG(p_1) & FG(p_2) & ... & FG(p_n) if conj == true
|
// FG(p_1) & FG(p_2) & ... & FG(p_n) if conj == true
|
||||||
static const formula*
|
static formula
|
||||||
FG_n(std::string name, int n, bool conj = false)
|
FG_n(std::string name, int n, bool conj = false)
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return conj ? constant::true_instance() : constant::false_instance();
|
return conj ? formula::tt() : formula::ff();
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
|
|
||||||
multop::type op = conj ? multop::And : multop::Or;
|
op o = conj ? op::And : op::Or;
|
||||||
|
|
||||||
for (int i = 1; i <= n; ++i)
|
for (int i = 1; i <= n; ++i)
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << i;
|
p << name << i;
|
||||||
const formula* f = F_(G_(env.require(p.str())));
|
formula f = F_(G_(formula::ap(p.str())));
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
result = multop::instance(op, f, result);
|
result = formula::multop(o, {f, result});
|
||||||
else
|
else
|
||||||
result = f;
|
result = f;
|
||||||
}
|
}
|
||||||
|
|
@ -419,93 +412,91 @@ FG_n(std::string name, int n, bool conj = false)
|
||||||
|
|
||||||
// (((p1 OP p2) OP p3)...OP pn) if right_assoc == false
|
// (((p1 OP p2) OP p3)...OP pn) if right_assoc == false
|
||||||
// (p1 OP (p2 OP (p3 OP (... pn) if right_assoc == true
|
// (p1 OP (p2 OP (p3 OP (... pn) if right_assoc == true
|
||||||
static const formula*
|
static formula
|
||||||
bin_n(std::string name, int n,
|
bin_n(std::string name, int n, op o, bool right_assoc = false)
|
||||||
binop::type op, bool right_assoc = false)
|
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
n = 1;
|
n = 1;
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
|
|
||||||
for (int i = 1; i <= n; ++i)
|
for (int i = 1; i <= n; ++i)
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << (right_assoc ? (n + 1 - i) : i);
|
p << name << (right_assoc ? (n + 1 - i) : i);
|
||||||
const formula* f = env.require(p.str());
|
formula f = formula::ap(p.str());
|
||||||
if (!result)
|
if (!result)
|
||||||
result = f;
|
result = f;
|
||||||
else if (right_assoc)
|
else if (right_assoc)
|
||||||
result = binop::instance(op, f, result);
|
result = formula::binop(o, f, result);
|
||||||
else
|
else
|
||||||
result = binop::instance(op, result, f);
|
result = formula::binop(o, result, f);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (GF(p1)|FG(p2))&(GF(p2)|FG(p3))&...&(GF(pn)|FG(p{n+1}))"
|
// (GF(p1)|FG(p2))&(GF(p2)|FG(p3))&...&(GF(pn)|FG(p{n+1}))"
|
||||||
static const formula*
|
static formula
|
||||||
R_n(std::string name, int n)
|
R_n(std::string name, int n)
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return constant::true_instance();
|
return formula::tt();
|
||||||
|
|
||||||
const formula* pi;
|
formula pi;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << 1;
|
p << name << 1;
|
||||||
pi = env.require(p.str());
|
pi = formula::ap(p.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
|
|
||||||
for (int i = 1; i <= n; ++i)
|
for (int i = 1; i <= n; ++i)
|
||||||
{
|
{
|
||||||
const formula* gf = G_(F_(pi));
|
formula gf = G_(F_(pi));
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << i + 1;
|
p << name << i + 1;
|
||||||
pi = env.require(p.str());
|
pi = formula::ap(p.str());
|
||||||
|
|
||||||
const formula* fg = F_(G_(pi->clone()));
|
formula fg = F_(G_(pi));
|
||||||
|
|
||||||
const formula* f = Or_(gf, fg);
|
formula f = Or_(gf, fg);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
result = And_(f, result);
|
result = And_(f, result);
|
||||||
else
|
else
|
||||||
result = f;
|
result = f;
|
||||||
}
|
}
|
||||||
pi->destroy();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (F(p1)|G(p2))&(F(p2)|G(p3))&...&(F(pn)|G(p{n+1}))"
|
// (F(p1)|G(p2))&(F(p2)|G(p3))&...&(F(pn)|G(p{n+1}))"
|
||||||
static const formula*
|
static formula
|
||||||
Q_n(std::string name, int n)
|
Q_n(std::string name, int n)
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return constant::true_instance();
|
return formula::tt();
|
||||||
|
|
||||||
const formula* pi;
|
formula pi;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << 1;
|
p << name << 1;
|
||||||
pi = env.require(p.str());
|
pi = formula::ap(p.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
|
|
||||||
for (int i = 1; i <= n; ++i)
|
for (int i = 1; i <= n; ++i)
|
||||||
{
|
{
|
||||||
const formula* f = F_(pi);
|
formula f = F_(pi);
|
||||||
|
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << i + 1;
|
p << name << i + 1;
|
||||||
pi = env.require(p.str());
|
pi = formula::ap(p.str());
|
||||||
|
|
||||||
const formula* g = G_(pi->clone());
|
formula g = G_(pi);
|
||||||
|
|
||||||
f = Or_(f, g);
|
f = Or_(f, g);
|
||||||
|
|
||||||
|
|
@ -514,31 +505,29 @@ Q_n(std::string name, int n)
|
||||||
else
|
else
|
||||||
result = f;
|
result = f;
|
||||||
}
|
}
|
||||||
pi->destroy();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OP(p1) | OP(p2) | ... | OP(Pn) if conj == false
|
// OP(p1) | OP(p2) | ... | OP(Pn) if conj == false
|
||||||
// OP(p1) & OP(p2) & ... & OP(Pn) if conj == true
|
// OP(p1) & OP(p2) & ... & OP(Pn) if conj == true
|
||||||
static const formula*
|
static formula
|
||||||
combunop_n(std::string name, int n,
|
combunop_n(std::string name, int n, op o, bool conj = false)
|
||||||
unop::type op, bool conj = false)
|
|
||||||
{
|
{
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return conj ? constant::true_instance() : constant::false_instance();
|
return conj ? formula::tt() : formula::ff();
|
||||||
|
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
|
|
||||||
multop::type cop = conj ? multop::And : multop::Or;
|
op cop = conj ? op::And : op::Or;
|
||||||
|
|
||||||
for (int i = 1; i <= n; ++i)
|
for (int i = 1; i <= n; ++i)
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << name << i;
|
p << name << i;
|
||||||
const formula* f = unop::instance(op, env.require(p.str()));
|
formula f = formula::unop(o, formula::ap(p.str()));
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
result = multop::instance(cop, f, result);
|
result = formula::multop(cop, {f, result});
|
||||||
else
|
else
|
||||||
result = f;
|
result = f;
|
||||||
}
|
}
|
||||||
|
|
@ -547,21 +536,21 @@ combunop_n(std::string name, int n,
|
||||||
|
|
||||||
// !((GF(p1)&GF(p2)&...&GF(pn))->G(q -> F(r)))
|
// !((GF(p1)&GF(p2)&...&GF(pn))->G(q -> F(r)))
|
||||||
// From "Fast LTL to Büchi Automata Translation" [gastin.01.cav]
|
// From "Fast LTL to Büchi Automata Translation" [gastin.01.cav]
|
||||||
static const formula*
|
static formula
|
||||||
fair_response(std::string p, std::string q, std::string r, int n)
|
fair_response(std::string p, std::string q, std::string r, int n)
|
||||||
{
|
{
|
||||||
const formula* fair = GF_n(p, n);
|
formula fair = GF_n(p, n);
|
||||||
const formula* resp = G_(Implies_(env.require(q), F_(env.require(r))));
|
formula resp = G_(Implies_(formula::ap(q), F_(formula::ap(r))));
|
||||||
return Not_(Implies_(fair, resp));
|
return Not_(Implies_(fair, resp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Builds X(X(...X(p))) with n occurrences of X.
|
// Builds X(X(...X(p))) with n occurrences of X.
|
||||||
static const formula*
|
static formula
|
||||||
X_n(const formula* p, int n)
|
X_n(formula p, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
const formula* res = p;
|
formula res = p;
|
||||||
while (n--)
|
while (n--)
|
||||||
res = X_(res);
|
res = X_(res);
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -569,214 +558,174 @@ X_n(const formula* p, int n)
|
||||||
|
|
||||||
// Based on LTLcounter.pl from Kristin Rozier.
|
// Based on LTLcounter.pl from Kristin Rozier.
|
||||||
// http://shemesh.larc.nasa.gov/people/kyr/benchmarking_scripts/
|
// http://shemesh.larc.nasa.gov/people/kyr/benchmarking_scripts/
|
||||||
static const formula*
|
static formula
|
||||||
ltl_counter(std::string bit, std::string marker, int n, bool linear)
|
ltl_counter(std::string bit, std::string marker, int n, bool linear)
|
||||||
{
|
{
|
||||||
const formula* b = env.require(bit);
|
formula b = formula::ap(bit);
|
||||||
const formula* neg_b = Not_(b);
|
formula neg_b = Not_(b);
|
||||||
const formula* m = env.require(marker);
|
formula m = formula::ap(marker);
|
||||||
const formula* neg_m = Not_(m); // to destroy
|
formula neg_m = Not_(m);
|
||||||
|
|
||||||
multop::vec* res = new multop::vec(4);
|
std::vector<formula> res(4);
|
||||||
|
|
||||||
// The marker starts with "1", followed by n-1 "0", then "1" again,
|
// The marker starts with "1", followed by n-1 "0", then "1" again,
|
||||||
// n-1 "0", etc.
|
// n-1 "0", etc.
|
||||||
if (!linear)
|
if (!linear)
|
||||||
{
|
{
|
||||||
// G(m -> X(!m)&XX(!m)&XXX(m)) [if n = 3]
|
// G(m -> X(!m)&XX(!m)&XXX(m)) [if n = 3]
|
||||||
multop::vec* v = new multop::vec(n);
|
std::vector<formula> v(n);
|
||||||
for (int i = 0; i + 1 < n; ++i)
|
for (int i = 0; i + 1 < n; ++i)
|
||||||
(*v)[i] = X_n(neg_m->clone(), i + 1);
|
v[i] = X_n(neg_m, i + 1);
|
||||||
(*v)[n - 1] = X_n(m->clone(), n);
|
v[n - 1] = X_n(m, n);
|
||||||
(*res)[0] = And_(m->clone(),
|
res[0] = And_(m, G_(Implies_(m, formula::And(std::move(v)))));
|
||||||
G_(Implies_(m->clone(),
|
|
||||||
multop::instance(multop::And, v))));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// G(m -> X(!m & X(!m X(m)))) [if n = 3]
|
// G(m -> X(!m & X(!m X(m)))) [if n = 3]
|
||||||
const formula* p = m->clone();
|
formula p = m;
|
||||||
for (int i = n - 1; i > 0; --i)
|
for (int i = n - 1; i > 0; --i)
|
||||||
p = And_(neg_m->clone(), X_(p));
|
p = And_(neg_m, X_(p));
|
||||||
(*res)[0] = And_(m->clone(),
|
res[0] = And_(m, G_(Implies_(m, X_(p))));
|
||||||
G_(Implies_(m->clone(), X_(p))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All bits are initially zero.
|
// All bits are initially zero.
|
||||||
if (!linear)
|
if (!linear)
|
||||||
{
|
{
|
||||||
// !b & X(!b) & XX(!b) [if n = 3]
|
// !b & X(!b) & XX(!b) [if n = 3]
|
||||||
multop::vec* v2 = new multop::vec(n);
|
std::vector<formula> v2(n);
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
(*v2)[i] = X_n(neg_b->clone(), i);
|
v2[i] = X_n(neg_b, i);
|
||||||
(*res)[1] = multop::instance(multop::And, v2);
|
res[1] = formula::And(std::move(v2));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// !b & X(!b & X(!b)) [if n = 3]
|
// !b & X(!b & X(!b)) [if n = 3]
|
||||||
const formula* p = neg_b->clone();
|
formula p = neg_b;
|
||||||
for (int i = n - 1; i > 0; --i)
|
for (int i = n - 1; i > 0; --i)
|
||||||
p = And_(neg_b->clone(), X_(p));
|
p = And_(neg_b, X_(p));
|
||||||
(*res)[1] = p;
|
res[1] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AndX_(x, y) (linear ? X_(And_((x), (y))) : And_(X_(x), X_(y)))
|
#define AndX_(x, y) (linear ? X_(And_((x), (y))) : And_(X_(x), X_(y)))
|
||||||
|
|
||||||
// If the least significant bit is 0, it will be 1 at the next time,
|
// If the least significant bit is 0, it will be 1 at the next time,
|
||||||
// and other bits stay the same.
|
// and other bits stay the same.
|
||||||
const formula* Xnm1_b = X_n(b->clone(), n - 1);
|
formula Xnm1_b = X_n(b, n - 1);
|
||||||
const formula* Xn_b = X_(Xnm1_b); // to destroy
|
formula Xn_b = X_(Xnm1_b);
|
||||||
(*res)[2] =
|
res[2] = G_(Implies_(And_(m, neg_b),
|
||||||
G_(Implies_(And_(m->clone(), neg_b->clone()),
|
AndX_(Xnm1_b, U_(And_(Not_(m), Equiv_(b, Xn_b)), m))));
|
||||||
AndX_(Xnm1_b->clone(), U_(And_(Not_(m->clone()),
|
|
||||||
Equiv_(b->clone(),
|
|
||||||
Xn_b->clone())),
|
|
||||||
m->clone()))));
|
|
||||||
|
|
||||||
// From the least significant bit to the first 0, all the bits
|
// From the least significant bit to the first 0, all the bits
|
||||||
// are flipped on the next value. Remaining bits are identical.
|
// are flipped on the next value. Remaining bits are identical.
|
||||||
const formula* Xnm1_negb = X_n(neg_b, n - 1);
|
formula Xnm1_negb = X_n(neg_b, n - 1);
|
||||||
const formula* Xn_negb = X_(Xnm1_negb); // to destroy
|
formula Xn_negb = X_(Xnm1_negb);
|
||||||
(*res)[3] =
|
res[3] = G_(Implies_(And_(m, b),
|
||||||
G_(Implies_(And_(m->clone(), b->clone()),
|
AndX_(Xnm1_negb,
|
||||||
AndX_(Xnm1_negb->clone(),
|
U_(And_(And_(b, neg_m), Xn_negb),
|
||||||
U_(And_(And_(b->clone(), neg_m->clone()),
|
Or_(m, And_(And_(neg_m, neg_b),
|
||||||
Xn_negb->clone()),
|
AndX_(Xnm1_b,
|
||||||
Or_(m->clone(),
|
U_(And_(neg_m,
|
||||||
And_(And_(neg_m->clone(),
|
Equiv_(b, Xn_b)),
|
||||||
neg_b->clone()),
|
m))))))));
|
||||||
AndX_(Xnm1_b->clone(),
|
return formula::And(std::move(res));
|
||||||
U_(And_(neg_m->clone(),
|
|
||||||
Equiv_(b->clone(),
|
|
||||||
Xn_b->clone())),
|
|
||||||
m->clone()))))))));
|
|
||||||
neg_m->destroy();
|
|
||||||
Xn_b->destroy();
|
|
||||||
Xn_negb->destroy();
|
|
||||||
|
|
||||||
return multop::instance(multop::And, res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const formula*
|
static formula
|
||||||
ltl_counter_carry(std::string bit, std::string marker,
|
ltl_counter_carry(std::string bit, std::string marker,
|
||||||
std::string carry, int n, bool linear)
|
std::string carry, int n, bool linear)
|
||||||
{
|
{
|
||||||
const formula* b = env.require(bit);
|
formula b = formula::ap(bit);
|
||||||
const formula* neg_b = Not_(b);
|
formula neg_b = Not_(b);
|
||||||
const formula* m = env.require(marker);
|
formula m = formula::ap(marker);
|
||||||
const formula* neg_m = Not_(m); // to destroy
|
formula neg_m = Not_(m);
|
||||||
const formula* c = env.require(carry);
|
formula c = formula::ap(carry);
|
||||||
const formula* neg_c = Not_(c); // to destroy
|
formula neg_c = Not_(c);
|
||||||
|
|
||||||
multop::vec* res = new multop::vec(6);
|
std::vector<formula> res(6);
|
||||||
|
|
||||||
// The marker starts with "1", followed by n-1 "0", then "1" again,
|
// The marker starts with "1", followed by n-1 "0", then "1" again,
|
||||||
// n-1 "0", etc.
|
// n-1 "0", etc.
|
||||||
if (!linear)
|
if (!linear)
|
||||||
{
|
{
|
||||||
// G(m -> X(!m)&XX(!m)&XXX(m)) [if n = 3]
|
// G(m -> X(!m)&XX(!m)&XXX(m)) [if n = 3]
|
||||||
multop::vec* v = new multop::vec(n);
|
std::vector<formula> v(n);
|
||||||
for (int i = 0; i + 1 < n; ++i)
|
for (int i = 0; i + 1 < n; ++i)
|
||||||
(*v)[i] = X_n(neg_m->clone(), i + 1);
|
v[i] = X_n(neg_m, i + 1);
|
||||||
(*v)[n - 1] = X_n(m->clone(), n);
|
v[n - 1] = X_n(m, n);
|
||||||
(*res)[0] = And_(m->clone(),
|
res[0] = And_(m, G_(Implies_(m, formula::And(std::move(v)))));
|
||||||
G_(Implies_(m->clone(),
|
|
||||||
multop::instance(multop::And, v))));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// G(m -> X(!m & X(!m X(m)))) [if n = 3]
|
// G(m -> X(!m & X(!m X(m)))) [if n = 3]
|
||||||
const formula* p = m->clone();
|
formula p = m;
|
||||||
for (int i = n - 1; i > 0; --i)
|
for (int i = n - 1; i > 0; --i)
|
||||||
p = And_(neg_m->clone(), X_(p));
|
p = And_(neg_m, X_(p));
|
||||||
(*res)[0] = And_(m->clone(),
|
res[0] = And_(m, G_(Implies_(m, X_(p))));
|
||||||
G_(Implies_(m->clone(), X_(p))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All bits are initially zero.
|
// All bits are initially zero.
|
||||||
if (!linear)
|
if (!linear)
|
||||||
{
|
{
|
||||||
// !b & X(!b) & XX(!b) [if n = 3]
|
// !b & X(!b) & XX(!b) [if n = 3]
|
||||||
multop::vec* v2 = new multop::vec(n);
|
std::vector<formula> v2(n);
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
(*v2)[i] = X_n(neg_b->clone(), i);
|
v2[i] = X_n(neg_b, i);
|
||||||
(*res)[1] = multop::instance(multop::And, v2);
|
res[1] = formula::And(std::move(v2));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// !b & X(!b & X(!b)) [if n = 3]
|
// !b & X(!b & X(!b)) [if n = 3]
|
||||||
const formula* p = neg_b->clone();
|
formula p = neg_b;
|
||||||
for (int i = n - 1; i > 0; --i)
|
for (int i = n - 1; i > 0; --i)
|
||||||
p = And_(neg_b->clone(), X_(p));
|
p = And_(neg_b, X_(p));
|
||||||
(*res)[1] = p;
|
res[1] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* Xn_b = X_n(b->clone(), n); // to destroy
|
formula Xn_b = X_n(b, n);
|
||||||
const formula* Xn_negb = X_n(neg_b, n); // to destroy
|
formula Xn_negb = X_n(neg_b, n);
|
||||||
|
|
||||||
// If m is 1 and b is 0 then c is 0 and n steps later b is 1.
|
// If m is 1 and b is 0 then c is 0 and n steps later b is 1.
|
||||||
(*res)[2] = G_(Implies_(And_(m->clone(), neg_b->clone()),
|
res[2] = G_(Implies_(And_(m, neg_b), And_(neg_c, Xn_b)));
|
||||||
And_(neg_c->clone(), Xn_b->clone())));
|
|
||||||
|
|
||||||
// If m is 1 and b is 1 then c is 1 and n steps later b is 0.
|
// If m is 1 and b is 1 then c is 1 and n steps later b is 0.
|
||||||
(*res)[3] = G_(Implies_(And_(m->clone(), b->clone()),
|
res[3] = G_(Implies_(And_(m, b), And_(c, Xn_negb)));
|
||||||
And_(c->clone(), Xn_negb->clone())));
|
|
||||||
|
|
||||||
if (!linear)
|
if (!linear)
|
||||||
{
|
{
|
||||||
// If there's no carry, then all of the bits stay the same n steps later.
|
// If there's no carry, then all of the bits stay the same n steps later.
|
||||||
(*res)[4] = G_(Implies_(And_(neg_c->clone(), X_(neg_m->clone())),
|
res[4] = G_(Implies_(And_(neg_c, X_(neg_m)),
|
||||||
And_(X_(Not_(c->clone())),
|
And_(X_(Not_(c)), Equiv_(X_(b), X_(Xn_b)))));
|
||||||
Equiv_(X_(b->clone()),
|
|
||||||
X_(Xn_b->clone())))));
|
|
||||||
|
|
||||||
// If there's a carry, then add one: flip the bits of b and
|
// If there's a carry, then add one: flip the bits of b and
|
||||||
// adjust the carry.
|
// adjust the carry.
|
||||||
(*res)[5] = G_(Implies_(c->clone(),
|
res[5] = G_(Implies_(c, And_(Implies_(X_(neg_b),
|
||||||
And_(Implies_(X_(neg_b->clone()),
|
And_(X_(neg_c), X_(Xn_b))),
|
||||||
And_(X_(neg_c->clone()),
|
Implies_(X_(b),
|
||||||
X_(Xn_b->clone()))),
|
And_(X_(c), X_(Xn_negb))))));
|
||||||
Implies_(X_(b->clone()),
|
|
||||||
And_(X_(c->clone()),
|
|
||||||
X_(Xn_negb->clone()))))));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If there's no carry, then all of the bits stay the same n steps later.
|
// If there's no carry, then all of the bits stay the same n steps later.
|
||||||
(*res)[4] = G_(Implies_(And_(neg_c->clone(), X_(neg_m->clone())),
|
res[4] = G_(Implies_(And_(neg_c, X_(neg_m)),
|
||||||
X_(And_(Not_(c->clone()),
|
X_(And_(Not_(c), Equiv_(b, Xn_b)))));
|
||||||
Equiv_(b->clone(),
|
|
||||||
Xn_b->clone())))));
|
|
||||||
|
|
||||||
// If there's a carry, then add one: flip the bits of b and
|
// If there's a carry, then add one: flip the bits of b and
|
||||||
// adjust the carry.
|
// adjust the carry.
|
||||||
(*res)[5] = G_(Implies_(c->clone(),
|
res[5] = G_(Implies_(c, X_(And_(Implies_(neg_b, And_(neg_c, Xn_b)),
|
||||||
X_(And_(Implies_(neg_b->clone(),
|
Implies_(b, And_(c, Xn_negb))))));
|
||||||
And_(neg_c->clone(),
|
|
||||||
Xn_b->clone())),
|
|
||||||
Implies_(b->clone(),
|
|
||||||
And_(c->clone(),
|
|
||||||
Xn_negb->clone()))))));
|
|
||||||
}
|
}
|
||||||
|
return formula::And(std::move(res));
|
||||||
neg_m->destroy();
|
|
||||||
neg_c->destroy();
|
|
||||||
Xn_b->destroy();
|
|
||||||
Xn_negb->destroy();
|
|
||||||
|
|
||||||
return multop::instance(multop::And, res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
output_pattern(int pattern, int n)
|
output_pattern(int pattern, int n)
|
||||||
{
|
{
|
||||||
const formula* f = 0;
|
formula f = nullptr;
|
||||||
switch (pattern)
|
switch (pattern)
|
||||||
{
|
{
|
||||||
// Keep this alphabetically-ordered!
|
// Keep this alphabetically-ordered!
|
||||||
case OPT_AND_F:
|
case OPT_AND_F:
|
||||||
f = combunop_n("p", n, unop::F, true);
|
f = combunop_n("p", n, op::F, true);
|
||||||
break;
|
break;
|
||||||
case OPT_AND_FG:
|
case OPT_AND_FG:
|
||||||
f = FG_n("p", n, true);
|
f = FG_n("p", n, true);
|
||||||
|
|
@ -785,13 +734,13 @@ output_pattern(int pattern, int n)
|
||||||
f = GF_n("p", n, true);
|
f = GF_n("p", n, true);
|
||||||
break;
|
break;
|
||||||
case OPT_CCJ_ALPHA:
|
case OPT_CCJ_ALPHA:
|
||||||
f = multop::instance(multop::And, E_n("p", n), E_n("q", n));
|
f = formula::And({E_n("p", n), E_n("q", n)});
|
||||||
break;
|
break;
|
||||||
case OPT_CCJ_BETA:
|
case OPT_CCJ_BETA:
|
||||||
f = multop::instance(multop::And, N_n("p", n), N_n("q", n));
|
f = formula::And({N_n("p", n), N_n("q", n)});
|
||||||
break;
|
break;
|
||||||
case OPT_CCJ_BETA_PRIME:
|
case OPT_CCJ_BETA_PRIME:
|
||||||
f = multop::instance(multop::And, N_prime_n("p", n), N_prime_n("q", n));
|
f = formula::And({N_prime_n("p", n), N_prime_n("q", n)});
|
||||||
break;
|
break;
|
||||||
case OPT_GH_Q:
|
case OPT_GH_Q:
|
||||||
f = Q_n("p", n);
|
f = Q_n("p", n);
|
||||||
|
|
@ -806,16 +755,16 @@ output_pattern(int pattern, int n)
|
||||||
f = FG_n("p", n, false);
|
f = FG_n("p", n, false);
|
||||||
break;
|
break;
|
||||||
case OPT_OR_G:
|
case OPT_OR_G:
|
||||||
f = combunop_n("p", n, unop::G, false);
|
f = combunop_n("p", n, op::G, false);
|
||||||
break;
|
break;
|
||||||
case OPT_OR_GF:
|
case OPT_OR_GF:
|
||||||
f = GF_n("p", n, false);
|
f = GF_n("p", n, false);
|
||||||
break;
|
break;
|
||||||
case OPT_R_LEFT:
|
case OPT_R_LEFT:
|
||||||
f = bin_n("p", n, binop::R, false);
|
f = bin_n("p", n, op::R, false);
|
||||||
break;
|
break;
|
||||||
case OPT_R_RIGHT:
|
case OPT_R_RIGHT:
|
||||||
f = bin_n("p", n, binop::R, true);
|
f = bin_n("p", n, op::R, true);
|
||||||
break;
|
break;
|
||||||
case OPT_RV_COUNTER_CARRY:
|
case OPT_RV_COUNTER_CARRY:
|
||||||
f = ltl_counter_carry("b", "m", "c", n, false);
|
f = ltl_counter_carry("b", "m", "c", n, false);
|
||||||
|
|
@ -830,10 +779,10 @@ output_pattern(int pattern, int n)
|
||||||
f = ltl_counter("b", "m", n, true);
|
f = ltl_counter("b", "m", n, true);
|
||||||
break;
|
break;
|
||||||
case OPT_U_LEFT:
|
case OPT_U_LEFT:
|
||||||
f = bin_n("p", n, binop::U, false);
|
f = bin_n("p", n, op::U, false);
|
||||||
break;
|
break;
|
||||||
case OPT_U_RIGHT:
|
case OPT_U_RIGHT:
|
||||||
f = bin_n("p", n, binop::U, true);
|
f = bin_n("p", n, op::U, true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(100, 0, "internal error: pattern not implemented");
|
error(100, 0, "internal error: pattern not implemented");
|
||||||
|
|
@ -841,15 +790,10 @@ output_pattern(int pattern, int n)
|
||||||
|
|
||||||
// Make sure we use only "p42"-style of atomic propositions
|
// Make sure we use only "p42"-style of atomic propositions
|
||||||
// in lbt's output.
|
// in lbt's output.
|
||||||
if (output_format == lbt_output && !f->has_lbt_atomic_props())
|
if (output_format == lbt_output && !f.has_lbt_atomic_props())
|
||||||
{
|
f = relabel(f, Pnn);
|
||||||
const spot::ltl::formula* r = spot::ltl::relabel(f, spot::ltl::Pnn);
|
|
||||||
f->destroy();
|
|
||||||
f = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
output_formula_checked(f, class_name[pattern - 1], n);
|
output_formula_checked(f, class_name[pattern - 1], n);
|
||||||
f->destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
|
|
@ -138,14 +138,14 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula* f,
|
process_formula(spot::ltl::formula f,
|
||||||
const char* filename = 0, int linenum = 0)
|
const char* filename = 0, 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 ltl::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::ltl::str_psl(f);
|
||||||
error_at_line(2, 0, filename, linenum,
|
error_at_line(2, 0, filename, linenum,
|
||||||
|
|
@ -159,7 +159,6 @@ namespace
|
||||||
const double translation_time = sw.stop();
|
const double translation_time = sw.stop();
|
||||||
|
|
||||||
printer.print(aut, f, filename, linenum, translation_time, nullptr);
|
printer.print(aut, f, filename, linenum, translation_time, nullptr);
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -170,16 +170,16 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula* f,
|
process_formula(spot::ltl::formula f,
|
||||||
const char* filename = 0, int linenum = 0)
|
const char* filename = 0, 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 ltl::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::ltl::str_psl(f);
|
||||||
error_at_line(2, 0, filename, linenum,
|
error_at_line(2, 0, filename, linenum,
|
||||||
|
|
@ -207,7 +207,6 @@ namespace
|
||||||
tgta = spot::minimize_tgta(tgta);
|
tgta = spot::minimize_tgta(tgta);
|
||||||
spot::print_dot(std::cout, tgta->get_ta());
|
spot::print_dot(std::cout, tgta->get_ta());
|
||||||
}
|
}
|
||||||
f->destroy();
|
|
||||||
flush_cout();
|
flush_cout();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@
|
||||||
#include "common_file.hh"
|
#include "common_file.hh"
|
||||||
#include "common_finput.hh"
|
#include "common_finput.hh"
|
||||||
#include "parseaut/public.hh"
|
#include "parseaut/public.hh"
|
||||||
#include "ltlast/unop.hh"
|
|
||||||
#include "ltlvisit/print.hh"
|
#include "ltlvisit/print.hh"
|
||||||
#include "ltlvisit/apcollect.hh"
|
#include "ltlvisit/apcollect.hh"
|
||||||
#include "ltlvisit/mutation.hh"
|
#include "ltlvisit/mutation.hh"
|
||||||
|
|
@ -819,8 +818,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef
|
typedef
|
||||||
std::unordered_set<const spot::ltl::formula*,
|
std::unordered_set<spot::ltl::formula> fset_t;
|
||||||
const spot::ptr_hash<const spot::ltl::formula> > fset_t;
|
|
||||||
|
|
||||||
|
|
||||||
class processor: public job_processor
|
class processor: public job_processor
|
||||||
|
|
@ -834,32 +832,22 @@ namespace
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~processor()
|
|
||||||
{
|
|
||||||
fset_t::iterator i = unique_set.begin();
|
|
||||||
while (i != unique_set.end())
|
|
||||||
(*i++)->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
process_string(const std::string& input,
|
process_string(const std::string& input,
|
||||||
const char* filename,
|
const char* filename,
|
||||||
int linenum)
|
int linenum)
|
||||||
{
|
{
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = parse_formula(input, pel);
|
spot::ltl::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::ltl::format_parse_errors(std::cerr, input, pel);
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
f->clone();
|
|
||||||
int res = process_formula(f, filename, linenum);
|
int res = process_formula(f, filename, linenum);
|
||||||
|
|
||||||
if (res && bogus_output)
|
if (res && bogus_output)
|
||||||
|
|
@ -867,7 +855,7 @@ namespace
|
||||||
if (res && grind_output)
|
if (res && grind_output)
|
||||||
{
|
{
|
||||||
std::string bogus = input;
|
std::string bogus = input;
|
||||||
std::vector<const spot::ltl::formula*> mutations;
|
std::vector<spot::ltl::formula> mutations;
|
||||||
unsigned mutation_count;
|
unsigned mutation_count;
|
||||||
unsigned mutation_max;
|
unsigned mutation_max;
|
||||||
while (res)
|
while (res)
|
||||||
|
|
@ -888,15 +876,12 @@ namespace
|
||||||
{
|
{
|
||||||
std::cerr << "Mutation " << mutation_count << '/'
|
std::cerr << "Mutation " << mutation_count << '/'
|
||||||
<< mutation_max << ": ";
|
<< mutation_max << ": ";
|
||||||
f->destroy();
|
f = g;
|
||||||
f = g->clone();
|
res = process_formula(g);
|
||||||
res = process_formula(g->clone());
|
|
||||||
if (res)
|
if (res)
|
||||||
break;
|
break;
|
||||||
++mutation_count;
|
++mutation_count;
|
||||||
}
|
}
|
||||||
for (auto g: mutations)
|
|
||||||
g->destroy();
|
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
if (lbt_input)
|
if (lbt_input)
|
||||||
|
|
@ -922,8 +907,6 @@ namespace
|
||||||
std::cerr << ".\n\n";
|
std::cerr << ".\n\n";
|
||||||
grind_output->ostream() << bogus << std::endl;
|
grind_output->ostream() << bogus << std::endl;
|
||||||
}
|
}
|
||||||
f->destroy();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -954,20 +937,16 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula* f,
|
process_formula(spot::ltl::formula f,
|
||||||
const char* filename = 0, int linenum = 0)
|
const char* filename = 0, int linenum = 0)
|
||||||
{
|
{
|
||||||
static unsigned round = 0;
|
static unsigned round = 0;
|
||||||
|
|
||||||
// If we need LBT atomic proposition in any of the input or
|
// If we need LBT atomic proposition in any of the input or
|
||||||
// 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);
|
||||||
const spot::ltl::formula* g = spot::ltl::relabel(f, spot::ltl::Pnn);
|
|
||||||
f->destroy();
|
|
||||||
f = g;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- Positive Formula ----------
|
// ---------- Positive Formula ----------
|
||||||
|
|
||||||
|
|
@ -991,18 +970,13 @@ namespace
|
||||||
// Make sure we do not translate the same formula twice.
|
// Make sure we do not translate the same formula twice.
|
||||||
if (!allow_dups)
|
if (!allow_dups)
|
||||||
{
|
{
|
||||||
if (unique_set.insert(f).second)
|
if (!unique_set.insert(f).second)
|
||||||
{
|
|
||||||
f->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
std::cerr
|
std::cerr
|
||||||
<< ("warning: This formula or its negation has already"
|
<< ("warning: This formula or its negation has already"
|
||||||
" been checked.\n Use --allow-dups if it "
|
" been checked.\n Use --allow-dups if it "
|
||||||
"should not be ignored.\n")
|
"should not be ignored.\n")
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1053,12 +1027,11 @@ namespace
|
||||||
nstats = &vstats[n + 1];
|
nstats = &vstats[n + 1];
|
||||||
nstats->resize(m);
|
nstats->resize(m);
|
||||||
|
|
||||||
const spot::ltl::formula* nf =
|
spot::ltl::formula nf = spot::ltl::formula::Not(f);
|
||||||
spot::ltl::unop::instance(spot::ltl::unop::Not, f->clone());
|
|
||||||
|
|
||||||
if (!allow_dups)
|
if (!allow_dups)
|
||||||
{
|
{
|
||||||
bool res = unique_set.insert(nf->clone()).second;
|
bool res = unique_set.insert(nf).second;
|
||||||
// It is not possible to discover that nf has already been
|
// It is not possible to discover that nf has already been
|
||||||
// translated, otherwise that would mean that f had been
|
// translated, otherwise that would mean that f had been
|
||||||
// translated too and we would have caught it before.
|
// translated too and we would have caught it before.
|
||||||
|
|
@ -1084,7 +1057,6 @@ namespace
|
||||||
|| (!want_stats && is_deterministic(neg[n]))))
|
|| (!want_stats && is_deterministic(neg[n]))))
|
||||||
comp_neg[n] = dtgba_complement(neg[n]);
|
comp_neg[n] = dtgba_complement(neg[n]);
|
||||||
}
|
}
|
||||||
nf->destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spot::cleanup_tmpfiles();
|
spot::cleanup_tmpfiles();
|
||||||
|
|
@ -1171,7 +1143,6 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f);
|
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f);
|
||||||
f->destroy();
|
|
||||||
|
|
||||||
if (want_stats)
|
if (want_stats)
|
||||||
for (size_t i = 0; i < m; ++i)
|
for (size_t i = 0; i < m; ++i)
|
||||||
|
|
|
||||||
|
|
@ -238,15 +238,13 @@ namespace
|
||||||
int linenum)
|
int linenum)
|
||||||
{
|
{
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = parse_formula(input, pel);
|
spot::ltl::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::ltl::format_parse_errors(std::cerr, input, pel);
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,22 +255,20 @@ namespace
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula* f,
|
process_formula(spot::ltl::formula f,
|
||||||
const char* filename = 0, int linenum = 0)
|
const char* filename = 0, int linenum = 0)
|
||||||
{
|
{
|
||||||
std::unique_ptr<spot::ltl::relabeling_map> relmap;
|
std::unique_ptr<spot::ltl::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.
|
||||||
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->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::ltl::relabeling_map);
|
||||||
auto g = spot::ltl::relabel(f, spot::ltl::Pnn, relmap.get());
|
f = spot::ltl::relabel(f, spot::ltl::Pnn, relmap.get());
|
||||||
f->destroy();
|
|
||||||
f = g;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned round = 1;
|
static unsigned round = 1;
|
||||||
|
|
@ -297,7 +293,6 @@ namespace
|
||||||
nullptr);
|
nullptr);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
f->destroy();
|
|
||||||
spot::cleanup_tmpfiles();
|
spot::cleanup_tmpfiles();
|
||||||
++round;
|
++round;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,6 @@
|
||||||
#include "ltlvisit/apcollect.hh"
|
#include "ltlvisit/apcollect.hh"
|
||||||
#include "ltlvisit/exclusive.hh"
|
#include "ltlvisit/exclusive.hh"
|
||||||
#include "ltlvisit/print.hh"
|
#include "ltlvisit/print.hh"
|
||||||
#include "ltlast/unop.hh"
|
|
||||||
#include "ltlast/multop.hh"
|
|
||||||
#include "twaalgos/ltl2tgba_fm.hh"
|
#include "twaalgos/ltl2tgba_fm.hh"
|
||||||
#include "twaalgos/minimize.hh"
|
#include "twaalgos/minimize.hh"
|
||||||
#include "twaalgos/safety.hh"
|
#include "twaalgos/safety.hh"
|
||||||
|
|
@ -261,15 +259,15 @@ 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 const spot::ltl::formula* implied_by = 0;
|
static spot::ltl::formula implied_by = nullptr;
|
||||||
static const spot::ltl::formula* imply = 0;
|
static spot::ltl::formula imply = nullptr;
|
||||||
static const spot::ltl::formula* equivalent_to = 0;
|
static spot::ltl::formula equivalent_to = nullptr;
|
||||||
|
|
||||||
static const spot::ltl::formula*
|
static spot::ltl::formula
|
||||||
parse_formula_arg(const std::string& input)
|
parse_formula_arg(const std::string& input)
|
||||||
{
|
{
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = parse_formula(input, pel);
|
spot::ltl::formula f = parse_formula(input, pel);
|
||||||
if (spot::ltl::format_parse_errors(std::cerr, input, pel))
|
if (spot::ltl::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;
|
||||||
|
|
@ -342,18 +340,16 @@ parse_opt(int key, char* arg, struct argp_state*)
|
||||||
break;
|
break;
|
||||||
case OPT_IMPLIED_BY:
|
case OPT_IMPLIED_BY:
|
||||||
{
|
{
|
||||||
const spot::ltl::formula* i = parse_formula_arg(arg);
|
spot::ltl::formula i = parse_formula_arg(arg);
|
||||||
// a→c∧b→c ≡ (a∨b)→c
|
// a→c∧b→c ≡ (a∨b)→c
|
||||||
implied_by =
|
implied_by = spot::ltl::formula::Or({implied_by, i});
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::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)
|
||||||
const spot::ltl::formula* i = parse_formula_arg(arg);
|
spot::ltl::formula i = parse_formula_arg(arg);
|
||||||
imply =
|
imply = spot::ltl::formula::And({imply, i});
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::And, imply, i);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPT_LTL:
|
case OPT_LTL:
|
||||||
|
|
@ -439,8 +435,7 @@ parse_opt(int key, char* arg, struct argp_state*)
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef
|
typedef
|
||||||
std::unordered_set<const spot::ltl::formula*,
|
std::unordered_set<spot::ltl::formula> fset_t;
|
||||||
const spot::ptr_hash<const spot::ltl::formula>> fset_t;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
@ -451,22 +446,8 @@ namespace
|
||||||
fset_t unique_set;
|
fset_t unique_set;
|
||||||
spot::ltl::relabeling_map relmap;
|
spot::ltl::relabeling_map relmap;
|
||||||
|
|
||||||
~ltl_processor()
|
|
||||||
{
|
|
||||||
fset_t::iterator i = unique_set.begin();
|
|
||||||
while (i != unique_set.end())
|
|
||||||
(*i++)->destroy();
|
|
||||||
|
|
||||||
if (equivalent_to)
|
|
||||||
equivalent_to->destroy();
|
|
||||||
if (implied_by)
|
|
||||||
implied_by->destroy();
|
|
||||||
if (imply)
|
|
||||||
imply->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
ltl_processor(spot::ltl::ltl_simplifier& simpl)
|
ltl_processor(spot::ltl::ltl_simplifier& simpl)
|
||||||
: simpl(simpl)
|
: simpl(simpl)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -475,7 +456,7 @@ namespace
|
||||||
const char* filename = 0, int linenum = 0)
|
const char* filename = 0, int linenum = 0)
|
||||||
{
|
{
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
const spot::ltl::formula* f = parse_formula(input, pel);
|
spot::ltl::formula f = parse_formula(input, pel);
|
||||||
|
|
||||||
if (!f || pel.size() > 0)
|
if (!f || pel.size() > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -486,9 +467,6 @@ namespace
|
||||||
spot::ltl::format_parse_errors(std::cerr, input, pel);
|
spot::ltl::format_parse_errors(std::cerr, input, pel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
|
|
||||||
if (error_style == skip_errors)
|
if (error_style == skip_errors)
|
||||||
std::cout << input << std::endl;
|
std::cout << input << std::endl;
|
||||||
else
|
else
|
||||||
|
|
@ -508,64 +486,44 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula* f,
|
process_formula(spot::ltl::formula f,
|
||||||
const char* filename = 0, int linenum = 0)
|
const char* filename = 0, int linenum = 0)
|
||||||
{
|
{
|
||||||
if (opt_max_count >= 0 && match_count >= opt_max_count)
|
if (opt_max_count >= 0 && match_count >= opt_max_count)
|
||||||
{
|
{
|
||||||
abort_run = true;
|
abort_run = true;
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (negate)
|
if (negate)
|
||||||
f = spot::ltl::unop::instance(spot::ltl::unop::Not, f);
|
f = spot::ltl::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);
|
||||||
const spot::ltl::formula* res = simpl.simplify(f);
|
f = spot::ltl::remove_x(f);
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spot::ltl::formula* res = spot::ltl::remove_x(f);
|
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simplification_level || boolean_to_isop)
|
if (simplification_level || boolean_to_isop)
|
||||||
{
|
f = simpl.simplify(f);
|
||||||
const spot::ltl::formula* res = simpl.simplify(f);
|
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nnf)
|
if (nnf)
|
||||||
{
|
f = simpl.negative_normal_form(f);
|
||||||
const spot::ltl::formula* res = simpl.negative_normal_form(f);
|
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (relabeling)
|
switch (relabeling)
|
||||||
{
|
{
|
||||||
case ApRelabeling:
|
case ApRelabeling:
|
||||||
{
|
{
|
||||||
relmap.clear();
|
relmap.clear();
|
||||||
auto res = spot::ltl::relabel(f, style, &relmap);
|
f = spot::ltl::relabel(f, style, &relmap);
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BseRelabeling:
|
case BseRelabeling:
|
||||||
{
|
{
|
||||||
relmap.clear();
|
relmap.clear();
|
||||||
auto res = spot::ltl::relabel_bse(f, style, &relmap);
|
f = spot::ltl::relabel_bse(f, style, &relmap);
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NoRelabeling:
|
case NoRelabeling:
|
||||||
|
|
@ -573,32 +531,24 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unabbreviate.empty())
|
if (!unabbreviate.empty())
|
||||||
{
|
f = spot::ltl::unabbreviate(f, unabbreviate.c_str());
|
||||||
auto res = spot::ltl::unabbreviate(f, unabbreviate.c_str());
|
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!excl_ap.empty())
|
if (!excl_ap.empty())
|
||||||
{
|
f = excl_ap.constrain(f);
|
||||||
auto res = excl_ap.constrain(f);
|
|
||||||
f->destroy();
|
|
||||||
f = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matched = true;
|
bool matched = true;
|
||||||
|
|
||||||
matched &= !ltl || f->is_ltl_formula();
|
matched &= !ltl || f.is_ltl_formula();
|
||||||
matched &= !psl || f->is_psl_formula();
|
matched &= !psl || f.is_psl_formula();
|
||||||
matched &= !boolean || f->is_boolean();
|
matched &= !boolean || f.is_boolean();
|
||||||
matched &= !universal || f->is_universal();
|
matched &= !universal || f.is_universal();
|
||||||
matched &= !eventual || f->is_eventual();
|
matched &= !eventual || f.is_eventual();
|
||||||
matched &= !syntactic_safety || f->is_syntactic_safety();
|
matched &= !syntactic_safety || f.is_syntactic_safety();
|
||||||
matched &= !syntactic_guarantee || f->is_syntactic_guarantee();
|
matched &= !syntactic_guarantee || f.is_syntactic_guarantee();
|
||||||
matched &= !syntactic_obligation || f->is_syntactic_obligation();
|
matched &= !syntactic_obligation || f.is_syntactic_obligation();
|
||||||
matched &= !syntactic_recurrence || f->is_syntactic_recurrence();
|
matched &= !syntactic_recurrence || f.is_syntactic_recurrence();
|
||||||
matched &= !syntactic_persistence || f->is_syntactic_persistence();
|
matched &= !syntactic_persistence || f.is_syntactic_persistence();
|
||||||
matched &= !syntactic_si || f->is_syntactic_stutter_invariant();
|
matched &= !syntactic_si || f.is_syntactic_stutter_invariant();
|
||||||
matched &= !ap || atomic_prop_collect(f)->size() == ap_n;
|
matched &= !ap || atomic_prop_collect(f)->size() == ap_n;
|
||||||
|
|
||||||
if (matched && (size_min > 0 || size_max >= 0))
|
if (matched && (size_min > 0 || size_max >= 0))
|
||||||
|
|
@ -643,13 +593,8 @@ namespace
|
||||||
|
|
||||||
matched ^= invert;
|
matched ^= invert;
|
||||||
|
|
||||||
if (unique)
|
if (unique && !unique_set.insert(f).second)
|
||||||
{
|
matched = false;
|
||||||
if (unique_set.insert(f).second)
|
|
||||||
f->clone();
|
|
||||||
else
|
|
||||||
matched = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matched)
|
if (matched)
|
||||||
{
|
{
|
||||||
|
|
@ -658,7 +603,7 @@ namespace
|
||||||
&& output_format != quiet_output)
|
&& output_format != quiet_output)
|
||||||
{
|
{
|
||||||
// Sort the formulas alphabetically.
|
// Sort the formulas alphabetically.
|
||||||
std::map<std::string, const spot::ltl::formula*> m;
|
std::map<std::string, spot::ltl::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)
|
||||||
|
|
@ -670,7 +615,6 @@ namespace
|
||||||
output_formula_checked(f, filename, linenum, prefix, suffix);
|
output_formula_checked(f, filename, linenum, prefix, suffix);
|
||||||
++match_count;
|
++match_count;
|
||||||
}
|
}
|
||||||
f->destroy();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,6 @@
|
||||||
#include "common_output.hh"
|
#include "common_output.hh"
|
||||||
#include "common_conv.hh"
|
#include "common_conv.hh"
|
||||||
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "ltlvisit/clone.hh"
|
|
||||||
#include "ltlvisit/apcollect.hh"
|
|
||||||
#include "ltlvisit/length.hh"
|
|
||||||
#include "ltlvisit/mutation.hh"
|
#include "ltlvisit/mutation.hh"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -100,17 +96,13 @@ namespace
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int
|
int
|
||||||
process_formula(const spot::ltl::formula* f, const char *filename = 0,
|
process_formula(spot::ltl::formula f, const char *filename = 0,
|
||||||
int linenum = 0)
|
int linenum = 0)
|
||||||
{
|
{
|
||||||
auto mutations =
|
auto mutations =
|
||||||
spot::ltl::mutate(f, mut_opts, max_output, mutation_nb, opt_sort);
|
spot::ltl::mutate(f, mut_opts, max_output, mutation_nb, opt_sort);
|
||||||
f->destroy();
|
|
||||||
for (auto g: mutations)
|
for (auto g: mutations)
|
||||||
{
|
output_formula_checked(g, filename, linenum);
|
||||||
output_formula_checked(g, filename, linenum);
|
|
||||||
g->destroy();
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@
|
||||||
#include "common_aoutput.hh"
|
#include "common_aoutput.hh"
|
||||||
#include "common_conv.hh"
|
#include "common_conv.hh"
|
||||||
|
|
||||||
#include "ltlenv/defaultenv.hh"
|
|
||||||
#include "misc/timer.hh"
|
#include "misc/timer.hh"
|
||||||
#include "misc/random.hh"
|
#include "misc/random.hh"
|
||||||
|
|
||||||
|
|
@ -252,7 +251,7 @@ parse_opt(int key, char* arg, struct argp_state* as)
|
||||||
aprops = spot::ltl::create_atomic_prop_set(ap_count_given.min);
|
aprops = spot::ltl::create_atomic_prop_set(ap_count_given.min);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
aprops.insert(spot::ltl::default_environment::instance().require(arg));
|
aprops.insert(spot::ltl::formula::ap(arg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -328,7 +327,6 @@ main(int argc, char** argv)
|
||||||
if (ap_count_given.max > 0
|
if (ap_count_given.max > 0
|
||||||
&& ap_count_given.min != ap_count_given.max)
|
&& ap_count_given.min != ap_count_given.max)
|
||||||
{
|
{
|
||||||
spot::ltl::destroy_atomic_prop_set(aprops);
|
|
||||||
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::ltl::create_atomic_prop_set(c);
|
||||||
}
|
}
|
||||||
|
|
@ -391,5 +389,4 @@ main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
error(2, 0, "%s", e.what());
|
error(2, 0, "%s", e.what());
|
||||||
}
|
}
|
||||||
spot::ltl::destroy_atomic_prop_set(aprops);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,14 +33,9 @@
|
||||||
#include "common_conv.hh"
|
#include "common_conv.hh"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "ltlast/multop.hh"
|
|
||||||
#include "ltlast/unop.hh"
|
|
||||||
#include "ltlvisit/randomltl.hh"
|
#include "ltlvisit/randomltl.hh"
|
||||||
#include "ltlvisit/length.hh"
|
|
||||||
#include "ltlvisit/simplify.hh"
|
#include "ltlvisit/simplify.hh"
|
||||||
#include "ltlenv/defaultenv.hh"
|
|
||||||
#include "misc/random.hh"
|
#include "misc/random.hh"
|
||||||
#include "misc/hash.hh"
|
|
||||||
#include "misc/optionmap.hh"
|
#include "misc/optionmap.hh"
|
||||||
|
|
||||||
const char argp_program_doc[] ="\
|
const char argp_program_doc[] ="\
|
||||||
|
|
@ -253,8 +248,8 @@ main(int argc, char** argv)
|
||||||
opts.set("output", output);
|
opts.set("output", output);
|
||||||
opts.set("tree_size_min", opt_tree_size.min);
|
opts.set("tree_size_min", opt_tree_size.min);
|
||||||
opts.set("tree_size_max", opt_tree_size.max);
|
opts.set("tree_size_max", opt_tree_size.max);
|
||||||
opts.set("opt_wf", opt_wf);
|
opts.set("wf", opt_wf);
|
||||||
opts.set("opt_seed", opt_seed);
|
opts.set("seed", opt_seed);
|
||||||
opts.set("simplification_level", simplification_level);
|
opts.set("simplification_level", simplification_level);
|
||||||
return opts;
|
return opts;
|
||||||
}(), opt_pL, opt_pS, opt_pB);
|
}(), opt_pL, opt_pS, opt_pB);
|
||||||
|
|
@ -291,14 +286,13 @@ main(int argc, char** argv)
|
||||||
default:
|
default:
|
||||||
error(2, 0, "internal error: unknown type of output");
|
error(2, 0, "internal error: unknown type of output");
|
||||||
}
|
}
|
||||||
destroy_atomic_prop_set(aprops);
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (opt_formulas < 0 || opt_formulas--)
|
while (opt_formulas < 0 || opt_formulas--)
|
||||||
{
|
{
|
||||||
static int count = 0;
|
static int count = 0;
|
||||||
const spot::ltl::formula* f = rg.next();
|
spot::ltl::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 " \
|
||||||
|
|
@ -307,21 +301,17 @@ main(int argc, char** argv)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
output_formula_checked(f, 0, ++count);
|
output_formula_checked(f, 0, ++count);
|
||||||
f->destroy();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error& e)
|
catch (const std::runtime_error& e)
|
||||||
{
|
{
|
||||||
destroy_atomic_prop_set(aprops);
|
|
||||||
error(2, 0, "%s", e.what());
|
error(2, 0, "%s", e.what());
|
||||||
}
|
}
|
||||||
catch (const std::invalid_argument& e)
|
catch (const std::invalid_argument& e)
|
||||||
{
|
{
|
||||||
destroy_atomic_prop_set(aprops);
|
|
||||||
error(2, 0, "%s", e.what());
|
error(2, 0, "%s", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_atomic_prop_set(aprops);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2011, 2012, 2013, 2014, 2015 Laboratoire de Recherche et
|
||||||
// Developpement de l'Epita (LRDE)
|
// Developpement de l'Epita (LRDE)
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
|
|
@ -260,11 +260,9 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void kripke_explicit::add_condition(const ltl::formula* f,
|
void kripke_explicit::add_condition(ltl::formula f, std::string on_me)
|
||||||
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);
|
||||||
f->destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2011, 2012, 2013, 2014, 2015 Laboratoire de Recherche
|
||||||
// Développement de l'Epita (LRDE)
|
// et Développement de l'Epita (LRDE)
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -151,8 +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(const ltl::formula* f,
|
void add_condition(ltl::formula f, std::string on_me);
|
||||||
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>&
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ typedef std::map<std::string, bdd> formula_cache;
|
||||||
{
|
{
|
||||||
int token;
|
int token;
|
||||||
std::string* str;
|
std::string* str;
|
||||||
const spot::ltl::formula* f;
|
|
||||||
std::list<std::string*>* list;
|
std::list<std::string*>* list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,8 +109,8 @@ strident "," condition "," follow_list ";"
|
||||||
if (i == fcache.end())
|
if (i == fcache.end())
|
||||||
{
|
{
|
||||||
parse_error_list pel;
|
parse_error_list pel;
|
||||||
const formula* f = spot::ltl::parse_infix_boolean(*$3, pel,
|
formula f = spot::ltl::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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
## -*- coding: utf-8 -*-
|
## -*- coding: utf-8 -*-
|
||||||
## Copyright (C) 2009, 2010, 2011, 2013, 2014 Laboratoire de Recherche
|
## Copyright (C) 2009, 2010, 2011, 2013, 2014, 2015 Laboratoire de
|
||||||
## et Développement de l'Epita (LRDE).
|
## Recherche et Développement de l'Epita (LRDE).
|
||||||
## Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
|
## Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
## et Marie Curie.
|
## et Marie Curie.
|
||||||
|
|
@ -26,24 +26,7 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS)
|
||||||
|
|
||||||
ltlastdir = $(pkgincludedir)/ltlast
|
ltlastdir = $(pkgincludedir)/ltlast
|
||||||
|
|
||||||
ltlast_HEADERS = \
|
ltlast_HEADERS = formula.hh
|
||||||
allnodes.hh \
|
|
||||||
atomic_prop.hh \
|
|
||||||
binop.hh \
|
|
||||||
bunop.hh \
|
|
||||||
constant.hh \
|
|
||||||
formula.hh \
|
|
||||||
multop.hh \
|
|
||||||
predecl.hh \
|
|
||||||
unop.hh \
|
|
||||||
visitor.hh
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libltlast.la
|
noinst_LTLIBRARIES = libltlast.la
|
||||||
libltlast_la_SOURCES = \
|
libltlast_la_SOURCES = formula.cc
|
||||||
atomic_prop.cc \
|
|
||||||
binop.cc \
|
|
||||||
bunop.cc \
|
|
||||||
constant.cc \
|
|
||||||
formula.cc \
|
|
||||||
multop.cc \
|
|
||||||
unop.cc
|
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2010, 2014 Laboratoire de Recherche et Développement
|
|
||||||
// de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/allnodes.hh
|
|
||||||
/// \brief Define all LTL node types.
|
|
||||||
///
|
|
||||||
/// This file is usually needed when \b defining a visitor.
|
|
||||||
/// Prefer ltlast/predecl.hh when only \b declaring methods and functions
|
|
||||||
/// over LTL nodes.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "binop.hh"
|
|
||||||
#include "unop.hh"
|
|
||||||
#include "multop.hh"
|
|
||||||
#include "atomic_prop.hh"
|
|
||||||
#include "constant.hh"
|
|
||||||
#include "bunop.hh"
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
|
|
||||||
// Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de
|
|
||||||
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "atomic_prop.hh"
|
|
||||||
#include "visitor.hh"
|
|
||||||
#include "misc/bareword.hh"
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cassert>
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
|
|
||||||
atomic_prop::atomic_prop(const std::string& name, environment& env)
|
|
||||||
: formula(AtomicProp), name_(name), env_(&env)
|
|
||||||
{
|
|
||||||
is.boolean = true;
|
|
||||||
is.sugar_free_boolean = true;
|
|
||||||
is.in_nenoform = true;
|
|
||||||
is.syntactic_si = true; // Assuming LTL (for PSL a Boolean
|
|
||||||
// term is not stared will be regarded
|
|
||||||
// as not stuttering were this
|
|
||||||
// matters.)
|
|
||||||
is.sugar_free_ltl = true;
|
|
||||||
is.ltl_formula = true;
|
|
||||||
is.psl_formula = true;
|
|
||||||
is.sere_formula = true;
|
|
||||||
is.finite = true;
|
|
||||||
is.eventual = false;
|
|
||||||
is.universal = false;
|
|
||||||
is.syntactic_safety = true;
|
|
||||||
is.syntactic_guarantee = true;
|
|
||||||
is.syntactic_obligation = true;
|
|
||||||
is.syntactic_recurrence = true;
|
|
||||||
is.syntactic_persistence = true;
|
|
||||||
is.not_marked = true;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
// is.lbt_atomic_props should be true if the name has the form
|
|
||||||
// pNN where NN is any number of digit.
|
|
||||||
std::string::const_iterator pos = name.begin();
|
|
||||||
bool lbtap = (pos != name.end() && *pos++ == 'p');
|
|
||||||
while (lbtap && pos != name.end())
|
|
||||||
{
|
|
||||||
char l = *pos++;
|
|
||||||
lbtap = (l >= '0' && l <= '9');
|
|
||||||
}
|
|
||||||
is.lbt_atomic_props = lbtap;
|
|
||||||
is.spin_atomic_props = lbtap || is_spin_ap(name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_prop::~atomic_prop()
|
|
||||||
{
|
|
||||||
// Get this instance out of the instance map.
|
|
||||||
size_t c = instances.erase(key(name(), &env()));
|
|
||||||
assert(c == 1);
|
|
||||||
(void) c; // For the NDEBUG case.
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
atomic_prop::dump() const
|
|
||||||
{
|
|
||||||
return "AP(" + name() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
atomic_prop::accept(visitor& v) const
|
|
||||||
{
|
|
||||||
v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_prop::map atomic_prop::instances;
|
|
||||||
|
|
||||||
const atomic_prop*
|
|
||||||
atomic_prop::instance(const std::string& name, environment& env)
|
|
||||||
{
|
|
||||||
const atomic_prop* ap;
|
|
||||||
auto ires = instances.emplace(key(name, &env), nullptr);
|
|
||||||
if (!ires.second)
|
|
||||||
{
|
|
||||||
ap = ires.first->second;
|
|
||||||
ap->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ap = ires.first->second = new atomic_prop(name, env);
|
|
||||||
}
|
|
||||||
return ap;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
atomic_prop::instance_count()
|
|
||||||
{
|
|
||||||
return instances.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
atomic_prop::dump_instances(std::ostream& os)
|
|
||||||
{
|
|
||||||
for (const auto& i: instances)
|
|
||||||
os << i.second << " = " << 1 + i.second->refs_
|
|
||||||
<< " * atomic_prop(" << i.first.first << ", "
|
|
||||||
<< i.first.second->name() << ")\n";
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2012, 2013, 2014 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/atomic_prop.hh
|
|
||||||
/// \brief LTL atomic propositions
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "formula.hh"
|
|
||||||
#include <string>
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <map>
|
|
||||||
#include "ltlenv/environment.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
|
|
||||||
/// \ingroup ltl_ast
|
|
||||||
/// \brief Atomic propositions.
|
|
||||||
class SPOT_API atomic_prop final : public formula
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Build an atomic proposition with name \a name in
|
|
||||||
/// environment \a env.
|
|
||||||
static const atomic_prop*
|
|
||||||
instance(const std::string& name, environment& env);
|
|
||||||
|
|
||||||
virtual void accept(visitor& visitor) const override;
|
|
||||||
|
|
||||||
/// Get the name of the atomic proposition.
|
|
||||||
const std::string& name() const
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the environment of the atomic proposition.
|
|
||||||
environment& env() const
|
|
||||||
{
|
|
||||||
return *env_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a canonic representation of the atomic proposition
|
|
||||||
virtual std::string dump() const override;
|
|
||||||
|
|
||||||
/// Number of instantiated atomic propositions. For debugging.
|
|
||||||
static unsigned instance_count();
|
|
||||||
/// List all instances of atomic propositions. For debugging.
|
|
||||||
static std::ostream& dump_instances(std::ostream& os);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
atomic_prop(const std::string& name, environment& env);
|
|
||||||
virtual ~atomic_prop();
|
|
||||||
|
|
||||||
typedef std::pair<std::string, environment*> key;
|
|
||||||
typedef std::map<key, const atomic_prop*> map;
|
|
||||||
static map instances;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string name_;
|
|
||||||
environment* env_;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline
|
|
||||||
const atomic_prop*
|
|
||||||
is_atomic_prop(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->kind() != formula::AtomicProp)
|
|
||||||
return 0;
|
|
||||||
return static_cast<const atomic_prop*>(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,538 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire
|
|
||||||
// de Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris
|
|
||||||
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <utility>
|
|
||||||
#include "binop.hh"
|
|
||||||
#include "unop.hh"
|
|
||||||
#include "multop.hh"
|
|
||||||
#include "constant.hh"
|
|
||||||
#include "visitor.hh"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
binop::binop(type op, const formula* first, const formula* second)
|
|
||||||
: formula(BinOp), op_(op), first_(first), second_(second)
|
|
||||||
{
|
|
||||||
// Beware: (f U g) is a pure eventuality if both operands
|
|
||||||
// are pure eventualities, unlike in the proceedings of
|
|
||||||
// Concur'00. (The revision of the paper available at
|
|
||||||
// http://www.bell-labs.com/project/TMP/ is fixed.) See
|
|
||||||
// also http://arxiv.org/abs/1011.4214v2 for a discussion
|
|
||||||
// about this problem. (Which we fixed in 2005 thanks
|
|
||||||
// to LBTT.)
|
|
||||||
// This means that we can use the following line to handle
|
|
||||||
// all cases of (f U g), (f R g), (f W g), (f M g) for
|
|
||||||
// universality and eventuality.
|
|
||||||
props = first->get_props() & second->get_props();
|
|
||||||
// The matter can be further refined because:
|
|
||||||
// (f U g) is a pure eventuality if
|
|
||||||
// g is a pure eventuality (regardless of f),
|
|
||||||
// or f == 1
|
|
||||||
// (g M f) is a pure eventuality if f and g are,
|
|
||||||
// or f == 1
|
|
||||||
// (g R f) is purely universal if
|
|
||||||
// f is purely universal (regardless of g)
|
|
||||||
// or g == 0
|
|
||||||
// (f W g) is purely universal if f and g are
|
|
||||||
// or g == 0
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case Xor:
|
|
||||||
case Equiv:
|
|
||||||
is.eventual = false;
|
|
||||||
is.universal = false;
|
|
||||||
is.sere_formula = is.boolean;
|
|
||||||
is.sugar_free_boolean = false;
|
|
||||||
is.in_nenoform = false;
|
|
||||||
// is.syntactic_obligation inherited;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
if (is.syntactic_obligation)
|
|
||||||
{
|
|
||||||
// Only formula that are in the intersection of
|
|
||||||
// guarantee and safety are closed by Xor and <=>.
|
|
||||||
bool sg = is.syntactic_safety && is.syntactic_guarantee;
|
|
||||||
is.syntactic_safety = sg;
|
|
||||||
is.syntactic_guarantee = sg;
|
|
||||||
assert(is.syntactic_recurrence == true);
|
|
||||||
assert(is.syntactic_persistence == true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
is.syntactic_safety = false;
|
|
||||||
is.syntactic_guarantee = false;
|
|
||||||
is.syntactic_recurrence = false;
|
|
||||||
is.syntactic_persistence = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Implies:
|
|
||||||
is.eventual = false;
|
|
||||||
is.universal = false;
|
|
||||||
is.sere_formula = is.boolean;
|
|
||||||
is.sugar_free_boolean = false;
|
|
||||||
is.in_nenoform = false;
|
|
||||||
is.syntactic_safety =
|
|
||||||
first->is_syntactic_guarantee() && second->is_syntactic_safety();
|
|
||||||
is.syntactic_guarantee =
|
|
||||||
first->is_syntactic_safety() && second->is_syntactic_guarantee();
|
|
||||||
// is.syntactic_obligation inherited
|
|
||||||
is.syntactic_persistence = first->is_syntactic_recurrence()
|
|
||||||
&& second->is_syntactic_persistence();
|
|
||||||
is.syntactic_recurrence = first->is_syntactic_persistence()
|
|
||||||
&& second->is_syntactic_recurrence();
|
|
||||||
is.accepting_eword = false;
|
|
||||||
break;
|
|
||||||
case EConcatMarked:
|
|
||||||
case EConcat:
|
|
||||||
is.not_marked = (op != EConcatMarked);
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
is.psl_formula = true;
|
|
||||||
|
|
||||||
is.syntactic_guarantee = second->is_syntactic_guarantee();
|
|
||||||
is.syntactic_persistence = second->is_syntactic_persistence();
|
|
||||||
if (first->is_finite())
|
|
||||||
{
|
|
||||||
is.syntactic_safety = second->is_syntactic_safety();
|
|
||||||
is.syntactic_obligation = second->is_syntactic_obligation();
|
|
||||||
is.syntactic_recurrence = second->is_syntactic_recurrence();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
is.syntactic_safety = false;
|
|
||||||
is.syntactic_obligation = second->is_syntactic_guarantee();
|
|
||||||
is.syntactic_recurrence = second->is_syntactic_guarantee();
|
|
||||||
}
|
|
||||||
assert(first->is_sere_formula());
|
|
||||||
assert(second->is_psl_formula());
|
|
||||||
if (first->is_boolean())
|
|
||||||
is.syntactic_si = false;
|
|
||||||
break;
|
|
||||||
case UConcat:
|
|
||||||
is.not_marked = true;
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
is.psl_formula = true;
|
|
||||||
|
|
||||||
is.syntactic_safety = second->is_syntactic_safety();
|
|
||||||
is.syntactic_recurrence = second->is_syntactic_recurrence();
|
|
||||||
if (first->is_finite())
|
|
||||||
{
|
|
||||||
is.syntactic_guarantee = second->is_syntactic_guarantee();
|
|
||||||
is.syntactic_obligation = second->is_syntactic_obligation();
|
|
||||||
is.syntactic_persistence = second->is_syntactic_persistence();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
is.syntactic_guarantee = false;
|
|
||||||
is.syntactic_obligation = second->is_syntactic_safety();
|
|
||||||
is.syntactic_persistence = second->is_syntactic_safety();
|
|
||||||
}
|
|
||||||
assert(first->is_sere_formula());
|
|
||||||
assert(second->is_psl_formula());
|
|
||||||
if (first->is_boolean())
|
|
||||||
is.syntactic_si = false;
|
|
||||||
break;
|
|
||||||
case U:
|
|
||||||
is.not_marked = true;
|
|
||||||
// f U g is universal if g is eventual, or if f == 1.
|
|
||||||
is.eventual = second->is_eventual();
|
|
||||||
is.eventual |= (first == constant::true_instance());
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.finite = false;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
|
|
||||||
is.syntactic_safety = false;
|
|
||||||
// is.syntactic_guarantee = Guarantee U Guarantee
|
|
||||||
is.syntactic_obligation = // Obligation U Guarantee
|
|
||||||
first->is_syntactic_obligation()
|
|
||||||
&& second->is_syntactic_guarantee();
|
|
||||||
is.syntactic_recurrence = // Recurrence U Guarantee
|
|
||||||
first->is_syntactic_recurrence()
|
|
||||||
&& second->is_syntactic_guarantee();
|
|
||||||
// is.syntactic_persistence = Persistence U Persistance
|
|
||||||
break;
|
|
||||||
case W:
|
|
||||||
is.not_marked = true;
|
|
||||||
// f W g is universal if f and g are, or if g == 0.
|
|
||||||
is.universal |= (second == constant::false_instance());
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.finite = false;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
|
|
||||||
// is.syntactic_safety = Safety W Safety;
|
|
||||||
is.syntactic_guarantee = false;
|
|
||||||
is.syntactic_obligation = // Safety W Obligation
|
|
||||||
first->is_syntactic_safety() && second->is_syntactic_obligation();
|
|
||||||
// is.syntactic_recurrence = Recurrence W Recurrence
|
|
||||||
is.syntactic_persistence = // Safety W Persistance
|
|
||||||
first->is_syntactic_safety()
|
|
||||||
&& second->is_syntactic_persistence();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case R:
|
|
||||||
is.not_marked = true;
|
|
||||||
// g R f is universal if f is universal, or if g == 0.
|
|
||||||
is.universal = second->is_universal();
|
|
||||||
is.universal |= (first == constant::false_instance());
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.finite = false;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
|
|
||||||
// is.syntactic_safety = Safety R Safety;
|
|
||||||
is.syntactic_guarantee = false;
|
|
||||||
is.syntactic_obligation = // Obligation R Safety
|
|
||||||
first->is_syntactic_obligation() && second->is_syntactic_safety();
|
|
||||||
//is.syntactic_recurrence = Recurrence R Recurrence
|
|
||||||
is.syntactic_persistence = // Persistence R Safety
|
|
||||||
first->is_syntactic_persistence()
|
|
||||||
&& second->is_syntactic_safety();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case M:
|
|
||||||
is.not_marked = true;
|
|
||||||
// g M f is eventual if both g and f are eventual, or if f == 1.
|
|
||||||
is.eventual |= (second == constant::true_instance());
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.finite = false;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
|
|
||||||
is.syntactic_safety = false;
|
|
||||||
// is.syntactic_guarantee = Guarantee M Guarantee
|
|
||||||
is.syntactic_obligation = // Guarantee M Obligation
|
|
||||||
first->is_syntactic_guarantee()
|
|
||||||
&& second->is_syntactic_obligation();
|
|
||||||
is.syntactic_recurrence = // Guarantee M Recurrence
|
|
||||||
first->is_syntactic_guarantee()
|
|
||||||
&& second->is_syntactic_recurrence();
|
|
||||||
// is.syntactic_persistence = Persistence M Persistance
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert((!is.syntactic_obligation) ||
|
|
||||||
(is.syntactic_persistence && is.syntactic_recurrence));
|
|
||||||
}
|
|
||||||
|
|
||||||
binop::~binop()
|
|
||||||
{
|
|
||||||
// Get this instance out of the instance map.
|
|
||||||
size_t c = instances.erase(key(op(), first(), second()));
|
|
||||||
assert(c == 1);
|
|
||||||
(void) c; // For the NDEBUG case.
|
|
||||||
|
|
||||||
// Dereference children.
|
|
||||||
first()->destroy();
|
|
||||||
second()->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
binop::dump() const
|
|
||||||
{
|
|
||||||
return (std::string("binop(") + op_name()
|
|
||||||
+ ", " + first()->dump()
|
|
||||||
+ ", " + second()->dump() + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
binop::accept(visitor& v) const
|
|
||||||
{
|
|
||||||
v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
binop::op_name() const
|
|
||||||
{
|
|
||||||
switch (op_)
|
|
||||||
{
|
|
||||||
case Xor:
|
|
||||||
return "Xor";
|
|
||||||
case Implies:
|
|
||||||
return "Implies";
|
|
||||||
case Equiv:
|
|
||||||
return "Equiv";
|
|
||||||
case U:
|
|
||||||
return "U";
|
|
||||||
case R:
|
|
||||||
return "R";
|
|
||||||
case W:
|
|
||||||
return "W";
|
|
||||||
case M:
|
|
||||||
return "M";
|
|
||||||
case EConcat:
|
|
||||||
return "EConcat";
|
|
||||||
case EConcatMarked:
|
|
||||||
return "EConcatMarked";
|
|
||||||
case UConcat:
|
|
||||||
return "UConcat";
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
binop::map binop::instances;
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
binop::instance(type op, const formula* first, const formula* second)
|
|
||||||
{
|
|
||||||
// Sort the operands of commutative operators, so that for
|
|
||||||
// example the formula instance for 'a xor b' is the same as
|
|
||||||
// that for 'b xor a'.
|
|
||||||
|
|
||||||
// Trivial identities:
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case Xor:
|
|
||||||
{
|
|
||||||
// Xor is commutative: sort operands.
|
|
||||||
formula_ptr_less_than_bool_first cmp;
|
|
||||||
if (cmp(second, first))
|
|
||||||
std::swap(second, first);
|
|
||||||
}
|
|
||||||
// - (1 ^ Exp) = !Exp
|
|
||||||
// - (0 ^ Exp) = Exp
|
|
||||||
if (first == constant::true_instance())
|
|
||||||
return unop::instance(unop::Not, second);
|
|
||||||
if (first == constant::false_instance())
|
|
||||||
return second;
|
|
||||||
if (first == second)
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
second->destroy();
|
|
||||||
return constant::false_instance();
|
|
||||||
}
|
|
||||||
// We expect constants to appear first, because they are
|
|
||||||
// instantiated first.
|
|
||||||
assert(second != constant::false_instance());
|
|
||||||
assert(second != constant::true_instance());
|
|
||||||
break;
|
|
||||||
case Equiv:
|
|
||||||
{
|
|
||||||
// Equiv is commutative: sort operands.
|
|
||||||
formula_ptr_less_than_bool_first cmp;
|
|
||||||
if (cmp(second, first))
|
|
||||||
std::swap(second, first);
|
|
||||||
}
|
|
||||||
// - (0 <=> Exp) = !Exp
|
|
||||||
// - (1 <=> Exp) = Exp
|
|
||||||
// - (Exp <=> Exp) = 1
|
|
||||||
if (first == constant::false_instance())
|
|
||||||
return unop::instance(unop::Not, second);
|
|
||||||
if (first == constant::true_instance())
|
|
||||||
return second;
|
|
||||||
if (first == second)
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
second->destroy();
|
|
||||||
return constant::true_instance();
|
|
||||||
}
|
|
||||||
// We expect constants to appear first, because they are
|
|
||||||
// instantiated first.
|
|
||||||
assert(second != constant::false_instance());
|
|
||||||
assert(second != constant::true_instance());
|
|
||||||
break;
|
|
||||||
case Implies:
|
|
||||||
// - (1 => Exp) = Exp
|
|
||||||
// - (0 => Exp) = 1
|
|
||||||
// - (Exp => 1) = 1
|
|
||||||
// - (Exp => 0) = !Exp
|
|
||||||
// - (Exp => Exp) = 1
|
|
||||||
if (first == constant::true_instance())
|
|
||||||
return second;
|
|
||||||
if (first == constant::false_instance())
|
|
||||||
{
|
|
||||||
second->destroy();
|
|
||||||
return constant::true_instance();
|
|
||||||
}
|
|
||||||
if (second == constant::true_instance())
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
if (second == constant::false_instance())
|
|
||||||
return unop::instance(unop::Not, first);
|
|
||||||
if (first == second)
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
second->destroy();
|
|
||||||
return constant::true_instance();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case U:
|
|
||||||
// - (Exp U 1) = 1
|
|
||||||
// - (Exp U 0) = 0
|
|
||||||
// - (0 U Exp) = Exp
|
|
||||||
// - (Exp U Exp) = Exp
|
|
||||||
if (second == constant::true_instance()
|
|
||||||
|| second == constant::false_instance()
|
|
||||||
|| first == constant::false_instance()
|
|
||||||
|| first == second)
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case W:
|
|
||||||
// - (Exp W 1) = 1
|
|
||||||
// - (0 W Exp) = Exp
|
|
||||||
// - (1 W Exp) = 1
|
|
||||||
// - (Exp W Exp) = Exp
|
|
||||||
if (second == constant::true_instance()
|
|
||||||
|| first == constant::false_instance()
|
|
||||||
|| first == second)
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
if (first == constant::true_instance())
|
|
||||||
{
|
|
||||||
second->destroy();
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case R:
|
|
||||||
// - (Exp R 1) = 1
|
|
||||||
// - (Exp R 0) = 0
|
|
||||||
// - (1 R Exp) = Exp
|
|
||||||
// - (Exp R Exp) = Exp
|
|
||||||
if (second == constant::true_instance()
|
|
||||||
|| second == constant::false_instance()
|
|
||||||
|| first == constant::true_instance()
|
|
||||||
|| first == second)
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case M:
|
|
||||||
// - (Exp M 0) = 0
|
|
||||||
// - (1 M Exp) = Exp
|
|
||||||
// - (0 M Exp) = 0
|
|
||||||
// - (Exp M Exp) = Exp
|
|
||||||
if (second == constant::false_instance()
|
|
||||||
|| first == constant::true_instance()
|
|
||||||
|| first == second)
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
if (first == constant::false_instance())
|
|
||||||
{
|
|
||||||
second->destroy();
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EConcat:
|
|
||||||
case EConcatMarked:
|
|
||||||
// - 0 <>-> Exp = 0
|
|
||||||
// - 1 <>-> Exp = Exp
|
|
||||||
// - [*0] <>-> Exp = 0
|
|
||||||
// - Exp <>-> 0 = 0
|
|
||||||
// - boolExp <>-> Exp = boolExp & Exp
|
|
||||||
if (first == constant::true_instance())
|
|
||||||
return second;
|
|
||||||
if (first == constant::false_instance()
|
|
||||||
|| first == constant::empty_word_instance())
|
|
||||||
{
|
|
||||||
second->destroy();
|
|
||||||
return constant::false_instance();
|
|
||||||
}
|
|
||||||
if (second == constant::false_instance())
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
if (first->is_boolean())
|
|
||||||
return multop::instance(multop::And, first, second);
|
|
||||||
break;
|
|
||||||
case UConcat:
|
|
||||||
// - 0 []-> Exp = 1
|
|
||||||
// - 1 []-> Exp = Exp
|
|
||||||
// - [*0] []-> Exp = 1
|
|
||||||
// - Exp []-> 1 = 1
|
|
||||||
// - boolExp []-> Exp = !boolExp | Exp
|
|
||||||
if (first == constant::true_instance())
|
|
||||||
return second;
|
|
||||||
if (first == constant::false_instance()
|
|
||||||
|| first == constant::empty_word_instance())
|
|
||||||
{
|
|
||||||
second->destroy();
|
|
||||||
return constant::true_instance();
|
|
||||||
}
|
|
||||||
if (second == constant::true_instance())
|
|
||||||
{
|
|
||||||
first->destroy();
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
if (first->is_boolean())
|
|
||||||
return multop::instance(multop::Or,
|
|
||||||
unop::instance(unop::Not, first), second);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula* res;
|
|
||||||
auto ires = instances.emplace(key(op, first, second), nullptr);
|
|
||||||
if (!ires.second)
|
|
||||||
{
|
|
||||||
// This instance already exists.
|
|
||||||
first->destroy();
|
|
||||||
second->destroy();
|
|
||||||
res = ires.first->second->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = ires.first->second = new binop(op, first, second);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
binop::instance_count()
|
|
||||||
{
|
|
||||||
return instances.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
binop::dump_instances(std::ostream& os)
|
|
||||||
{
|
|
||||||
for (const auto& i: instances)
|
|
||||||
os << i.second << " = "
|
|
||||||
<< 1 + i.second->refs_ << " * "
|
|
||||||
<< i.second->dump() << '\n';
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,239 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Laboratoire de
|
|
||||||
// Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris
|
|
||||||
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/binop.hh
|
|
||||||
/// \brief LTL binary operators
|
|
||||||
///
|
|
||||||
/// This does not include \c AND and \c OR operators. These are
|
|
||||||
/// considered to be multi-operand operators (see spot::ltl::multop).
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "formula.hh"
|
|
||||||
#include <map>
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
|
|
||||||
/// \ingroup ltl_ast
|
|
||||||
/// \brief Binary operator.
|
|
||||||
class SPOT_API binop final: public formula
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Different kinds of binary opertaors
|
|
||||||
///
|
|
||||||
/// And and Or are not here. Because they
|
|
||||||
/// are often nested we represent them as multops.
|
|
||||||
enum type { Xor,
|
|
||||||
Implies,
|
|
||||||
Equiv,
|
|
||||||
U, ///< until
|
|
||||||
R, ///< release (dual of until)
|
|
||||||
W, ///< weak until
|
|
||||||
M, ///< strong release (dual of weak until)
|
|
||||||
EConcat, ///< Existential Concatenation
|
|
||||||
EConcatMarked, ///< Existential Concatenation, Marked
|
|
||||||
UConcat ///< Universal Concatenation
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Build a unary operator with operation \a op and
|
|
||||||
/// children \a first and \a second.
|
|
||||||
///
|
|
||||||
/// Some reordering will be performed on arguments of commutative
|
|
||||||
/// operators (Xor and Equiv) to ensure that for instance (a <=> b)
|
|
||||||
/// is the same formula as (b <=> a).
|
|
||||||
///
|
|
||||||
/// Furthermore, the following trivial simplifications are
|
|
||||||
/// performed (the left formula is rewritten as the right
|
|
||||||
/// formula):
|
|
||||||
/// - (1 => Exp) = Exp
|
|
||||||
/// - (0 => Exp) = 1
|
|
||||||
/// - (Exp => 1) = 1
|
|
||||||
/// - (Exp => 0) = !Exp
|
|
||||||
/// - (Exp => Exp) = 1
|
|
||||||
/// - (1 ^ Exp) = !Exp
|
|
||||||
/// - (0 ^ Exp) = Exp
|
|
||||||
/// - (Exp ^ Exp) = 0
|
|
||||||
/// - (0 <=> Exp) = !Exp
|
|
||||||
/// - (1 <=> Exp) = Exp
|
|
||||||
/// - (Exp <=> Exp) = Exp
|
|
||||||
/// - (Exp U 1) = 1
|
|
||||||
/// - (Exp U 0) = 0
|
|
||||||
/// - (0 U Exp) = Exp
|
|
||||||
/// - (Exp U Exp) = Exp
|
|
||||||
/// - (Exp W 1) = 1
|
|
||||||
/// - (0 W Exp) = Exp
|
|
||||||
/// - (1 W Exp) = 1
|
|
||||||
/// - (Exp W Exp) = Exp
|
|
||||||
/// - (Exp R 1) = 1
|
|
||||||
/// - (Exp R 0) = 0
|
|
||||||
/// - (1 R Exp) = Exp
|
|
||||||
/// - (Exp R Exp) = Exp
|
|
||||||
/// - (Exp M 0) = 0
|
|
||||||
/// - (1 M Exp) = Exp
|
|
||||||
/// - (0 M Exp) = 0
|
|
||||||
/// - (Exp M Exp) = Exp
|
|
||||||
/// - 0 <>-> Exp = 0
|
|
||||||
/// - 1 <>-> Exp = Exp
|
|
||||||
/// - [*0] <>-> Exp = 0
|
|
||||||
/// - Exp <>-> 0 = 0
|
|
||||||
/// - boolExp <>-> Exp = boolExp & Exp
|
|
||||||
/// - 0 []-> Exp = 1
|
|
||||||
/// - 1 []-> Exp = Exp
|
|
||||||
/// - [*0] []-> Exp = 1
|
|
||||||
/// - Exp []-> 1 = 1
|
|
||||||
/// - boolExp <>-> Exp = !boolExp | Exp
|
|
||||||
static const formula* instance(type op,
|
|
||||||
const formula* first,
|
|
||||||
const formula* second);
|
|
||||||
|
|
||||||
virtual void accept(visitor& v) const override;
|
|
||||||
|
|
||||||
/// Get the first operand.
|
|
||||||
const formula* first() const
|
|
||||||
{
|
|
||||||
return first_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the second operand.
|
|
||||||
const formula* second() const
|
|
||||||
{
|
|
||||||
return second_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of this operator.
|
|
||||||
type op() const
|
|
||||||
{
|
|
||||||
return op_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of this operator, as a string.
|
|
||||||
const char* op_name() const;
|
|
||||||
|
|
||||||
/// Return a canonic representation of the atomic proposition
|
|
||||||
virtual std::string dump() const override;
|
|
||||||
|
|
||||||
/// Number of instantiated binary operators. For debugging.
|
|
||||||
static unsigned instance_count();
|
|
||||||
|
|
||||||
/// Dump all instances. For debugging.
|
|
||||||
static std::ostream& dump_instances(std::ostream& os);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef std::tuple<type, const formula*, const formula*> key;
|
|
||||||
typedef std::map<key, const binop*> map;
|
|
||||||
static map instances;
|
|
||||||
|
|
||||||
binop(type op, const formula* first, const formula* second);
|
|
||||||
virtual ~binop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
type op_;
|
|
||||||
const formula* first_;
|
|
||||||
const formula* second_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a binop
|
|
||||||
///
|
|
||||||
/// Cast \a f into a binop iff it is a binop instance. Return 0
|
|
||||||
/// otherwise. This is faster than \c dynamic_cast.
|
|
||||||
inline
|
|
||||||
const binop*
|
|
||||||
is_binop(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->kind() != formula::BinOp)
|
|
||||||
return 0;
|
|
||||||
return static_cast<const binop*>(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a binop if it has type \a op.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a binop iff it is a unop instance with operator \a op.
|
|
||||||
/// Returns 0 otherwise.
|
|
||||||
inline
|
|
||||||
const binop*
|
|
||||||
is_binop(const formula* f, binop::type op)
|
|
||||||
{
|
|
||||||
if (const binop* bo = is_binop(f))
|
|
||||||
if (bo->op() == op)
|
|
||||||
return bo;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a binop if it has type \a op1 or \a op2.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a binop iff it is a unop instance with operator \a op1 or
|
|
||||||
/// \a op2. Returns 0 otherwise.
|
|
||||||
inline
|
|
||||||
const binop*
|
|
||||||
is_binop(const formula* f, binop::type op1, binop::type op2)
|
|
||||||
{
|
|
||||||
if (const binop* bo = is_binop(f))
|
|
||||||
if (bo->op() == op1 || bo->op() == op2)
|
|
||||||
return bo;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a binop if it is a U.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const binop*
|
|
||||||
is_U(const formula* f)
|
|
||||||
{
|
|
||||||
return is_binop(f, binop::U);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a binop if it is a M.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const binop*
|
|
||||||
is_M(const formula* f)
|
|
||||||
{
|
|
||||||
return is_binop(f, binop::M);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a binop if it is a R.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const binop*
|
|
||||||
is_R(const formula* f)
|
|
||||||
{
|
|
||||||
return is_binop(f, binop::R);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a binop if it is a W.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const binop*
|
|
||||||
is_W(const formula* f)
|
|
||||||
{
|
|
||||||
return is_binop(f, binop::W);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,350 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
|
|
||||||
// Recherche et Développement de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "bunop.hh"
|
|
||||||
#include "visitor.hh"
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include "constant.hh"
|
|
||||||
#include "unop.hh"
|
|
||||||
#include "multop.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
// Can't build it on startup, because it uses
|
|
||||||
// constant::true_instance that may not have been built yet...
|
|
||||||
const formula* bunop::one_star_ = 0;
|
|
||||||
|
|
||||||
bunop::bunop(type op, const formula* child, unsigned min, unsigned max)
|
|
||||||
: formula(BUnOp), op_(op), child_(child), min_(min), max_(max)
|
|
||||||
{
|
|
||||||
props = child->get_props();
|
|
||||||
|
|
||||||
assert(is.sere_formula);
|
|
||||||
is.boolean = false;
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.psl_formula = false;
|
|
||||||
is.eventual = false;
|
|
||||||
is.universal = false;
|
|
||||||
is.syntactic_safety = false;
|
|
||||||
is.syntactic_guarantee = false;
|
|
||||||
is.syntactic_obligation = false;
|
|
||||||
is.syntactic_recurrence = false;
|
|
||||||
is.syntactic_persistence = false;
|
|
||||||
|
|
||||||
switch (op_)
|
|
||||||
{
|
|
||||||
case Star:
|
|
||||||
if (max_ == unbounded)
|
|
||||||
{
|
|
||||||
is.finite = false;
|
|
||||||
is.syntactic_si = min_ == 1 && child->is_boolean();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
is.syntactic_si = false;
|
|
||||||
}
|
|
||||||
if (min_ == 0)
|
|
||||||
is.accepting_eword = true;
|
|
||||||
break;
|
|
||||||
case FStar:
|
|
||||||
is.accepting_eword = false;
|
|
||||||
is.syntactic_si &= !child->is_boolean();
|
|
||||||
if (max_ == unbounded)
|
|
||||||
is.finite = false;
|
|
||||||
if (min_ == 0)
|
|
||||||
is.syntactic_si = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bunop::~bunop()
|
|
||||||
{
|
|
||||||
// one_star_ should never get deleted. Otherwise, that means it
|
|
||||||
// has been destroyed too much, or not cloned enough.
|
|
||||||
assert(this != one_star_);
|
|
||||||
|
|
||||||
// Get this instance out of the instance map.
|
|
||||||
size_t c = instances.erase(key(op(), child(), min_, max_));
|
|
||||||
assert(c == 1);
|
|
||||||
(void) c; // For the NDEBUG case.
|
|
||||||
|
|
||||||
// Dereference child.
|
|
||||||
child()->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
bunop::dump() const
|
|
||||||
{
|
|
||||||
std::ostringstream out;
|
|
||||||
out << "bunop(" << op_name() << ", "
|
|
||||||
<< child()->dump() << ", " << min_ << ", ";
|
|
||||||
if (max_ == unbounded)
|
|
||||||
out << "unbounded";
|
|
||||||
else
|
|
||||||
out << max_;
|
|
||||||
out << ')';
|
|
||||||
return out.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
bunop::accept(visitor& v) const
|
|
||||||
{
|
|
||||||
v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
bunop::op_name() const
|
|
||||||
{
|
|
||||||
switch (op_)
|
|
||||||
{
|
|
||||||
case Star:
|
|
||||||
return "Star";
|
|
||||||
case FStar:
|
|
||||||
return "FStar";
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
bunop::format() const
|
|
||||||
{
|
|
||||||
std::ostringstream out;
|
|
||||||
|
|
||||||
switch (op_)
|
|
||||||
{
|
|
||||||
case Star:
|
|
||||||
// Syntactic sugaring
|
|
||||||
if (min_ == 1 && max_ == unbounded)
|
|
||||||
return "[+]";
|
|
||||||
out << "[*";
|
|
||||||
break;
|
|
||||||
case FStar:
|
|
||||||
// Syntactic sugaring
|
|
||||||
if (min_ == 1 && max_ == unbounded)
|
|
||||||
return "[:+]";
|
|
||||||
out << "[:*";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (min_ != 0 || max_ != unbounded)
|
|
||||||
{
|
|
||||||
// Always print the min_, even when it is equal to 0, this
|
|
||||||
// way we avoid ambiguities (like when reading
|
|
||||||
// a[*..3];b[->..2] which actually means a[*0..3];b[->1..2].
|
|
||||||
out << min_;
|
|
||||||
if (min_ != max_)
|
|
||||||
{
|
|
||||||
out << "..";
|
|
||||||
if (max_ != unbounded)
|
|
||||||
out << max_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out << ']';
|
|
||||||
return out.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
bunop::map bunop::instances;
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
bunop::instance(type op, const formula* child,
|
|
||||||
unsigned min, unsigned max)
|
|
||||||
{
|
|
||||||
assert(min <= max);
|
|
||||||
|
|
||||||
const formula* neutral = nullptr;
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case Star:
|
|
||||||
neutral = constant::empty_word_instance();
|
|
||||||
break;
|
|
||||||
case FStar:
|
|
||||||
neutral = constant::true_instance();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// common trivial simplifications
|
|
||||||
|
|
||||||
// - [*0][*min..max] = [*0]
|
|
||||||
// - [*0][:*0..max] = 1
|
|
||||||
// - [*0][:*min..max] = 0 if min > 0
|
|
||||||
if (child == constant::empty_word_instance())
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case Star:
|
|
||||||
return neutral;
|
|
||||||
case FStar:
|
|
||||||
if (min == 0)
|
|
||||||
return neutral;
|
|
||||||
else
|
|
||||||
return constant::false_instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// - 0[*0..max] = [*0]
|
|
||||||
// - 0[*min..max] = 0 if min > 0
|
|
||||||
// - b[:*0..max] = 1
|
|
||||||
// - b[:*min..max] = 0 if min > 0
|
|
||||||
if (child == constant::false_instance()
|
|
||||||
|| (op == FStar && child->is_boolean()))
|
|
||||||
{
|
|
||||||
if (min == 0)
|
|
||||||
{
|
|
||||||
child->destroy();
|
|
||||||
return neutral;
|
|
||||||
}
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - Exp[*0] = [*0]
|
|
||||||
// - Exp[:*0] = 1
|
|
||||||
if (max == 0)
|
|
||||||
{
|
|
||||||
child->destroy();
|
|
||||||
return neutral;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - Exp[*1] = Exp
|
|
||||||
// - Exp[:*1] = Exp if Exp does not accept [*0]
|
|
||||||
if (min == 1 && max == 1)
|
|
||||||
if (op == Star || !child->accepts_eword())
|
|
||||||
return child;
|
|
||||||
|
|
||||||
// - Exp[*i..j][*k..l] = Exp[*ik..jl] if i*(k+1)<=jk+1.
|
|
||||||
// - Exp[:*i..j][:*k..l] = Exp[:*ik..jl] if i*(k+1)<=jk+1.
|
|
||||||
if (const bunop* s = is_bunop(child, op))
|
|
||||||
{
|
|
||||||
unsigned i = s->min();
|
|
||||||
unsigned j = s->max();
|
|
||||||
|
|
||||||
// Exp has to be true between i*min and j*min
|
|
||||||
// then between i*(min+1) and j*(min+1)
|
|
||||||
// ...
|
|
||||||
// finally between i*max and j*max
|
|
||||||
//
|
|
||||||
// We can merge these intervals into [i*min..j*max] iff the
|
|
||||||
// first are adjacent or overlap, i.e. iff
|
|
||||||
// i*(min+1) <= j*min+1.
|
|
||||||
// (Because i<=j, this entails that the other intervals also
|
|
||||||
// overlap).
|
|
||||||
|
|
||||||
const formula* exp = s->child();
|
|
||||||
if (j == unbounded)
|
|
||||||
{
|
|
||||||
min *= i;
|
|
||||||
max = unbounded;
|
|
||||||
|
|
||||||
// Exp[*min..max]
|
|
||||||
exp->clone();
|
|
||||||
child->destroy();
|
|
||||||
child = exp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (i * (min + 1) <= (j * min) + 1)
|
|
||||||
{
|
|
||||||
min *= i;
|
|
||||||
if (max != unbounded)
|
|
||||||
{
|
|
||||||
if (j == unbounded)
|
|
||||||
max = unbounded;
|
|
||||||
else
|
|
||||||
max *= j;
|
|
||||||
}
|
|
||||||
exp->clone();
|
|
||||||
child->destroy();
|
|
||||||
child = exp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula* res;
|
|
||||||
auto ires = instances.emplace(key(op, child, min, max), nullptr);
|
|
||||||
if (!ires.second)
|
|
||||||
{
|
|
||||||
// This instance already exists.
|
|
||||||
child->destroy();
|
|
||||||
res = ires.first->second->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = ires.first->second = new bunop(op, child, min, max);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
bunop::sugar_goto(const formula* b, unsigned min, unsigned max)
|
|
||||||
{
|
|
||||||
assert(b->is_boolean());
|
|
||||||
// b[->min..max] is implemented as ((!b)[*];b)[*min..max]
|
|
||||||
const formula* s =
|
|
||||||
bunop::instance(bunop::Star,
|
|
||||||
unop::instance(unop::Not, b->clone()));
|
|
||||||
return bunop::instance(bunop::Star,
|
|
||||||
multop::instance(multop::Concat, s, b),
|
|
||||||
min, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
bunop::sugar_equal(const formula* b, unsigned min, unsigned max)
|
|
||||||
{
|
|
||||||
assert(b->is_boolean());
|
|
||||||
// b[=0..] = 1[*]
|
|
||||||
if (min == 0 && max == unbounded)
|
|
||||||
{
|
|
||||||
b->destroy();
|
|
||||||
return instance(Star, constant::true_instance());
|
|
||||||
}
|
|
||||||
|
|
||||||
// b[=min..max] is implemented as ((!b)[*];b)[*min..max];(!b)[*]
|
|
||||||
const formula* s =
|
|
||||||
bunop::instance(bunop::Star,
|
|
||||||
unop::instance(unop::Not, b->clone()));
|
|
||||||
const formula* t =
|
|
||||||
bunop::instance(bunop::Star,
|
|
||||||
multop::instance(multop::Concat,
|
|
||||||
s->clone(), b), min, max);
|
|
||||||
return multop::instance(multop::Concat, t, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
bunop::instance_count()
|
|
||||||
{
|
|
||||||
// Don't count one_star_ since it should not be destroyed.
|
|
||||||
return instances.size() - !!one_star_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
bunop::dump_instances(std::ostream& os)
|
|
||||||
{
|
|
||||||
for (const auto& i: instances)
|
|
||||||
os << i.second << " = "
|
|
||||||
<< 1 + i.second->refs_ << " * "
|
|
||||||
<< i.second->dump()
|
|
||||||
<< '\n';
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de Recherche
|
|
||||||
// et Développement de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/bunop.hh
|
|
||||||
/// \brief Bounded Unary operators
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "formula.hh"
|
|
||||||
#include <map>
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <tuple>
|
|
||||||
#include "constant.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
|
|
||||||
/// \ingroup ltl_ast
|
|
||||||
/// \brief Bounded unary operator.
|
|
||||||
class SPOT_API bunop final : public formula
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum type { Star, FStar };
|
|
||||||
|
|
||||||
static const unsigned unbounded = -1U;
|
|
||||||
|
|
||||||
/// \brief Build a bunop with bounds \a min and \a max.
|
|
||||||
///
|
|
||||||
/// The following trivial simplifications are performed
|
|
||||||
/// automatically (the left expression is rewritten as the right
|
|
||||||
/// expression):
|
|
||||||
/// - 0[*0..max] = [*0]
|
|
||||||
/// - 0[*min..max] = 0 if min > 0
|
|
||||||
/// - [*0][*min..max] = [*0]
|
|
||||||
/// - Exp[*i..j][*k..l] = Exp[*ik..jl] if i*(k+1)<=jk+1.
|
|
||||||
/// - Exp[*0] = [*0]
|
|
||||||
/// - Exp[*1] = Exp
|
|
||||||
/// - b[:*0..max] = 1
|
|
||||||
/// - b[:*min..max] = b if min > 0
|
|
||||||
/// - [*0][:*0..max] = 1
|
|
||||||
/// - [*0][:*min..max] = 0 if min > 0
|
|
||||||
/// - Exp[:*i..j][:*k..l] = Exp[:*ik..jl] if i*(k+1)<=jk+1.
|
|
||||||
/// - Exp[:*0] = 1
|
|
||||||
/// - Exp[:*1] = Exp if Exp does not accept [*0]
|
|
||||||
///
|
|
||||||
/// These rewriting rules imply that it is not possible to build
|
|
||||||
/// an LTL formula object that is SYNTACTICALLY equal to one of
|
|
||||||
/// these left expressions.
|
|
||||||
static const formula* instance(type op,
|
|
||||||
const formula* child,
|
|
||||||
unsigned min = 0,
|
|
||||||
unsigned max = unbounded);
|
|
||||||
|
|
||||||
/// \brief Implement <code>b[->i..j]</code> using the Kleen star.
|
|
||||||
///
|
|
||||||
/// <code>b[->i..j]</code> is implemented as
|
|
||||||
/// <code>((!b)[*];b)[*i..j]</code>.
|
|
||||||
///
|
|
||||||
/// Note that \a min defaults to 1, not 0, because [->] means
|
|
||||||
/// [->1..].
|
|
||||||
///
|
|
||||||
/// \pre \a child must be a Boolean formula.
|
|
||||||
static const formula* sugar_goto(const formula* child,
|
|
||||||
unsigned min = 1,
|
|
||||||
unsigned max = unbounded);
|
|
||||||
|
|
||||||
/// \brief Implement b[=i..j] using the Kleen star.
|
|
||||||
///
|
|
||||||
/// <code>b[=i..j]</code> is implemented as
|
|
||||||
/// <code>((!b)[*];b)[*i..j];(!b)[*]</code>.
|
|
||||||
///
|
|
||||||
/// \pre \a child must be a Boolean formula.
|
|
||||||
static const formula* sugar_equal(const formula* child,
|
|
||||||
unsigned min = 0,
|
|
||||||
unsigned max = unbounded);
|
|
||||||
|
|
||||||
virtual void accept(visitor& v) const override;
|
|
||||||
|
|
||||||
/// Get the sole operand of this operator.
|
|
||||||
const formula* child() const
|
|
||||||
{
|
|
||||||
return child_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Minimum number of repetition.
|
|
||||||
unsigned min() const
|
|
||||||
{
|
|
||||||
return min_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Minimum number of repetition.
|
|
||||||
unsigned max() const
|
|
||||||
{
|
|
||||||
return max_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief A string representation of the operator.
|
|
||||||
///
|
|
||||||
/// For instance "[*2..]".
|
|
||||||
std::string format() const;
|
|
||||||
|
|
||||||
/// Get the type of this operator.
|
|
||||||
type op() const
|
|
||||||
{
|
|
||||||
return op_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of this operator, as a string.
|
|
||||||
const char* op_name() const;
|
|
||||||
|
|
||||||
/// Return a canonic representation of operation.
|
|
||||||
virtual std::string dump() const override;
|
|
||||||
|
|
||||||
/// Number of instantiated unary operators. For debugging.
|
|
||||||
static unsigned instance_count();
|
|
||||||
|
|
||||||
/// Dump all instances. For debugging.
|
|
||||||
static std::ostream& dump_instances(std::ostream& os);
|
|
||||||
|
|
||||||
/// \brief Return a formula for <code>1[*]</code>.
|
|
||||||
///
|
|
||||||
/// A global instance is returned, and it should not be
|
|
||||||
/// destroyed. Remember to clone it if you use it to build a
|
|
||||||
/// formula.
|
|
||||||
static const formula* one_star()
|
|
||||||
{
|
|
||||||
if (!one_star_)
|
|
||||||
one_star_ = instance(Star, constant::true_instance());
|
|
||||||
return one_star_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef std::tuple<type, const formula*, unsigned, unsigned> key;
|
|
||||||
typedef std::map<key, const bunop*> map;
|
|
||||||
static map instances;
|
|
||||||
|
|
||||||
bunop(type op, const formula* child, unsigned min, unsigned max);
|
|
||||||
virtual ~bunop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
type op_;
|
|
||||||
const formula* child_;
|
|
||||||
unsigned min_;
|
|
||||||
unsigned max_;
|
|
||||||
static const formula* one_star_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a bunop.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a bunop iff it is a bunop instance. Return 0
|
|
||||||
/// otherwise. This is faster than \c dynamic_cast.
|
|
||||||
inline
|
|
||||||
const bunop*
|
|
||||||
is_bunop(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->kind() != formula::BUnOp)
|
|
||||||
return 0;
|
|
||||||
return static_cast<const bunop*>(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a bunop if it has type \a op.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a bunop iff it is a bunop instance with operator \a op.
|
|
||||||
/// Returns 0 otherwise.
|
|
||||||
inline
|
|
||||||
const bunop*
|
|
||||||
is_bunop(const formula* f, bunop::type op)
|
|
||||||
{
|
|
||||||
if (const bunop* bo = is_bunop(f))
|
|
||||||
if (bo->op() == op)
|
|
||||||
return bo;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a bunop if it is a Star.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const bunop*
|
|
||||||
is_Star(const formula* f)
|
|
||||||
{
|
|
||||||
return is_bunop(f, bunop::Star);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a bunop if it is a Star[0..].
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const bunop*
|
|
||||||
is_KleenStar(const formula* f)
|
|
||||||
{
|
|
||||||
if (const bunop* b = is_Star(f))
|
|
||||||
if (b->min() == 0 && b->max() == bunop::unbounded)
|
|
||||||
return b;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire
|
|
||||||
// de Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris
|
|
||||||
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "constant.hh"
|
|
||||||
#include "visitor.hh"
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
constant constant::true_instance_(constant::True);
|
|
||||||
constant constant::false_instance_(constant::False);
|
|
||||||
constant constant::empty_word_instance_(constant::EmptyWord);
|
|
||||||
|
|
||||||
constant::constant(type val)
|
|
||||||
: formula(Constant), val_(val)
|
|
||||||
{
|
|
||||||
switch (val)
|
|
||||||
{
|
|
||||||
case constant::True:
|
|
||||||
case constant::False:
|
|
||||||
is.boolean = true;
|
|
||||||
is.sugar_free_boolean = true;
|
|
||||||
is.in_nenoform = true;
|
|
||||||
is.syntactic_si = true; // for LTL (not PSL)
|
|
||||||
is.sugar_free_ltl = true;
|
|
||||||
is.ltl_formula = true;
|
|
||||||
is.psl_formula = true;
|
|
||||||
is.sere_formula = true;
|
|
||||||
is.finite = true;
|
|
||||||
is.eventual = true;
|
|
||||||
is.universal = true;
|
|
||||||
is.syntactic_safety = true;
|
|
||||||
is.syntactic_guarantee = true;
|
|
||||||
is.syntactic_obligation = true;
|
|
||||||
is.syntactic_recurrence = true;
|
|
||||||
is.syntactic_persistence = true;
|
|
||||||
is.not_marked = true;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
is.lbt_atomic_props = true;
|
|
||||||
is.spin_atomic_props = true;
|
|
||||||
break;
|
|
||||||
case constant::EmptyWord:
|
|
||||||
is.boolean = false;
|
|
||||||
is.sugar_free_boolean = false;
|
|
||||||
is.in_nenoform = true;
|
|
||||||
is.syntactic_si = true;
|
|
||||||
is.sugar_free_ltl = true;
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.psl_formula = false;
|
|
||||||
is.sere_formula = true;
|
|
||||||
is.finite = true;
|
|
||||||
is.eventual = false;
|
|
||||||
is.syntactic_safety = false;
|
|
||||||
is.syntactic_guarantee = false;
|
|
||||||
is.syntactic_obligation = false;
|
|
||||||
is.syntactic_recurrence = false;
|
|
||||||
is.syntactic_persistence = false;
|
|
||||||
is.universal = false;
|
|
||||||
is.not_marked = true;
|
|
||||||
is.accepting_eword = true;
|
|
||||||
is.lbt_atomic_props = true;
|
|
||||||
is.spin_atomic_props = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constant::~constant()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
constant::dump() const
|
|
||||||
{
|
|
||||||
switch (val())
|
|
||||||
{
|
|
||||||
case True:
|
|
||||||
return "constant(1)";
|
|
||||||
case False:
|
|
||||||
return "constant(0)";
|
|
||||||
case EmptyWord:
|
|
||||||
return "constant(e)";
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
constant::accept(visitor& v) const
|
|
||||||
{
|
|
||||||
v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
constant::val_name() const
|
|
||||||
{
|
|
||||||
switch (val_)
|
|
||||||
{
|
|
||||||
case True:
|
|
||||||
return "1";
|
|
||||||
case False:
|
|
||||||
return "0";
|
|
||||||
case EmptyWord:
|
|
||||||
return "[*0]";
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche
|
|
||||||
// et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/constant.hh
|
|
||||||
/// \brief LTL constants
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "formula.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
|
|
||||||
/// \ingroup ltl_ast
|
|
||||||
/// \brief A constant (True or False)
|
|
||||||
class SPOT_API constant final : public formula
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum type { False, True, EmptyWord };
|
|
||||||
virtual void accept(visitor& v) const override;
|
|
||||||
|
|
||||||
/// Return the value of the constant.
|
|
||||||
type val() const
|
|
||||||
{
|
|
||||||
return val_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the value of the constant as a string.
|
|
||||||
const char* val_name() const;
|
|
||||||
|
|
||||||
virtual std::string dump() const override;
|
|
||||||
|
|
||||||
/// Get the sole instance of spot::ltl::constant::constant(True).
|
|
||||||
static constant* true_instance() { return &true_instance_; }
|
|
||||||
/// Get the sole instance of spot::ltl::constant::constant(False).
|
|
||||||
static constant* false_instance() { return &false_instance_; }
|
|
||||||
/// Get the sole instance of spot::ltl::constant::constant(EmptyWord).
|
|
||||||
static constant* empty_word_instance() { return &empty_word_instance_; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
constant(type val);
|
|
||||||
virtual ~constant();
|
|
||||||
|
|
||||||
private:
|
|
||||||
type val_;
|
|
||||||
|
|
||||||
static constant true_instance_;
|
|
||||||
static constant false_instance_;
|
|
||||||
static constant empty_word_instance_;
|
|
||||||
// If you add new constants here, be sure to update the
|
|
||||||
// formula::formula() constructor.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a constant.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a constant iff it is a constant instance.
|
|
||||||
/// Return 0 otherwise. This is faster than \c dynamic_cast.
|
|
||||||
inline
|
|
||||||
const constant*
|
|
||||||
is_constant(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->kind() != formula::Constant)
|
|
||||||
return 0;
|
|
||||||
return static_cast<const constant*>(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,699 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
|
|
||||||
// Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de
|
|
||||||
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cassert>
|
|
||||||
#include <utility>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include "multop.hh"
|
|
||||||
#include "constant.hh"
|
|
||||||
#include "bunop.hh"
|
|
||||||
#include "visitor.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
multop::multop(type op, vec* v)
|
|
||||||
: formula(MultOp), op_(op), children_(v)
|
|
||||||
{
|
|
||||||
unsigned s = v->size();
|
|
||||||
assert(s > 1);
|
|
||||||
|
|
||||||
props = (*v)[0]->get_props();
|
|
||||||
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case Fusion:
|
|
||||||
is.accepting_eword = false;
|
|
||||||
case Concat:
|
|
||||||
case AndNLM:
|
|
||||||
case AndRat:
|
|
||||||
{
|
|
||||||
bool syntactic_si = is.syntactic_si && !is.boolean;
|
|
||||||
// Note: AndNLM(p1,p2) and AndRat(p1,p2) are Boolean
|
|
||||||
// formulae, but they are actually rewritten as And(p1,p2)
|
|
||||||
// by trivial identities before this constructor is called.
|
|
||||||
// So at this point, AndNLM/AndRat are always used with at
|
|
||||||
// most one Boolean argument, and the result is therefore
|
|
||||||
// NOT Boolean.
|
|
||||||
is.boolean = false;
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.psl_formula = false;
|
|
||||||
is.eventual = false;
|
|
||||||
is.universal = false;
|
|
||||||
|
|
||||||
for (unsigned i = 1; i < s; ++i)
|
|
||||||
{
|
|
||||||
syntactic_si &= (*v)[i]->is_syntactic_stutter_invariant()
|
|
||||||
&& !(*v)[i]->is_boolean();
|
|
||||||
props &= (*v)[i]->get_props();
|
|
||||||
}
|
|
||||||
is.syntactic_si = syntactic_si;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case And:
|
|
||||||
for (unsigned i = 1; i < s; ++i)
|
|
||||||
props &= (*v)[i]->get_props();
|
|
||||||
break;
|
|
||||||
case OrRat:
|
|
||||||
{
|
|
||||||
bool syntactic_si = is.syntactic_si && !is.boolean;
|
|
||||||
// Note: OrRat(p1,p2) is a Boolean formula, but its is
|
|
||||||
// actually rewritten as Or(p1,p2) by trivial identities
|
|
||||||
// before this constructor is called. So at this point,
|
|
||||||
// AndNLM is always used with at most one Boolean argument,
|
|
||||||
// and the result is therefore NOT Boolean.
|
|
||||||
is.boolean = false;
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.psl_formula = false;
|
|
||||||
is.eventual = false;
|
|
||||||
is.universal = false;
|
|
||||||
|
|
||||||
bool ew = (*v)[0]->accepts_eword();
|
|
||||||
for (unsigned i = 1; i < s; ++i)
|
|
||||||
{
|
|
||||||
ew |= (*v)[i]->accepts_eword();
|
|
||||||
syntactic_si &= (*v)[i]->is_syntactic_stutter_invariant()
|
|
||||||
&& !(*v)[i]->is_boolean();
|
|
||||||
props &= (*v)[i]->get_props();
|
|
||||||
}
|
|
||||||
is.accepting_eword = ew;
|
|
||||||
is.syntactic_si = syntactic_si;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Or:
|
|
||||||
{
|
|
||||||
bool ew = (*v)[0]->accepts_eword();
|
|
||||||
for (unsigned i = 1; i < s; ++i)
|
|
||||||
{
|
|
||||||
ew |= (*v)[i]->accepts_eword();
|
|
||||||
props &= (*v)[i]->get_props();
|
|
||||||
}
|
|
||||||
is.accepting_eword = ew;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// A concatenation is an siSERE if it contains one stared
|
|
||||||
// Boolean, and the other operands are siSERE (i.e.,
|
|
||||||
// sub-formulas that verify is_syntactic_stutter_invariant() and
|
|
||||||
// !is_boolean());
|
|
||||||
if (op == Concat)
|
|
||||||
{
|
|
||||||
unsigned sb = 0; // stared Boolean formulas seen
|
|
||||||
for (unsigned i = 0; i < s; ++i)
|
|
||||||
{
|
|
||||||
if ((*v)[i]->is_syntactic_stutter_invariant()
|
|
||||||
&& !(*v)[i]->is_boolean())
|
|
||||||
continue;
|
|
||||||
if (const bunop* b = is_Star((*v)[i]))
|
|
||||||
{
|
|
||||||
sb += b->child()->is_boolean();
|
|
||||||
if (sb > 1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is.syntactic_si = sb == 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
multop::~multop()
|
|
||||||
{
|
|
||||||
// Get this instance out of the instance map.
|
|
||||||
size_t c = instances.erase(key(op(), children_));
|
|
||||||
assert(c == 1);
|
|
||||||
(void) c; // For the NDEBUG case.
|
|
||||||
|
|
||||||
// Dereference children.
|
|
||||||
unsigned s = size();
|
|
||||||
for (unsigned n = 0; n < s; ++n)
|
|
||||||
nth(n)->destroy();
|
|
||||||
|
|
||||||
delete children_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
multop::dump() const
|
|
||||||
{
|
|
||||||
std::string r = "multop(";
|
|
||||||
r += op_name();
|
|
||||||
unsigned max = size();
|
|
||||||
for (unsigned n = 0; n < max; ++n)
|
|
||||||
r += ", " + nth(n)->dump();
|
|
||||||
r += ")";
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
multop::accept(visitor& v) const
|
|
||||||
{
|
|
||||||
v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
multop::all_but(unsigned n) const
|
|
||||||
{
|
|
||||||
unsigned s = size();
|
|
||||||
vec* v = new vec;
|
|
||||||
v->reserve(s - 1);
|
|
||||||
for (unsigned pos = 0; pos < n; ++pos)
|
|
||||||
v->push_back(nth(pos)->clone());
|
|
||||||
for (unsigned pos = n + 1; pos < s; ++pos)
|
|
||||||
v->push_back(nth(pos)->clone());
|
|
||||||
return instance(op_, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
multop::boolean_count() const
|
|
||||||
{
|
|
||||||
unsigned pos = 0;
|
|
||||||
unsigned s = size();
|
|
||||||
while (pos < s && nth(pos)->is_boolean())
|
|
||||||
++pos;
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
multop::boolean_operands(unsigned* width) const
|
|
||||||
{
|
|
||||||
unsigned s = boolean_count();
|
|
||||||
if (width)
|
|
||||||
*width = s;
|
|
||||||
if (!s)
|
|
||||||
return 0;
|
|
||||||
if (s == 1)
|
|
||||||
return nth(0)->clone();
|
|
||||||
vec* v = new vec(children_->begin(),
|
|
||||||
children_->begin() + s);
|
|
||||||
for (unsigned n = 0; n < s; ++n)
|
|
||||||
(*v)[n]->clone();
|
|
||||||
return instance(op_, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
multop::op_name() const
|
|
||||||
{
|
|
||||||
switch (op_)
|
|
||||||
{
|
|
||||||
case And:
|
|
||||||
return "And";
|
|
||||||
case AndRat:
|
|
||||||
return "AndRat";
|
|
||||||
case AndNLM:
|
|
||||||
return "AndNLM";
|
|
||||||
case Or:
|
|
||||||
return "Or";
|
|
||||||
case OrRat:
|
|
||||||
return "OrRat";
|
|
||||||
case Concat:
|
|
||||||
return "Concat";
|
|
||||||
case Fusion:
|
|
||||||
return "Fusion";
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
static void
|
|
||||||
gather_bool(multop::vec* v, multop::type op)
|
|
||||||
{
|
|
||||||
// Gather all boolean terms.
|
|
||||||
multop::vec* b = new multop::vec;
|
|
||||||
multop::vec::iterator i = v->begin();
|
|
||||||
while (i != v->end())
|
|
||||||
{
|
|
||||||
if ((*i)->is_boolean())
|
|
||||||
{
|
|
||||||
b->push_back(*i);
|
|
||||||
i = v->erase(i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// - AndNLM(Exps1...,Bool1,Exps2...,Bool2,Exps3...) =
|
|
||||||
// AndNLM(And(Bool1,Bool2),Exps1...,Exps2...,Exps3...)
|
|
||||||
// - AndRat(Exps1...,Bool1,Exps2...,Bool2,Exps3...) =
|
|
||||||
// AndRat(And(Bool1,Bool2),Exps1...,Exps2...,Exps3...)
|
|
||||||
// - OrRat(Exps1...,Bool1,Exps2...,Bool2,Exps3...) =
|
|
||||||
// AndRat(Or(Bool1,Bool2),Exps1...,Exps2...,Exps3...)
|
|
||||||
if (!b->empty())
|
|
||||||
v->insert(v->begin(), multop::instance(op, b));
|
|
||||||
else
|
|
||||||
delete b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
multop::map multop::instances;
|
|
||||||
|
|
||||||
// We match equivalent formulae modulo "ACI rules"
|
|
||||||
// (i.e. associativity, commutativity and idempotence of the
|
|
||||||
// operator). For instance if `+' designates the OR operator and
|
|
||||||
// `0' is false (the neutral element for `+') , then `f+f+0' is
|
|
||||||
// equivalent to `f'.
|
|
||||||
const formula*
|
|
||||||
multop::instance(type op, vec* v)
|
|
||||||
{
|
|
||||||
// Inline children of same kind.
|
|
||||||
//
|
|
||||||
// When we construct a formula such as Multop(Op,X,Multop(Op,Y,Z))
|
|
||||||
// we will want to inline it as Multop(Op,X,Y,Z).
|
|
||||||
{
|
|
||||||
vec inlined;
|
|
||||||
vec::iterator i = v->begin();
|
|
||||||
while (i != v->end())
|
|
||||||
{
|
|
||||||
// Some simplification routines erase terms using null
|
|
||||||
// pointers that we must ignore.
|
|
||||||
if ((*i) == 0)
|
|
||||||
{
|
|
||||||
// FIXME: For commutative operators we should replace
|
|
||||||
// the pointer by the first non-null value at the end
|
|
||||||
// of the array instead of calling erase.
|
|
||||||
i = v->erase(i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (const multop* p = is_multop(*i, op))
|
|
||||||
{
|
|
||||||
unsigned ps = p->size();
|
|
||||||
for (unsigned n = 0; n < ps; ++n)
|
|
||||||
inlined.push_back(p->nth(n)->clone());
|
|
||||||
(*i)->destroy();
|
|
||||||
// FIXME: Do not use erase. See previous FIXME.
|
|
||||||
i = v->erase(i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// All operators except "Concat" and "Fusion" are
|
|
||||||
// commutative, so we just keep a list of the inlined
|
|
||||||
// arguments that should later be added to the vector.
|
|
||||||
// For concat we have to keep track of the order of
|
|
||||||
// all the arguments.
|
|
||||||
if (op == Concat || op == Fusion)
|
|
||||||
inlined.push_back(*i);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if (op == Concat || op == Fusion)
|
|
||||||
v->swap(inlined);
|
|
||||||
else
|
|
||||||
v->insert(v->end(), inlined.begin(), inlined.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op != Concat && op != Fusion)
|
|
||||||
std::sort(v->begin(), v->end(), formula_ptr_less_than_bool_first());
|
|
||||||
|
|
||||||
unsigned orig_size = v->size();
|
|
||||||
|
|
||||||
const formula* neutral;
|
|
||||||
const formula* neutral2;
|
|
||||||
const formula* abs;
|
|
||||||
const formula* abs2;
|
|
||||||
const formula* weak_abs;
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case And:
|
|
||||||
neutral = constant::true_instance();
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = constant::false_instance();
|
|
||||||
abs2 = 0;
|
|
||||||
weak_abs = 0;
|
|
||||||
break;
|
|
||||||
case AndRat:
|
|
||||||
neutral = bunop::one_star();
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = constant::false_instance();
|
|
||||||
abs2 = 0;
|
|
||||||
weak_abs = constant::empty_word_instance();
|
|
||||||
gather_bool(v, And);
|
|
||||||
break;
|
|
||||||
case AndNLM:
|
|
||||||
neutral = constant::empty_word_instance();
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = constant::false_instance();
|
|
||||||
abs2 = 0;
|
|
||||||
weak_abs = constant::true_instance();
|
|
||||||
gather_bool(v, And);
|
|
||||||
break;
|
|
||||||
case Or:
|
|
||||||
neutral = constant::false_instance();
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = constant::true_instance();
|
|
||||||
abs2 = 0;
|
|
||||||
weak_abs = 0;
|
|
||||||
break;
|
|
||||||
case OrRat:
|
|
||||||
neutral = constant::false_instance();
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = bunop::one_star();
|
|
||||||
abs2 = 0;
|
|
||||||
weak_abs = 0;
|
|
||||||
gather_bool(v, Or);
|
|
||||||
break;
|
|
||||||
case Concat:
|
|
||||||
neutral = constant::empty_word_instance();
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = constant::false_instance();
|
|
||||||
abs2 = 0;
|
|
||||||
weak_abs = 0;
|
|
||||||
|
|
||||||
// - Concat(Exps1...,FExps2...,1[*],FExps3...,Exps4) =
|
|
||||||
// Concat(Exps1...,1[*],Exps4)
|
|
||||||
// If FExps2... and FExps3 all accept [*0].
|
|
||||||
{
|
|
||||||
vec::iterator i = v->begin();
|
|
||||||
const formula* os = bunop::one_star();
|
|
||||||
while (i != v->end())
|
|
||||||
{
|
|
||||||
while (i != v->end() && !(*i)->accepts_eword())
|
|
||||||
++i;
|
|
||||||
if (i == v->end())
|
|
||||||
break;
|
|
||||||
vec::iterator b = i;
|
|
||||||
// b is the first expressions that accepts [*0].
|
|
||||||
// let's find more, and locate the position of
|
|
||||||
// 1[*] at the same time.
|
|
||||||
bool os_seen = false;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
os_seen |= (*i == os);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
while (i != v->end() && (*i)->accepts_eword());
|
|
||||||
|
|
||||||
if (os_seen) // [b..i) is a range that contains [*].
|
|
||||||
{
|
|
||||||
// Place [*] at the start of the range, and erase
|
|
||||||
// all other formulae.
|
|
||||||
(*b)->destroy();
|
|
||||||
*b++ = os->clone();
|
|
||||||
for (vec::iterator c = b; c < i; ++c)
|
|
||||||
(*c)->destroy();
|
|
||||||
i = v->erase(b, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case Fusion:
|
|
||||||
neutral = constant::true_instance();
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = constant::false_instance();
|
|
||||||
abs2 = constant::empty_word_instance();
|
|
||||||
weak_abs = 0;
|
|
||||||
|
|
||||||
// Make a first pass to group adjacent Boolean formulae.
|
|
||||||
// - Fusion(Exps1...,BoolExp1...BoolExpN,Exps2,Exps3...) =
|
|
||||||
// Fusion(Exps1...,And(BoolExp1...BoolExpN),Exps2,Exps3...)
|
|
||||||
{
|
|
||||||
vec::iterator i = v->begin();
|
|
||||||
while (i != v->end())
|
|
||||||
{
|
|
||||||
if ((*i)->is_boolean())
|
|
||||||
{
|
|
||||||
vec::iterator first = i;
|
|
||||||
++i;
|
|
||||||
if (i == v->end())
|
|
||||||
break;
|
|
||||||
if (!(*i)->is_boolean())
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
do
|
|
||||||
++i;
|
|
||||||
while (i != v->end() && (*i)->is_boolean());
|
|
||||||
// We have at least two adjacent Boolean formulae.
|
|
||||||
// Replace the first one by the conjunction of all.
|
|
||||||
vec* b = new vec;
|
|
||||||
b->insert(b->begin(), first, i);
|
|
||||||
i = v->erase(first + 1, i);
|
|
||||||
*first = instance(And, b);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
neutral = 0;
|
|
||||||
neutral2 = 0;
|
|
||||||
abs = 0;
|
|
||||||
abs2 = 0;
|
|
||||||
weak_abs = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove duplicates (except for Concat and Fusion). We can't use
|
|
||||||
// std::unique(), because we must destroy() any formula we drop.
|
|
||||||
// Also ignore neutral elements and handle absorbent elements.
|
|
||||||
{
|
|
||||||
const formula* last = 0;
|
|
||||||
vec::iterator i = v->begin();
|
|
||||||
bool weak_abs_seen = false;
|
|
||||||
while (i != v->end())
|
|
||||||
{
|
|
||||||
if ((*i == neutral) || (*i == neutral2) || (*i == last))
|
|
||||||
{
|
|
||||||
(*i)->destroy();
|
|
||||||
i = v->erase(i);
|
|
||||||
}
|
|
||||||
else if (*i == abs || *i == abs2)
|
|
||||||
{
|
|
||||||
for (i = v->begin(); i != v->end(); ++i)
|
|
||||||
(*i)->destroy();
|
|
||||||
delete v;
|
|
||||||
return abs->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
weak_abs_seen |= (*i == weak_abs);
|
|
||||||
if (op != Concat && op != Fusion) // Don't remove duplicates
|
|
||||||
last = *i;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (weak_abs_seen)
|
|
||||||
{
|
|
||||||
if (op == AndRat)
|
|
||||||
{
|
|
||||||
// We have a* && [*0] && c = 0
|
|
||||||
// and a* && [*0] && c* = [*0]
|
|
||||||
// So if [*0] has been seen, check if alls term
|
|
||||||
// recognize the empty word.
|
|
||||||
bool acc_eword = true;
|
|
||||||
for (i = v->begin(); i != v->end(); ++i)
|
|
||||||
{
|
|
||||||
acc_eword &= (*i)->accepts_eword();
|
|
||||||
(*i)->destroy();
|
|
||||||
}
|
|
||||||
delete v;
|
|
||||||
if (acc_eword)
|
|
||||||
return weak_abs;
|
|
||||||
else
|
|
||||||
return abs;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Similarly, a* & 1 & (c;d) = c;d
|
|
||||||
// a* & 1 & c* = 1
|
|
||||||
assert(op == AndNLM);
|
|
||||||
multop::vec tmp;
|
|
||||||
for (i = v->begin(); i != v->end(); ++i)
|
|
||||||
{
|
|
||||||
if (*i == weak_abs)
|
|
||||||
continue;
|
|
||||||
if ((*i)->accepts_eword())
|
|
||||||
{
|
|
||||||
(*i)->destroy();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tmp.push_back(*i);
|
|
||||||
}
|
|
||||||
if (tmp.empty())
|
|
||||||
tmp.push_back(weak_abs);
|
|
||||||
v->swap(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (op == Concat || op == Fusion)
|
|
||||||
{
|
|
||||||
// Perform an extra loop to merge starable items.
|
|
||||||
// f;f -> f[*2]
|
|
||||||
// f;f[*i..j] -> f[*i+1..j+1]
|
|
||||||
// f[*i..j];f -> f[*i+1..j+1]
|
|
||||||
// f[*i..j];f[*k..l] -> f[*i+k..j+l]
|
|
||||||
// same for FStar:
|
|
||||||
// f:f -> f[:*2]
|
|
||||||
// f:f[*i..j] -> f[:*i+1..j+1]
|
|
||||||
// f[:*i..j];f -> f[:*i+1..j+1]
|
|
||||||
// f[:*i..j];f[:*k..l] -> f[:*i+k..j+l]
|
|
||||||
bunop::type bop = op == Concat ? bunop::Star : bunop::FStar;
|
|
||||||
i = v->begin();
|
|
||||||
while (i != v->end())
|
|
||||||
{
|
|
||||||
vec::iterator fpos = i;
|
|
||||||
const formula* f;
|
|
||||||
unsigned min;
|
|
||||||
unsigned max;
|
|
||||||
bool changed = false;
|
|
||||||
if (const bunop* is = is_bunop(*i, bop))
|
|
||||||
{
|
|
||||||
f = is->child();
|
|
||||||
min = is->min();
|
|
||||||
max = is->max();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
f = *i;
|
|
||||||
min = max = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
while (i != v->end())
|
|
||||||
{
|
|
||||||
const formula* f2;
|
|
||||||
unsigned min2;
|
|
||||||
unsigned max2;
|
|
||||||
if (const bunop* is = is_bunop(*i, bop))
|
|
||||||
{
|
|
||||||
f2 = is->child();
|
|
||||||
if (f2 != f)
|
|
||||||
break;
|
|
||||||
min2 = is->min();
|
|
||||||
max2 = is->max();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
f2 = *i;
|
|
||||||
if (f2 != f)
|
|
||||||
break;
|
|
||||||
min2 = max2 = 1;
|
|
||||||
}
|
|
||||||
if (min2 == bunop::unbounded)
|
|
||||||
min = bunop::unbounded;
|
|
||||||
else if (min != bunop::unbounded)
|
|
||||||
min += min2;
|
|
||||||
if (max2 == bunop::unbounded)
|
|
||||||
max = bunop::unbounded;
|
|
||||||
else if (max != bunop::unbounded)
|
|
||||||
max += max2;
|
|
||||||
(*i)->destroy();
|
|
||||||
i = v->erase(i);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
const formula* newfs =
|
|
||||||
bunop::instance(bop, f->clone(), min, max);
|
|
||||||
(*fpos)->destroy();
|
|
||||||
*fpos = newfs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec::size_type s = v->size();
|
|
||||||
if (s == 0)
|
|
||||||
{
|
|
||||||
delete v;
|
|
||||||
assert(neutral != 0);
|
|
||||||
return neutral->clone();
|
|
||||||
}
|
|
||||||
else if (s == 1)
|
|
||||||
{
|
|
||||||
// Simply replace Multop(Op,X) by X.
|
|
||||||
// Except we should never reduce the
|
|
||||||
// arguments of a Fusion operator to
|
|
||||||
// a list with a single formula that
|
|
||||||
// accepts [*0].
|
|
||||||
const formula* res = (*v)[0];
|
|
||||||
if (op != Fusion || orig_size == 1
|
|
||||||
|| !res->accepts_eword())
|
|
||||||
{
|
|
||||||
delete v;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
// If Fusion(f, ...) reduce to Fusion(f), emit Fusion(1,f).
|
|
||||||
// to ensure that [*0] is not accepted.
|
|
||||||
v->insert(v->begin(), constant::true_instance());
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula* res;
|
|
||||||
// Insert the key with the dummy nullptr just
|
|
||||||
// to check if p already exists.
|
|
||||||
auto ires = instances.emplace(key(op, v), nullptr);
|
|
||||||
if (!ires.second)
|
|
||||||
{
|
|
||||||
// The instance did already exists. Free v.
|
|
||||||
for (auto f: *v)
|
|
||||||
f->destroy();
|
|
||||||
delete v;
|
|
||||||
res = ires.first->second->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The instance did not already exist.
|
|
||||||
res = ires.first->second = new multop(op, v);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
multop::instance(type op, const formula* first, const formula* second)
|
|
||||||
{
|
|
||||||
vec* v = new vec;
|
|
||||||
v->push_back(first);
|
|
||||||
v->push_back(second);
|
|
||||||
return instance(op, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
multop::instance_count()
|
|
||||||
{
|
|
||||||
return instances.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
multop::dump_instances(std::ostream& os)
|
|
||||||
{
|
|
||||||
for (const auto& i: instances)
|
|
||||||
os << i.second << " = "
|
|
||||||
<< 1 + i.second->refs_ << " * "
|
|
||||||
<< i.second->dump()
|
|
||||||
<< '\n';
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire
|
|
||||||
// de Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris
|
|
||||||
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/multop.hh
|
|
||||||
/// \brief LTL multi-operand operators
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "formula.hh"
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <iosfwd>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
|
|
||||||
/// \ingroup ltl_ast
|
|
||||||
/// \brief Multi-operand operators.
|
|
||||||
class SPOT_API multop final: public formula
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum type { Or, OrRat, And, AndRat, AndNLM, Concat, Fusion };
|
|
||||||
|
|
||||||
/// List of formulae.
|
|
||||||
typedef std::vector<const formula*> vec;
|
|
||||||
|
|
||||||
/// \brief Build a spot::ltl::multop with two children.
|
|
||||||
///
|
|
||||||
/// If one of the children itself is a spot::ltl::multop
|
|
||||||
/// with the same type, it will be inlined. I.e., children
|
|
||||||
/// of that child will be added, and that child itself will
|
|
||||||
/// be destroyed. This allows incremental building of
|
|
||||||
/// n-ary ltl::multop.
|
|
||||||
///
|
|
||||||
/// This functions can perform slight optimizations and
|
|
||||||
/// may not return an ltl::multop object. See the other
|
|
||||||
/// instance function for the list of rewritings.
|
|
||||||
static const formula*
|
|
||||||
instance(type op, const formula* first, const formula* second);
|
|
||||||
|
|
||||||
/// \brief Build a spot::ltl::multop with many children.
|
|
||||||
///
|
|
||||||
/// Same as the other instance() function, but take a vector of
|
|
||||||
/// formulae as argument. This vector is acquired by the
|
|
||||||
/// spot::ltl::multop class, the caller should allocate it with
|
|
||||||
/// \c new, but not use it (especially not destroy it) after it
|
|
||||||
/// has been passed to spot::ltl::multop. Inside the vector,
|
|
||||||
/// null pointers are ignored.
|
|
||||||
///
|
|
||||||
/// Most operators (Or, OrRat, And, AndRat, Concat) are
|
|
||||||
/// associative, and are automatically inlined. Or, OrRat, And,
|
|
||||||
/// and AndRat are commutative, so their arguments are also
|
|
||||||
/// sorted, to ensure that "a & b" is equal to "b & a", also
|
|
||||||
/// duplicate arguments are removed.
|
|
||||||
///
|
|
||||||
/// Furthermore this function can perform slight optimizations
|
|
||||||
/// and may not return an ltl::multop object. For instance if
|
|
||||||
/// the vector contains only one unique element, this this
|
|
||||||
/// formula will be returned as-is. Neutral and absorbent element
|
|
||||||
/// are also taken care of. The following rewritings are performed
|
|
||||||
/// (the left patterns are rewritten as shown on the right):
|
|
||||||
///
|
|
||||||
/// - And(Exps1...,1,Exps2...) = And(Exps1...,Exps2...)
|
|
||||||
/// - And(Exps1...,0,Exps2...) = 0
|
|
||||||
/// - And(Exp) = Exp
|
|
||||||
/// - Or(Exps1...,1,Exps2...) = 1
|
|
||||||
/// - Or(Exps1...,0,Exps2...) = Or(Exps1...,Exps2...)
|
|
||||||
/// - Or(Exp) = Exp
|
|
||||||
/// - AndNLM(FExps1...,1,Exps2...) = AndNLM(Exps2...)
|
|
||||||
/// if Fexps1... accept [*0], and Exps2... don't.
|
|
||||||
/// - AndNLM(FExps1...,1,FExps2...) = 1
|
|
||||||
/// if Fexps1...,FExps2... all accept[*0].
|
|
||||||
/// - AndNLM(Exps1...,0,Exps2...) = 0
|
|
||||||
/// - AndNLM(Exps1...,[*0],Exps2...) = AndNLM(Exps1...,Exps2...)
|
|
||||||
/// - AndNLM(Exp) = Exp
|
|
||||||
/// - AndNLM(Exps1...,BoolExp1,Exps2...,BoolExp2,Exps3...) =
|
|
||||||
/// AndNLM(Exps1...,Exps2...,Exps3...,And(BoolExp1,BoolExp2))
|
|
||||||
/// - AndRat(Exps1...,0,Exps2...) = 0
|
|
||||||
/// - AndRat(Exps1...,BoolExp1,Exps2...,BoolExps2...) =
|
|
||||||
/// AndRat(Exps1...,Exps2...,And(BoolExp1,BoolExps2...))
|
|
||||||
/// - AndRat(Exps1...,[*0],Exps2...) = [*0] if all Expi accept [*0]
|
|
||||||
/// - AndRat(Exps1...,[*0],Exps2...) = 0 if some Expi reject [*0]
|
|
||||||
/// - AndRat(Exps1...,1[*],Exps2...) = AndRat(Exps1...,Exps2...)
|
|
||||||
/// - OrRat(Exps1...,0,Exps2...) = OrRat(Exps1...,Exps2...)
|
|
||||||
/// - OrRat(Exps1...,BoolExp1,Exps2...,BoolExps2...) =
|
|
||||||
/// OrRat(Exps1...,Exps2...,Or(BoolExp1,BoolExps2...))
|
|
||||||
/// - OrRat(Exps1...,1[*],Exps2...) = 1[*]
|
|
||||||
/// - Concat(Exps1...,0,Exps2...) = 0
|
|
||||||
/// - Concat(Exps1...,[*0],Exps2...) = Concat(Exps1...,Exps2...)
|
|
||||||
/// - Concat(Exps1...,FExps2...,1[*],FExps3...,Exps4) =
|
|
||||||
/// Concat(Exps1...,1[*],Exps4) if FExps2...FExps3... all accept [*0]
|
|
||||||
/// - Concat(Exp) = Exp
|
|
||||||
/// - Concat(Exps1...,E,E[*i..j],E[*k..l],Exps2...) =
|
|
||||||
/// Concat(Exps1...,E[*1+i+k..j+l],Exps2...) and similar forms
|
|
||||||
/// - Fusion(Exps1...1,Exps2...) = Fusion(Exps1...,Exps2...)
|
|
||||||
/// if at least one exp reject [*0]
|
|
||||||
/// - Fusion(Exps1...,0,Exps2...) = 0
|
|
||||||
/// - Fusion(Exps1...,[*0],Exps2...) = 0
|
|
||||||
/// - Fusion(Exp) = Exp
|
|
||||||
/// - Fusion(Exps1...,BoolExp1...BoolExpN,Exps2,Exps3...) =
|
|
||||||
/// Fusion(Exps1...,And(BoolExp1...BoolExpN),Exps2,Exps3...)
|
|
||||||
static const formula* instance(type op, vec* v);
|
|
||||||
|
|
||||||
virtual void accept(visitor& v) const;
|
|
||||||
|
|
||||||
/// Get the number of children.
|
|
||||||
unsigned size() const
|
|
||||||
{
|
|
||||||
return children_->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Get the nth child.
|
|
||||||
///
|
|
||||||
/// Starting with \a n = 0.
|
|
||||||
const formula* nth(unsigned n) const
|
|
||||||
{
|
|
||||||
return (*children_)[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief construct a formula without the nth child.
|
|
||||||
///
|
|
||||||
/// If the formula \c f is <code>a|b|c|d</code> and <code>c</code>
|
|
||||||
/// is child number 2, then calling <code>f->all_but(2)</code> will
|
|
||||||
/// return a new formula <code>a|b|d</code>.
|
|
||||||
const formula* all_but(unsigned n) const;
|
|
||||||
|
|
||||||
/// \brief return the number of Boolean operands in the binop.
|
|
||||||
///
|
|
||||||
/// For instance if \c f <code>a|b|Xc|Gd</code>, this
|
|
||||||
/// returns 2.
|
|
||||||
unsigned boolean_count() const;
|
|
||||||
|
|
||||||
/// \brief return the Boolean part of the binop.
|
|
||||||
///
|
|
||||||
/// For instance if \c f <code>a|b|Xc|Gd</code>, this
|
|
||||||
/// returns <code>a|b</code>. Return 0 if there is no
|
|
||||||
/// Boolean operand.
|
|
||||||
///
|
|
||||||
/// If \a width is not null, it is filled with the number
|
|
||||||
/// of Boolean operands extracted (i.e., the result
|
|
||||||
/// of boolean_count())
|
|
||||||
const formula* boolean_operands(unsigned* width = 0) const;
|
|
||||||
|
|
||||||
/// Get the type of this operator.
|
|
||||||
type op() const
|
|
||||||
{
|
|
||||||
return op_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of this operator, as a string.
|
|
||||||
const char* op_name() const;
|
|
||||||
|
|
||||||
/// Return a canonic representation of the atomic proposition
|
|
||||||
virtual std::string dump() const;
|
|
||||||
|
|
||||||
/// Number of instantiated multi-operand operators. For debugging.
|
|
||||||
static unsigned instance_count();
|
|
||||||
|
|
||||||
/// Dump all instances. For debugging.
|
|
||||||
static std::ostream& dump_instances(std::ostream& os);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef std::pair<type, vec*> key;
|
|
||||||
/// Comparison functor used internally by ltl::multop.
|
|
||||||
struct paircmp
|
|
||||||
{
|
|
||||||
bool
|
|
||||||
operator()(const key& p1, const key& p2) const
|
|
||||||
{
|
|
||||||
if (p1.first != p2.first)
|
|
||||||
return p1.first < p2.first;
|
|
||||||
return *p1.second < *p2.second;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
typedef std::map<key, const multop*, paircmp> map;
|
|
||||||
static map instances;
|
|
||||||
|
|
||||||
multop(type op, vec* v);
|
|
||||||
virtual ~multop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
type op_;
|
|
||||||
vec* children_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a multop iff it is a multop instance. Return 0
|
|
||||||
/// otherwise. This is faster than \c dynamic_cast.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_multop(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->kind() != formula::MultOp)
|
|
||||||
return 0;
|
|
||||||
return static_cast<const multop*>(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it has type \a op.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a multop iff it is a multop instance with operator \a op.
|
|
||||||
/// Returns 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_multop(const formula* f, multop::type op)
|
|
||||||
{
|
|
||||||
if (const multop* mo = is_multop(f))
|
|
||||||
if (mo->op() == op)
|
|
||||||
return mo;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it has type \a op1 or \a op2.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a multop iff it is a multop instance with
|
|
||||||
/// operator \a op1 or \a op2. Returns 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_multop(const formula* f, multop::type op1, multop::type op2)
|
|
||||||
{
|
|
||||||
if (const multop* mo = is_multop(f))
|
|
||||||
if (mo->op() == op1 || mo->op() == op2)
|
|
||||||
return mo;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it is an And.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_And(const formula* f)
|
|
||||||
{
|
|
||||||
return is_multop(f, multop::And);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it is an AndRat.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_AndRat(const formula* f)
|
|
||||||
{
|
|
||||||
return is_multop(f, multop::AndRat);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it is an AndNLM.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_AndNLM(const formula* f)
|
|
||||||
{
|
|
||||||
return is_multop(f, multop::AndNLM);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it is an Or.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_Or(const formula* f)
|
|
||||||
{
|
|
||||||
return is_multop(f, multop::Or);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it is an OrRat.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_OrRat(const formula* f)
|
|
||||||
{
|
|
||||||
return is_multop(f, multop::OrRat);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it is a Concat.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_Concat(const formula* f)
|
|
||||||
{
|
|
||||||
return is_multop(f, multop::Concat);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a multop if it is a Fusion.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const multop*
|
|
||||||
is_Fusion(const formula* f)
|
|
||||||
{
|
|
||||||
return is_multop(f, multop::Fusion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2012, 2014 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/predecl.hh
|
|
||||||
/// \brief Predeclare all LTL node types.
|
|
||||||
///
|
|
||||||
/// This file is usually used when \b declaring methods and functions
|
|
||||||
/// over LTL nodes.
|
|
||||||
/// Use ltlast/allnodes.hh or an individual header when the definition of
|
|
||||||
/// the node is actually needed.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
struct visitor;
|
|
||||||
|
|
||||||
class atomic_prop;
|
|
||||||
class binop;
|
|
||||||
class bunop;
|
|
||||||
class constant;
|
|
||||||
class formula;
|
|
||||||
class multop;
|
|
||||||
class unop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,314 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire
|
|
||||||
// de Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris
|
|
||||||
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "unop.hh"
|
|
||||||
#include "visitor.hh"
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <iostream>
|
|
||||||
#include "constant.hh"
|
|
||||||
#include "atomic_prop.hh"
|
|
||||||
#include "bunop.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
unop::unop(type op, const formula* child)
|
|
||||||
: formula(UnOp), op_(op), child_(child)
|
|
||||||
{
|
|
||||||
props = child->get_props();
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case Not:
|
|
||||||
is.not_marked = true;
|
|
||||||
is.eventual = child->is_universal();
|
|
||||||
is.universal = child->is_eventual();
|
|
||||||
is.in_nenoform = (child->kind() == AtomicProp);
|
|
||||||
is.sere_formula = is.boolean;
|
|
||||||
|
|
||||||
is.syntactic_safety = child->is_syntactic_guarantee();
|
|
||||||
is.syntactic_guarantee = child->is_syntactic_safety();
|
|
||||||
// is.syntactic_obligation inherited from child
|
|
||||||
is.syntactic_recurrence = child->is_syntactic_persistence();
|
|
||||||
is.syntactic_persistence = child->is_syntactic_recurrence();
|
|
||||||
|
|
||||||
is.accepting_eword = false;
|
|
||||||
break;
|
|
||||||
case X:
|
|
||||||
is.not_marked = true;
|
|
||||||
is.boolean = false;
|
|
||||||
is.syntactic_si = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
// is.syntactic_safety inherited
|
|
||||||
// is.syntactic_guarantee inherited
|
|
||||||
// is.syntactic_obligation inherited
|
|
||||||
// is.syntactic_recurrence inherited
|
|
||||||
// is.syntactic_persistence inherited
|
|
||||||
is.accepting_eword = false;
|
|
||||||
break;
|
|
||||||
case F:
|
|
||||||
is.not_marked = true;
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.finite = false;
|
|
||||||
is.sugar_free_ltl = false;
|
|
||||||
is.eventual = true;
|
|
||||||
is.syntactic_safety = false;
|
|
||||||
// is.syntactic_guarantee inherited
|
|
||||||
is.syntactic_obligation = is.syntactic_guarantee;
|
|
||||||
is.syntactic_recurrence = is.syntactic_guarantee;
|
|
||||||
// is.syntactic_persistence inherited
|
|
||||||
is.accepting_eword = false;
|
|
||||||
break;
|
|
||||||
case G:
|
|
||||||
is.not_marked = true;
|
|
||||||
is.boolean = false;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.finite = false;
|
|
||||||
is.sugar_free_ltl = false;
|
|
||||||
is.universal = true;
|
|
||||||
// is.syntactic_safety inherited
|
|
||||||
is.syntactic_guarantee = false;
|
|
||||||
is.syntactic_obligation = is.syntactic_safety;
|
|
||||||
// is.syntactic_recurrence inherited
|
|
||||||
is.syntactic_persistence = is.syntactic_safety;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
break;
|
|
||||||
case NegClosure:
|
|
||||||
case NegClosureMarked:
|
|
||||||
is.not_marked = (op == NegClosure);
|
|
||||||
is.boolean = false;
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.psl_formula = true;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.syntactic_safety = is.finite;
|
|
||||||
is.syntactic_guarantee = true;
|
|
||||||
is.syntactic_obligation = true;
|
|
||||||
is.syntactic_recurrence = true;
|
|
||||||
is.syntactic_persistence = true;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
assert(child->is_sere_formula());
|
|
||||||
assert(!child->is_boolean());
|
|
||||||
break;
|
|
||||||
case Closure:
|
|
||||||
is.not_marked = true;
|
|
||||||
is.boolean = false;
|
|
||||||
is.ltl_formula = false;
|
|
||||||
is.psl_formula = true;
|
|
||||||
is.sere_formula = false;
|
|
||||||
is.syntactic_safety = true;
|
|
||||||
is.syntactic_guarantee = is.finite;
|
|
||||||
is.syntactic_obligation = true;
|
|
||||||
is.syntactic_recurrence = true;
|
|
||||||
is.syntactic_persistence = true;
|
|
||||||
is.accepting_eword = false;
|
|
||||||
assert(child->is_sere_formula());
|
|
||||||
assert(!child->is_boolean());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unop::~unop()
|
|
||||||
{
|
|
||||||
// Get this instance out of the instance map.
|
|
||||||
size_t c = instances.erase(key(op(), child()));
|
|
||||||
assert(c == 1);
|
|
||||||
(void) c; // For the NDEBUG case.
|
|
||||||
|
|
||||||
// Dereference child.
|
|
||||||
child()->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
unop::dump() const
|
|
||||||
{
|
|
||||||
return std::string("unop(") + op_name() + ", " + child()->dump() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
unop::accept(visitor& v) const
|
|
||||||
{
|
|
||||||
v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
unop::op_name() const
|
|
||||||
{
|
|
||||||
switch (op_)
|
|
||||||
{
|
|
||||||
case Not:
|
|
||||||
return "Not";
|
|
||||||
case X:
|
|
||||||
return "X";
|
|
||||||
case F:
|
|
||||||
return "F";
|
|
||||||
case G:
|
|
||||||
return "G";
|
|
||||||
case Closure:
|
|
||||||
return "Closure";
|
|
||||||
case NegClosure:
|
|
||||||
return "NegClosure";
|
|
||||||
case NegClosureMarked:
|
|
||||||
return "NegClosureMarked";
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
unop::map unop::instances;
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
unop::instance(type op, const formula* child)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Some trivial simplifications.
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case F:
|
|
||||||
case G:
|
|
||||||
{
|
|
||||||
if (const unop* u = is_unop(child))
|
|
||||||
{
|
|
||||||
// F and G are idempotent.
|
|
||||||
if (u->op() == op)
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
|
|
||||||
// F(0) = G(0) = 0
|
|
||||||
// F(1) = G(1) = 1
|
|
||||||
if (child == constant::false_instance()
|
|
||||||
|| child == constant::true_instance())
|
|
||||||
return child;
|
|
||||||
|
|
||||||
assert(child != constant::empty_word_instance());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Not:
|
|
||||||
{
|
|
||||||
// !1 = 0
|
|
||||||
if (child == constant::true_instance())
|
|
||||||
return constant::false_instance();
|
|
||||||
// !0 = 1
|
|
||||||
if (child == constant::false_instance())
|
|
||||||
return constant::true_instance();
|
|
||||||
// ![*0] = 1[+]
|
|
||||||
if (child == constant::empty_word_instance())
|
|
||||||
return bunop::instance(bunop::Star,
|
|
||||||
constant::true_instance(), 1);
|
|
||||||
|
|
||||||
if (const unop* u = is_unop(child))
|
|
||||||
{
|
|
||||||
// "Not" is an involution.
|
|
||||||
if (u->op() == op)
|
|
||||||
{
|
|
||||||
const formula* c = u->child()->clone();
|
|
||||||
u->destroy();
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
// !Closure(Exp) = NegClosure(Exp)
|
|
||||||
if (u->op() == Closure)
|
|
||||||
{
|
|
||||||
const formula* c = unop::instance(NegClosure,
|
|
||||||
u->child()->clone());
|
|
||||||
u->destroy();
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
// !NegClosure(Exp) = Closure(Exp)
|
|
||||||
if (u->op() == NegClosure)
|
|
||||||
{
|
|
||||||
const formula* c = unop::instance(Closure,
|
|
||||||
u->child()->clone());
|
|
||||||
u->destroy();
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case X:
|
|
||||||
// X(1) = 1, X(0) = 0
|
|
||||||
if (child == constant::true_instance()
|
|
||||||
|| child == constant::false_instance())
|
|
||||||
return child;
|
|
||||||
assert(child != constant::empty_word_instance());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Closure:
|
|
||||||
// {0} = 0, {1} = 1, {b} = b
|
|
||||||
if (child->is_boolean())
|
|
||||||
return child;
|
|
||||||
// {[*0]} = 0
|
|
||||||
if (child == constant::empty_word_instance())
|
|
||||||
return constant::false_instance();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NegClosure:
|
|
||||||
case NegClosureMarked:
|
|
||||||
// {1} = 0
|
|
||||||
if (child == constant::true_instance())
|
|
||||||
return constant::false_instance();
|
|
||||||
// {0} = 1, {[*0]} = 1
|
|
||||||
if (child == constant::false_instance()
|
|
||||||
|| child == constant::empty_word_instance())
|
|
||||||
return constant::true_instance();
|
|
||||||
// {b} = !b
|
|
||||||
if (child->is_boolean())
|
|
||||||
return unop::instance(Not, child);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula* res;
|
|
||||||
auto ires = instances.emplace(key(op, child), nullptr);
|
|
||||||
if (!ires.second)
|
|
||||||
{
|
|
||||||
// This instance already exists.
|
|
||||||
child->destroy();
|
|
||||||
res = ires.first->second->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = ires.first->second = new unop(op, child);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
unop::instance_count()
|
|
||||||
{
|
|
||||||
return instances.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
unop::dump_instances(std::ostream& os)
|
|
||||||
{
|
|
||||||
for (const auto& i: instances)
|
|
||||||
os << i.second << " = "
|
|
||||||
<< 1 + i.second->refs_ << " * "
|
|
||||||
<< i.second->dump()
|
|
||||||
<< '\n';
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,218 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Laboratoire de
|
|
||||||
// Recherche et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris
|
|
||||||
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
|
||||||
// Université Pierre et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/unop.hh
|
|
||||||
/// \brief LTL unary operators
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <iosfwd>
|
|
||||||
#include "formula.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
|
|
||||||
/// \ingroup ltl_ast
|
|
||||||
/// \brief Unary operators.
|
|
||||||
class SPOT_API unop final : public formula
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum type {
|
|
||||||
// LTL
|
|
||||||
Not, X, F, G,
|
|
||||||
// Closure
|
|
||||||
Closure, NegClosure, NegClosureMarked
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Build an unary operator with operation \a op and
|
|
||||||
/// child \a child.
|
|
||||||
///
|
|
||||||
/// The following trivial simplifications are performed
|
|
||||||
/// automatically (the left expression is rewritten as the right
|
|
||||||
/// expression):
|
|
||||||
/// - FF(Exp) = F(Exp)
|
|
||||||
/// - GG(Exp) = G(Exp)
|
|
||||||
/// - F(0) = 0
|
|
||||||
/// - G(0) = 0
|
|
||||||
/// - X(0) = 0
|
|
||||||
/// - F(1) = 1
|
|
||||||
/// - G(1) = 1
|
|
||||||
/// - X(1) = 1
|
|
||||||
/// - !1 = 0
|
|
||||||
/// - !0 = 1
|
|
||||||
/// - ![*0] = 1[+] (read below)
|
|
||||||
/// - !!Exp = Exp
|
|
||||||
/// - !Closure(Exp) = NegClosure(Exp)
|
|
||||||
/// - !NegClosure(Exp) = Closure(Exp)
|
|
||||||
/// - Closure([*0]) = 1
|
|
||||||
/// - Closure(1) = 1
|
|
||||||
/// - Closure(0) = 0
|
|
||||||
/// - Closure(b) = b
|
|
||||||
/// - NegClosure([*0]) = 0
|
|
||||||
/// - NegClosure(1) = 0
|
|
||||||
/// - NegClosure(0) = 1
|
|
||||||
/// - NegClosure(b) = !b
|
|
||||||
///
|
|
||||||
/// This rewriting implies that it is not possible to build an
|
|
||||||
/// LTL formula object that is SYNTACTICALLY equal to one of
|
|
||||||
/// these left expressions.
|
|
||||||
///
|
|
||||||
/// Note that the "![*0]" form cannot be read using the PSL
|
|
||||||
/// grammar. Spot cannot read it either. However some
|
|
||||||
/// BDD-based algorithm may need to negate any constant, so we
|
|
||||||
/// handle this one as well.
|
|
||||||
static const formula* instance(type op, const formula* child);
|
|
||||||
|
|
||||||
virtual void accept(visitor& v) const override;
|
|
||||||
|
|
||||||
/// Get the sole operand of this operator.
|
|
||||||
const formula* child() const
|
|
||||||
{
|
|
||||||
return child_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of this operator.
|
|
||||||
type op() const
|
|
||||||
{
|
|
||||||
return op_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of this operator, as a string.
|
|
||||||
const char* op_name() const;
|
|
||||||
|
|
||||||
/// Return a canonic representation of the atomic proposition
|
|
||||||
virtual std::string dump() const override;
|
|
||||||
|
|
||||||
/// Number of instantiated unary operators. For debugging.
|
|
||||||
static unsigned instance_count();
|
|
||||||
|
|
||||||
/// Dump all instances. For debugging.
|
|
||||||
static std::ostream& dump_instances(std::ostream& os);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef std::pair<type, const formula*> key;
|
|
||||||
typedef std::map<key, const unop*> map;
|
|
||||||
static map instances;
|
|
||||||
|
|
||||||
unop(type op, const formula* child);
|
|
||||||
virtual ~unop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
type op_;
|
|
||||||
const formula* child_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop
|
|
||||||
///
|
|
||||||
/// Cast \a f into a unop iff it is a unop instance. Return 0
|
|
||||||
/// otherwise. This is faster than \c dynamic_cast.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_unop(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->kind() != formula::UnOp)
|
|
||||||
return 0;
|
|
||||||
return static_cast<const unop*>(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop if it has type \a op.
|
|
||||||
///
|
|
||||||
/// Cast \a f into a unop iff it is a unop instance with operator \a op.
|
|
||||||
/// Returns 0 otherwise.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_unop(const formula* f, unop::type op)
|
|
||||||
{
|
|
||||||
if (const unop* uo = is_unop(f))
|
|
||||||
if (uo->op() == op)
|
|
||||||
return uo;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop if it is a Not.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_Not(const formula* f)
|
|
||||||
{
|
|
||||||
return is_unop(f, unop::Not);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop if it is a X.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_X(const formula* f)
|
|
||||||
{
|
|
||||||
return is_unop(f, unop::X);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop if it is a F.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_F(const formula* f)
|
|
||||||
{
|
|
||||||
return is_unop(f, unop::F);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop if it is a G.
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_G(const formula* f)
|
|
||||||
{
|
|
||||||
return is_unop(f, unop::G);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop if has the form GF(...).
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_GF(const formula* f)
|
|
||||||
{
|
|
||||||
if (const unop* op = is_G(f))
|
|
||||||
return is_F(op->child());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Cast \a f into a unop if has the form FG(...).
|
|
||||||
///
|
|
||||||
/// Return 0 otherwise.
|
|
||||||
inline
|
|
||||||
const unop*
|
|
||||||
is_FG(const formula* f)
|
|
||||||
{
|
|
||||||
if (const unop* op = is_F(f))
|
|
||||||
return is_G(op->child());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche
|
|
||||||
// et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// \file ltlast/visitor.hh
|
|
||||||
/// \brief LTL visitor interface
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "misc/common.hh"
|
|
||||||
#include "predecl.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
/// \ingroup ltl_essential
|
|
||||||
/// \brief Formula visitor
|
|
||||||
///
|
|
||||||
/// Implementing visitors is the prefered way
|
|
||||||
/// to traverse a formula, since it does not
|
|
||||||
/// involve any cast.
|
|
||||||
struct SPOT_API visitor
|
|
||||||
{
|
|
||||||
virtual ~visitor() {}
|
|
||||||
virtual void visit(const atomic_prop* node) = 0;
|
|
||||||
virtual void visit(const constant* node) = 0;
|
|
||||||
virtual void visit(const binop* node) = 0;
|
|
||||||
virtual void visit(const unop* node) = 0;
|
|
||||||
virtual void visit(const multop* node) = 0;
|
|
||||||
virtual void visit(const bunop* node) = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2009, 2012, 2014 Laboratoire de Recherche et Développement
|
// Copyright (C) 2009, 2012, 2014, 2015 Laboratoire de Recherche et
|
||||||
// de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
// et Marie Curie.
|
// et Marie Curie.
|
||||||
|
|
@ -31,28 +31,22 @@ namespace spot
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
declarative_environment::~declarative_environment()
|
|
||||||
{
|
|
||||||
for (prop_map::iterator i = props_.begin(); i != props_.end(); ++i)
|
|
||||||
i->second->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
declarative_environment::declare(const std::string& prop_str)
|
declarative_environment::declare(const std::string& prop_str)
|
||||||
{
|
{
|
||||||
if (props_.find(prop_str) != props_.end())
|
if (props_.find(prop_str) != props_.end())
|
||||||
return false;
|
return false;
|
||||||
props_[prop_str] = ltl::atomic_prop::instance(prop_str, *this);
|
props_[prop_str] = formula::ap(prop_str);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
declarative_environment::require(const std::string& prop_str)
|
declarative_environment::require(const std::string& prop_str)
|
||||||
{
|
{
|
||||||
prop_map::iterator i = props_.find(prop_str);
|
prop_map::iterator i = props_.find(prop_str);
|
||||||
if (i == props_.end())
|
if (i == props_.end())
|
||||||
return 0;
|
return nullptr;
|
||||||
return i->second->clone();
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string&
|
const std::string&
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2009, 2012, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2009, 2012, 2013, 2014, 2015 Laboratoire de Recherche
|
||||||
// Développement de l'Epita (LRDE).
|
// et Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
// et Marie Curie.
|
// et Marie Curie.
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
#include "environment.hh"
|
#include "environment.hh"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "ltlast/atomic_prop.hh"
|
#include "ltlast/formula.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -41,18 +41,18 @@ namespace spot
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
declarative_environment();
|
declarative_environment();
|
||||||
~declarative_environment();
|
~declarative_environment() = default;
|
||||||
|
|
||||||
/// Declare an atomic proposition. Return false iff the
|
/// Declare an atomic proposition. Return false iff the
|
||||||
/// proposition was already declared.
|
/// proposition was already declared.
|
||||||
bool declare(const std::string& prop_str);
|
bool declare(const std::string& prop_str);
|
||||||
|
|
||||||
virtual const formula* require(const std::string& prop_str);
|
virtual formula require(const std::string& prop_str);
|
||||||
|
|
||||||
/// Get the name of the environment.
|
/// Get the name of the environment.
|
||||||
virtual const std::string& name() const;
|
virtual const std::string& name() const;
|
||||||
|
|
||||||
typedef std::map<const std::string, const atomic_prop*> prop_map;
|
typedef std::map<const std::string, formula> prop_map;
|
||||||
|
|
||||||
/// Get the map of atomic proposition known to this environment.
|
/// Get the map of atomic proposition known to this environment.
|
||||||
const prop_map& get_prop_map() const;
|
const prop_map& get_prop_map() const;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2014 Laboratoire de Recherche et Développement
|
// Copyright (C) 2012, 2014, 2015 Laboratoire de Recherche et
|
||||||
// de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
// et Marie Curie.
|
// et Marie Curie.
|
||||||
|
|
@ -31,10 +31,10 @@ namespace spot
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const atomic_prop*
|
formula
|
||||||
default_environment::require(const std::string& s)
|
default_environment::require(const std::string& s)
|
||||||
{
|
{
|
||||||
return atomic_prop::instance(s, *this);
|
return formula::ap(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string&
|
const std::string&
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2013, 2014, 2015 Laboratoire de Recherche et
|
// Copyright (C) 2012, 2013, 2014, 2015 Laboratoire de Recherche et
|
||||||
// Développement
|
// Développement de l'Epita (LRDE).
|
||||||
// de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
// et Marie Curie.
|
// et Marie Curie.
|
||||||
|
|
@ -24,7 +23,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "environment.hh"
|
#include "environment.hh"
|
||||||
#include "ltlast/atomic_prop.hh"
|
#include "ltlast/formula.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -42,7 +41,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~default_environment();
|
virtual ~default_environment();
|
||||||
virtual const atomic_prop* require(const std::string& prop_str);
|
virtual formula require(const std::string& prop_str);
|
||||||
virtual const std::string& name() const;
|
virtual const std::string& name() const;
|
||||||
|
|
||||||
/// Get the sole instance of spot::ltl::default_environment.
|
/// Get the sole instance of spot::ltl::default_environment.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2008, 2012, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2008, 2012, 2014, 2015 Laboratoire de Recherche et
|
||||||
// Développement de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris
|
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris
|
||||||
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
|
||||||
|
|
@ -38,20 +38,14 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// Usually \a prop_str, is the name of an atomic proposition,
|
/// Usually \a prop_str, is the name of an atomic proposition,
|
||||||
/// and spot::ltl::require simply returns the associated
|
/// and spot::ltl::require simply returns the associated
|
||||||
/// spot::ltl::atomic_prop.
|
/// spot::ltl::formula.
|
||||||
///
|
///
|
||||||
/// Note this is not a \c const method. Some environments will
|
/// Note this is not a \c const method. Some environments will
|
||||||
/// "create" the atomic proposition when requested.
|
/// "create" the atomic proposition when requested.
|
||||||
///
|
///
|
||||||
/// We return a spot::ltl::formula instead of an
|
|
||||||
/// spot::ltl::atomic_prop, because this
|
|
||||||
/// will allow nifty tricks (e.g., we could name formulae in an
|
|
||||||
/// environment, and let the parser build a larger tree from
|
|
||||||
/// these).
|
|
||||||
///
|
|
||||||
/// \return 0 iff \a prop_str is not part of the environment,
|
/// \return 0 iff \a prop_str is not part of the environment,
|
||||||
/// or the associated spot::ltl::formula otherwise.
|
/// or the associated spot::ltl::formula otherwise.
|
||||||
virtual const formula* require(const std::string& prop_str) = 0;
|
virtual formula require(const std::string& prop_str) = 0;
|
||||||
|
|
||||||
/// Get the name of the environment.
|
/// Get the name of the environment.
|
||||||
virtual const std::string& name() const = 0;
|
virtual const std::string& name() const = 0;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "public.hh"
|
#include "public.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "ltlvisit/print.hh"
|
#include "ltlvisit/print.hh"
|
||||||
|
|
||||||
struct minmax_t { unsigned min, max; };
|
struct minmax_t { unsigned min, max; };
|
||||||
|
|
@ -43,11 +43,11 @@
|
||||||
|
|
||||||
%parse-param {spot::ltl::parse_error_list &error_list}
|
%parse-param {spot::ltl::parse_error_list &error_list}
|
||||||
%parse-param {spot::ltl::environment &parse_environment}
|
%parse-param {spot::ltl::environment &parse_environment}
|
||||||
%parse-param {const spot::ltl::formula* &result}
|
%parse-param {spot::ltl::formula &result}
|
||||||
%union
|
%union
|
||||||
{
|
{
|
||||||
std::string* str;
|
std::string* str;
|
||||||
const spot::ltl::formula* ltl;
|
const spot::ltl::fnode* ltl;
|
||||||
unsigned num;
|
unsigned num;
|
||||||
minmax_t minmax;
|
minmax_t minmax;
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ using namespace spot::ltl;
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
missing_right_op_msg(op, str); \
|
missing_right_op_msg(op, str); \
|
||||||
res = constant::false_instance(); \
|
res = fnode::ff(); \
|
||||||
} \
|
} \
|
||||||
while (0);
|
while (0);
|
||||||
|
|
||||||
|
|
@ -91,7 +91,7 @@ using namespace spot::ltl;
|
||||||
|
|
||||||
enum parser_type { parser_ltl, parser_bool, parser_sere };
|
enum parser_type { parser_ltl, parser_bool, parser_sere };
|
||||||
|
|
||||||
static const 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::ltl::environment& env,
|
||||||
|
|
@ -117,11 +117,11 @@ using namespace spot::ltl;
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
{
|
{
|
||||||
error_list.emplace_back(location, "unexpected empty block");
|
error_list.emplace_back(location, "unexpected empty block");
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
spot::ltl::parse_error_list suberror;
|
spot::ltl::parse_error_list suberror;
|
||||||
const spot::ltl::formula* f = 0;
|
formula f;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case parser_sere:
|
case parser_sere:
|
||||||
|
|
@ -138,9 +138,6 @@ using namespace spot::ltl;
|
||||||
if (suberror.empty())
|
if (suberror.empty())
|
||||||
return f;
|
return f;
|
||||||
|
|
||||||
if (f)
|
|
||||||
f->destroy();
|
|
||||||
|
|
||||||
f = env.require(str);
|
f = env.require(str);
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
|
|
@ -240,72 +237,76 @@ 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(), $$); } <ltl>
|
%printer { spot::ltl::print_psl(debug_stream(), formula($$)); } <ltl>
|
||||||
%printer { spot::ltl::print_sere(debug_stream(), $$); } sere bracedsere
|
%printer { spot::ltl::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>
|
||||||
|
|
||||||
%%
|
%%
|
||||||
result: START_LTL subformula END_OF_INPUT
|
result: START_LTL subformula END_OF_INPUT
|
||||||
{ result = $2;
|
{
|
||||||
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_LTL enderror
|
| START_LTL enderror
|
||||||
{
|
{
|
||||||
result = 0;
|
result = nullptr;
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
| START_LTL subformula enderror
|
| START_LTL subformula enderror
|
||||||
{
|
{
|
||||||
result = $2;
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_LTL emptyinput
|
| START_LTL emptyinput
|
||||||
{ YYABORT; }
|
{ YYABORT; }
|
||||||
| START_BOOL boolformula END_OF_INPUT
|
| START_BOOL boolformula END_OF_INPUT
|
||||||
{ result = $2;
|
{
|
||||||
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_BOOL enderror
|
| START_BOOL enderror
|
||||||
{
|
{
|
||||||
result = 0;
|
result = nullptr;
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
| START_BOOL boolformula enderror
|
| START_BOOL boolformula enderror
|
||||||
{
|
{
|
||||||
result = $2;
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_BOOL emptyinput
|
| START_BOOL emptyinput
|
||||||
{ YYABORT; }
|
{ YYABORT; }
|
||||||
| START_SERE sere END_OF_INPUT
|
| START_SERE sere END_OF_INPUT
|
||||||
{ result = $2;
|
{
|
||||||
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_SERE enderror
|
| START_SERE enderror
|
||||||
{
|
{
|
||||||
result = 0;
|
result = nullptr;
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
| START_SERE sere enderror
|
| START_SERE sere enderror
|
||||||
{
|
{
|
||||||
result = $2;
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_SERE emptyinput
|
| START_SERE emptyinput
|
||||||
{ YYABORT; }
|
{ YYABORT; }
|
||||||
| START_LBT lbtformula END_OF_INPUT
|
| START_LBT lbtformula END_OF_INPUT
|
||||||
{ result = $2;
|
{
|
||||||
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_LBT enderror
|
| START_LBT enderror
|
||||||
{
|
{
|
||||||
result = 0;
|
result = nullptr;
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
| START_LBT lbtformula enderror
|
| START_LBT lbtformula enderror
|
||||||
{
|
{
|
||||||
result = $2;
|
result = formula($2);
|
||||||
YYACCEPT;
|
YYACCEPT;
|
||||||
}
|
}
|
||||||
| START_LBT emptyinput
|
| START_LBT emptyinput
|
||||||
|
|
@ -314,7 +315,7 @@ result: START_LTL subformula END_OF_INPUT
|
||||||
emptyinput: END_OF_INPUT
|
emptyinput: END_OF_INPUT
|
||||||
{
|
{
|
||||||
error_list.emplace_back(@$, "empty input");
|
error_list.emplace_back(@$, "empty input");
|
||||||
result = 0;
|
result = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
enderror: error END_OF_INPUT
|
enderror: error END_OF_INPUT
|
||||||
|
|
@ -331,11 +332,11 @@ error_opt: | error
|
||||||
sqbracketargs: OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
sqbracketargs: OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
{ $$.min = $1; $$.max = $3; }
|
{ $$.min = $1; $$.max = $3; }
|
||||||
| OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
|
| OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
|
||||||
{ $$.min = $1; $$.max = bunop::unbounded; }
|
{ $$.min = $1; $$.max = fnode::unbounded(); }
|
||||||
| OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
| OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
{ $$.min = 0U; $$.max = $2; }
|
{ $$.min = 0U; $$.max = $2; }
|
||||||
| OP_SQBKT_SEP_opt OP_SQBKT_CLOSE
|
| OP_SQBKT_SEP_opt OP_SQBKT_CLOSE
|
||||||
{ $$.min = 0U; $$.max = bunop::unbounded; }
|
{ $$.min = 0U; $$.max = fnode::unbounded(); }
|
||||||
| OP_SQBKT_NUM OP_SQBKT_CLOSE
|
| OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
{ $$.min = $$.max = $1; }
|
{ $$.min = $$.max = $1; }
|
||||||
|
|
||||||
|
|
@ -343,11 +344,11 @@ sqbracketargs: OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
gotoargs: OP_GOTO_OPEN OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
gotoargs: OP_GOTO_OPEN OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
{ $$.min = $2; $$.max = $4; }
|
{ $$.min = $2; $$.max = $4; }
|
||||||
| OP_GOTO_OPEN OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
|
| OP_GOTO_OPEN OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
|
||||||
{ $$.min = $2; $$.max = bunop::unbounded; }
|
{ $$.min = $2; $$.max = fnode::unbounded(); }
|
||||||
| OP_GOTO_OPEN OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
| OP_GOTO_OPEN OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
{ $$.min = 1U; $$.max = $3; }
|
{ $$.min = 1U; $$.max = $3; }
|
||||||
| OP_GOTO_OPEN OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
|
| OP_GOTO_OPEN OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
|
||||||
{ $$.min = 1U; $$.max = bunop::unbounded; }
|
{ $$.min = 1U; $$.max = fnode::unbounded(); }
|
||||||
| OP_GOTO_OPEN OP_SQBKT_CLOSE
|
| OP_GOTO_OPEN OP_SQBKT_CLOSE
|
||||||
{ $$.min = $$.max = 1U; }
|
{ $$.min = $$.max = 1U; }
|
||||||
| OP_GOTO_OPEN OP_SQBKT_NUM OP_SQBKT_CLOSE
|
| OP_GOTO_OPEN OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
|
|
@ -363,28 +364,28 @@ gotoargs: OP_GOTO_OPEN OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||||
kleen_star: OP_STAR | OP_BSTAR
|
kleen_star: OP_STAR | OP_BSTAR
|
||||||
|
|
||||||
starargs: kleen_star
|
starargs: kleen_star
|
||||||
{ $$.min = 0U; $$.max = bunop::unbounded; }
|
{ $$.min = 0U; $$.max = fnode::unbounded(); }
|
||||||
| OP_PLUS
|
| OP_PLUS
|
||||||
{ $$.min = 1U; $$.max = bunop::unbounded; }
|
{ $$.min = 1U; $$.max = fnode::unbounded(); }
|
||||||
| OP_STAR_OPEN sqbracketargs
|
| OP_STAR_OPEN sqbracketargs
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| OP_STAR_OPEN error OP_SQBKT_CLOSE
|
| OP_STAR_OPEN error OP_SQBKT_CLOSE
|
||||||
{ error_list.emplace_back(@$, "treating this star block as [*]");
|
{ error_list.emplace_back(@$, "treating this star block as [*]");
|
||||||
$$.min = 0U; $$.max = bunop::unbounded; }
|
$$.min = 0U; $$.max = fnode::unbounded(); }
|
||||||
| OP_STAR_OPEN error_opt END_OF_INPUT
|
| OP_STAR_OPEN error_opt END_OF_INPUT
|
||||||
{ error_list.emplace_back(@$, "missing closing bracket for star");
|
{ error_list.emplace_back(@$, "missing closing bracket for star");
|
||||||
$$.min = $$.max = 0U; }
|
$$.min = $$.max = 0U; }
|
||||||
|
|
||||||
fstarargs: OP_BFSTAR
|
fstarargs: OP_BFSTAR
|
||||||
{ $$.min = 0U; $$.max = bunop::unbounded; }
|
{ $$.min = 0U; $$.max = fnode::unbounded(); }
|
||||||
| OP_FPLUS
|
| OP_FPLUS
|
||||||
{ $$.min = 1U; $$.max = bunop::unbounded; }
|
{ $$.min = 1U; $$.max = fnode::unbounded(); }
|
||||||
| OP_FSTAR_OPEN sqbracketargs
|
| OP_FSTAR_OPEN sqbracketargs
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| OP_FSTAR_OPEN error OP_SQBKT_CLOSE
|
| OP_FSTAR_OPEN error OP_SQBKT_CLOSE
|
||||||
{ error_list.emplace_back
|
{ error_list.emplace_back
|
||||||
(@$, "treating this fusion-star block as [:*]");
|
(@$, "treating this fusion-star block as [:*]");
|
||||||
$$.min = 0U; $$.max = bunop::unbounded; }
|
$$.min = 0U; $$.max = fnode::unbounded(); }
|
||||||
| OP_FSTAR_OPEN error_opt END_OF_INPUT
|
| OP_FSTAR_OPEN error_opt END_OF_INPUT
|
||||||
{ error_list.emplace_back
|
{ error_list.emplace_back
|
||||||
(@$, "missing closing bracket for fusion-star");
|
(@$, "missing closing bracket for fusion-star");
|
||||||
|
|
@ -394,19 +395,16 @@ equalargs: OP_EQUAL_OPEN sqbracketargs
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| OP_EQUAL_OPEN error OP_SQBKT_CLOSE
|
| OP_EQUAL_OPEN error OP_SQBKT_CLOSE
|
||||||
{ error_list.emplace_back(@$, "treating this equal block as [*]");
|
{ error_list.emplace_back(@$, "treating this equal block as [*]");
|
||||||
$$.min = 0U; $$.max = bunop::unbounded; }
|
$$.min = 0U; $$.max = fnode::unbounded(); }
|
||||||
| OP_EQUAL_OPEN error_opt END_OF_INPUT
|
| OP_EQUAL_OPEN error_opt END_OF_INPUT
|
||||||
{ error_list.
|
{ error_list.
|
||||||
emplace_back(@$, "missing closing bracket for equal operator");
|
emplace_back(@$, "missing closing bracket for equal operator");
|
||||||
$$.min = $$.max = 0U; }
|
$$.min = $$.max = 0U; }
|
||||||
|
|
||||||
|
|
||||||
/* The reason we use `constant::false_instance()' for error recovery
|
|
||||||
is that it isn't reference counted. (Hence it can't leak references.) */
|
|
||||||
|
|
||||||
booleanatom: ATOMIC_PROP
|
booleanatom: ATOMIC_PROP
|
||||||
{
|
{
|
||||||
$$ = parse_environment.require(*$1);
|
$$ = parse_environment.require(*$1).to_node_();
|
||||||
if (! $$)
|
if (! $$)
|
||||||
{
|
{
|
||||||
std::string s = "unknown atomic proposition `";
|
std::string s = "unknown atomic proposition `";
|
||||||
|
|
@ -423,7 +421,7 @@ booleanatom: ATOMIC_PROP
|
||||||
}
|
}
|
||||||
| ATOMIC_PROP OP_POST_POS
|
| ATOMIC_PROP OP_POST_POS
|
||||||
{
|
{
|
||||||
$$ = parse_environment.require(*$1);
|
$$ = parse_environment.require(*$1).to_node_();
|
||||||
if (! $$)
|
if (! $$)
|
||||||
{
|
{
|
||||||
std::string s = "unknown atomic proposition `";
|
std::string s = "unknown atomic proposition `";
|
||||||
|
|
@ -440,7 +438,7 @@ booleanatom: ATOMIC_PROP
|
||||||
}
|
}
|
||||||
| ATOMIC_PROP OP_POST_NEG
|
| ATOMIC_PROP OP_POST_NEG
|
||||||
{
|
{
|
||||||
$$ = parse_environment.require(*$1);
|
$$ = parse_environment.require(*$1).to_node_();
|
||||||
if (! $$)
|
if (! $$)
|
||||||
{
|
{
|
||||||
std::string s = "unknown atomic proposition `";
|
std::string s = "unknown atomic proposition `";
|
||||||
|
|
@ -454,19 +452,19 @@ booleanatom: ATOMIC_PROP
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
delete $1;
|
delete $1;
|
||||||
$$ = unop::instance(unop::Not, $$);
|
$$ = fnode::unop(op::Not, $$);
|
||||||
}
|
}
|
||||||
| CONST_TRUE
|
| CONST_TRUE
|
||||||
{ $$ = constant::true_instance(); }
|
{ $$ = fnode::tt(); }
|
||||||
| CONST_FALSE
|
| CONST_FALSE
|
||||||
{ $$ = constant::false_instance(); }
|
{ $$ = fnode::ff(); }
|
||||||
|
|
||||||
sere: booleanatom
|
sere: booleanatom
|
||||||
| OP_NOT sere
|
| OP_NOT sere
|
||||||
{
|
{
|
||||||
if ($2->is_boolean())
|
if ($2->is_boolean())
|
||||||
{
|
{
|
||||||
$$ = unop::instance(unop::Not, $2);
|
$$ = fnode::unop(op::Not, $2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -475,14 +473,16 @@ sere: booleanatom
|
||||||
"be applied to a Boolean expression");
|
"be applied to a Boolean expression");
|
||||||
error_list.emplace_back(@$, "treating this block as false");
|
error_list.emplace_back(@$, "treating this block as false");
|
||||||
$2->destroy();
|
$2->destroy();
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| bracedsere
|
| bracedsere
|
||||||
| PAR_BLOCK
|
| PAR_BLOCK
|
||||||
{
|
{
|
||||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
$$ =
|
||||||
debug_level(), parser_sere, error_list);
|
try_recursive_parse(*$1, @1, parse_environment,
|
||||||
|
debug_level(), parser_sere, error_list)
|
||||||
|
.to_node_();
|
||||||
delete $1;
|
delete $1;
|
||||||
if (!$$)
|
if (!$$)
|
||||||
YYERROR;
|
YYERROR;
|
||||||
|
|
@ -493,7 +493,7 @@ sere: booleanatom
|
||||||
{ error_list.
|
{ error_list.
|
||||||
emplace_back(@$,
|
emplace_back(@$,
|
||||||
"treating this parenthetical block as false");
|
"treating this parenthetical block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
| PAR_OPEN sere END_OF_INPUT
|
| PAR_OPEN sere END_OF_INPUT
|
||||||
{ error_list.emplace_back(@1 + @2, "missing closing parenthesis");
|
{ error_list.emplace_back(@1 + @2, "missing closing parenthesis");
|
||||||
|
|
@ -503,28 +503,28 @@ sere: booleanatom
|
||||||
{ error_list.emplace_back(@$,
|
{ error_list.emplace_back(@$,
|
||||||
"missing closing parenthesis, "
|
"missing closing parenthesis, "
|
||||||
"treating this parenthetical block as false");
|
"treating this parenthetical block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
| sere OP_AND sere
|
| sere OP_AND sere
|
||||||
{ $$ = multop::instance(multop::AndRat, $1, $3); }
|
{ $$ = fnode::multop(op::AndRat, {$1, $3}); }
|
||||||
| sere OP_AND error
|
| sere OP_AND error
|
||||||
{ missing_right_binop($$, $1, @2,
|
{ missing_right_binop($$, $1, @2,
|
||||||
"length-matching and operator"); }
|
"length-matching and operator"); }
|
||||||
| sere OP_SHORT_AND sere
|
| sere OP_SHORT_AND sere
|
||||||
{ $$ = multop::instance(multop::AndNLM, $1, $3); }
|
{ $$ = fnode::multop(op::AndNLM, {$1, $3}); }
|
||||||
| sere OP_SHORT_AND error
|
| sere OP_SHORT_AND error
|
||||||
{ missing_right_binop($$, $1, @2,
|
{ missing_right_binop($$, $1, @2,
|
||||||
"non-length-matching and operator"); }
|
"non-length-matching and operator"); }
|
||||||
| sere OP_OR sere
|
| sere OP_OR sere
|
||||||
{ $$ = multop::instance(multop::OrRat, $1, $3); }
|
{ $$ = fnode::multop(op::OrRat, {$1, $3}); }
|
||||||
| sere OP_OR error
|
| sere OP_OR error
|
||||||
{ missing_right_binop($$, $1, @2, "or operator"); }
|
{ missing_right_binop($$, $1, @2, "or operator"); }
|
||||||
| sere OP_CONCAT sere
|
| sere OP_CONCAT sere
|
||||||
{ $$ = multop::instance(multop::Concat, $1, $3); }
|
{ $$ = fnode::multop(op::Concat, {$1, $3}); }
|
||||||
| sere OP_CONCAT error
|
| sere OP_CONCAT error
|
||||||
{ missing_right_binop($$, $1, @2, "concat operator"); }
|
{ missing_right_binop($$, $1, @2, "concat operator"); }
|
||||||
| sere OP_FUSION sere
|
| sere OP_FUSION sere
|
||||||
{ $$ = multop::instance(multop::Fusion, $1, $3); }
|
{ $$ = fnode::multop(op::Fusion, {$1, $3}); }
|
||||||
| sere OP_FUSION error
|
| sere OP_FUSION error
|
||||||
{ missing_right_binop($$, $1, @2, "fusion operator"); }
|
{ missing_right_binop($$, $1, @2, "fusion operator"); }
|
||||||
| starargs
|
| starargs
|
||||||
|
|
@ -534,8 +534,7 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@1, "reversed range");
|
error_list.emplace_back(@1, "reversed range");
|
||||||
std::swap($1.max, $1.min);
|
std::swap($1.max, $1.min);
|
||||||
}
|
}
|
||||||
$$ = bunop::instance(bunop::Star, constant::true_instance(),
|
$$ = fnode::bunop(op::Star, fnode::tt(), $1.min, $1.max);
|
||||||
$1.min, $1.max);
|
|
||||||
}
|
}
|
||||||
| sere starargs
|
| sere starargs
|
||||||
{
|
{
|
||||||
|
|
@ -544,7 +543,7 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@2, "reversed range");
|
error_list.emplace_back(@2, "reversed range");
|
||||||
std::swap($2.max, $2.min);
|
std::swap($2.max, $2.min);
|
||||||
}
|
}
|
||||||
$$ = bunop::instance(bunop::Star, $1, $2.min, $2.max);
|
$$ = fnode::bunop(op::Star, $1, $2.min, $2.max);
|
||||||
}
|
}
|
||||||
| sere fstarargs
|
| sere fstarargs
|
||||||
{
|
{
|
||||||
|
|
@ -553,7 +552,7 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@2, "reversed range");
|
error_list.emplace_back(@2, "reversed range");
|
||||||
std::swap($2.max, $2.min);
|
std::swap($2.max, $2.min);
|
||||||
}
|
}
|
||||||
$$ = bunop::instance(bunop::FStar, $1, $2.min, $2.max);
|
$$ = fnode::bunop(op::FStar, $1, $2.min, $2.max);
|
||||||
}
|
}
|
||||||
| sere equalargs
|
| sere equalargs
|
||||||
{
|
{
|
||||||
|
|
@ -564,7 +563,8 @@ sere: booleanatom
|
||||||
}
|
}
|
||||||
if ($1->is_boolean())
|
if ($1->is_boolean())
|
||||||
{
|
{
|
||||||
$$ = bunop::sugar_equal($1, $2.min, $2.max);
|
$$ = formula::sugar_equal(formula($1),
|
||||||
|
$2.min, $2.max).to_node_();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -574,7 +574,7 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@$,
|
error_list.emplace_back(@$,
|
||||||
"treating this block as false");
|
"treating this block as false");
|
||||||
$1->destroy();
|
$1->destroy();
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| sere gotoargs
|
| sere gotoargs
|
||||||
|
|
@ -586,7 +586,8 @@ sere: booleanatom
|
||||||
}
|
}
|
||||||
if ($1->is_boolean())
|
if ($1->is_boolean())
|
||||||
{
|
{
|
||||||
$$ = bunop::sugar_goto($1, $2.min, $2.max);
|
$$ = formula::sugar_goto(formula($1),
|
||||||
|
$2.min, $2.max).to_node_();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -596,14 +597,14 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@$,
|
error_list.emplace_back(@$,
|
||||||
"treating this block as false");
|
"treating this block as false");
|
||||||
$1->destroy();
|
$1->destroy();
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| sere OP_XOR sere
|
| sere OP_XOR sere
|
||||||
{
|
{
|
||||||
if ($1->is_boolean() && $3->is_boolean())
|
if ($1->is_boolean() && $3->is_boolean())
|
||||||
{
|
{
|
||||||
$$ = binop::instance(binop::Xor, $1, $3);
|
$$ = fnode::binop(op::Xor, $1, $3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -622,7 +623,7 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@$, "treating this block as false");
|
error_list.emplace_back(@$, "treating this block as false");
|
||||||
$1->destroy();
|
$1->destroy();
|
||||||
$3->destroy();
|
$3->destroy();
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| sere OP_XOR error
|
| sere OP_XOR error
|
||||||
|
|
@ -631,7 +632,7 @@ sere: booleanatom
|
||||||
{
|
{
|
||||||
if ($1->is_boolean())
|
if ($1->is_boolean())
|
||||||
{
|
{
|
||||||
$$ = binop::instance(binop::Implies, $1, $3);
|
$$ = fnode::binop(op::Implies, $1, $3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -644,7 +645,7 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@$, "treating this block as false");
|
error_list.emplace_back(@$, "treating this block as false");
|
||||||
$1->destroy();
|
$1->destroy();
|
||||||
$3->destroy();
|
$3->destroy();
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| sere OP_IMPLIES error
|
| sere OP_IMPLIES error
|
||||||
|
|
@ -653,7 +654,7 @@ sere: booleanatom
|
||||||
{
|
{
|
||||||
if ($1->is_boolean() && $3->is_boolean())
|
if ($1->is_boolean() && $3->is_boolean())
|
||||||
{
|
{
|
||||||
$$ = binop::instance(binop::Equiv, $1, $3);
|
$$ = fnode::binop(op::Equiv, $1, $3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -672,7 +673,7 @@ sere: booleanatom
|
||||||
error_list.emplace_back(@$, "treating this block as false");
|
error_list.emplace_back(@$, "treating this block as false");
|
||||||
$1->destroy();
|
$1->destroy();
|
||||||
$3->destroy();
|
$3->destroy();
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| sere OP_EQUIV error
|
| sere OP_EQUIV error
|
||||||
|
|
@ -687,7 +688,7 @@ bracedsere: BRACE_OPEN sere BRACE_CLOSE
|
||||||
| BRACE_OPEN error BRACE_CLOSE
|
| BRACE_OPEN error BRACE_CLOSE
|
||||||
{ error_list.emplace_back(@$,
|
{ error_list.emplace_back(@$,
|
||||||
"treating this brace block as false");
|
"treating this brace block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
| BRACE_OPEN sere END_OF_INPUT
|
| BRACE_OPEN sere END_OF_INPUT
|
||||||
{ error_list.emplace_back(@1 + @2,
|
{ error_list.emplace_back(@1 + @2,
|
||||||
|
|
@ -703,13 +704,13 @@ bracedsere: BRACE_OPEN sere BRACE_CLOSE
|
||||||
{ error_list.emplace_back(@$,
|
{ error_list.emplace_back(@$,
|
||||||
"missing closing brace, "
|
"missing closing brace, "
|
||||||
"treating this brace block as false");
|
"treating this brace block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
| BRA_BLOCK
|
| BRA_BLOCK
|
||||||
{
|
{
|
||||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||||
debug_level(),
|
debug_level(),
|
||||||
parser_sere, error_list);
|
parser_sere, error_list).to_node_();
|
||||||
delete $1;
|
delete $1;
|
||||||
if (!$$)
|
if (!$$)
|
||||||
YYERROR;
|
YYERROR;
|
||||||
|
|
@ -718,7 +719,8 @@ bracedsere: BRACE_OPEN sere BRACE_CLOSE
|
||||||
parenthesedsubformula: PAR_BLOCK
|
parenthesedsubformula: PAR_BLOCK
|
||||||
{
|
{
|
||||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||||
debug_level(), parser_ltl, error_list);
|
debug_level(), parser_ltl, error_list)
|
||||||
|
.to_node_();
|
||||||
delete $1;
|
delete $1;
|
||||||
if (!$$)
|
if (!$$)
|
||||||
YYERROR;
|
YYERROR;
|
||||||
|
|
@ -732,7 +734,7 @@ parenthesedsubformula: PAR_BLOCK
|
||||||
| PAR_OPEN error PAR_CLOSE
|
| PAR_OPEN error PAR_CLOSE
|
||||||
{ error_list.emplace_back(@$,
|
{ error_list.emplace_back(@$,
|
||||||
"treating this parenthetical block as false");
|
"treating this parenthetical block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
| PAR_OPEN subformula END_OF_INPUT
|
| PAR_OPEN subformula END_OF_INPUT
|
||||||
{ error_list.emplace_back(@1 + @2, "missing closing parenthesis");
|
{ error_list.emplace_back(@1 + @2, "missing closing parenthesis");
|
||||||
|
|
@ -747,7 +749,7 @@ parenthesedsubformula: PAR_BLOCK
|
||||||
{ error_list.emplace_back(@$,
|
{ error_list.emplace_back(@$,
|
||||||
"missing closing parenthesis, "
|
"missing closing parenthesis, "
|
||||||
"treating this parenthetical block as false");
|
"treating this parenthetical block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -755,7 +757,8 @@ boolformula: booleanatom
|
||||||
| PAR_BLOCK
|
| PAR_BLOCK
|
||||||
{
|
{
|
||||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||||
debug_level(), parser_bool, error_list);
|
debug_level(), parser_bool, error_list)
|
||||||
|
.to_node_();
|
||||||
delete $1;
|
delete $1;
|
||||||
if (!$$)
|
if (!$$)
|
||||||
YYERROR;
|
YYERROR;
|
||||||
|
|
@ -769,7 +772,7 @@ boolformula: booleanatom
|
||||||
| PAR_OPEN error PAR_CLOSE
|
| PAR_OPEN error PAR_CLOSE
|
||||||
{ error_list.emplace_back(@$,
|
{ error_list.emplace_back(@$,
|
||||||
"treating this parenthetical block as false");
|
"treating this parenthetical block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
| PAR_OPEN boolformula END_OF_INPUT
|
| PAR_OPEN boolformula END_OF_INPUT
|
||||||
{ error_list.emplace_back(@1 + @2,
|
{ error_list.emplace_back(@1 + @2,
|
||||||
|
|
@ -785,156 +788,153 @@ boolformula: booleanatom
|
||||||
{ error_list.emplace_back(@$,
|
{ error_list.emplace_back(@$,
|
||||||
"missing closing parenthesis, "
|
"missing closing parenthesis, "
|
||||||
"treating this parenthetical block as false");
|
"treating this parenthetical block as false");
|
||||||
$$ = constant::false_instance();
|
$$ = fnode::ff();
|
||||||
}
|
}
|
||||||
| boolformula OP_AND boolformula
|
| boolformula OP_AND boolformula
|
||||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||||
| boolformula OP_AND error
|
| boolformula OP_AND error
|
||||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||||
| boolformula OP_SHORT_AND boolformula
|
| boolformula OP_SHORT_AND boolformula
|
||||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||||
| boolformula OP_SHORT_AND error
|
| boolformula OP_SHORT_AND error
|
||||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||||
| boolformula OP_STAR boolformula
|
| boolformula OP_STAR boolformula
|
||||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||||
| boolformula OP_STAR error
|
| boolformula OP_STAR error
|
||||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||||
| boolformula OP_OR boolformula
|
| boolformula OP_OR boolformula
|
||||||
{ $$ = multop::instance(multop::Or, $1, $3); }
|
{ $$ = fnode::multop(op::Or, {$1, $3}); }
|
||||||
| boolformula OP_OR error
|
| boolformula OP_OR error
|
||||||
{ missing_right_binop($$, $1, @2, "or operator"); }
|
{ missing_right_binop($$, $1, @2, "or operator"); }
|
||||||
| boolformula OP_XOR boolformula
|
| boolformula OP_XOR boolformula
|
||||||
{ $$ = binop::instance(binop::Xor, $1, $3); }
|
{ $$ = fnode::binop(op::Xor, $1, $3); }
|
||||||
| boolformula OP_XOR error
|
| boolformula OP_XOR error
|
||||||
{ missing_right_binop($$, $1, @2, "xor operator"); }
|
{ missing_right_binop($$, $1, @2, "xor operator"); }
|
||||||
| boolformula OP_IMPLIES boolformula
|
| boolformula OP_IMPLIES boolformula
|
||||||
{ $$ = binop::instance(binop::Implies, $1, $3); }
|
{ $$ = fnode::binop(op::Implies, $1, $3); }
|
||||||
| boolformula OP_IMPLIES error
|
| boolformula OP_IMPLIES error
|
||||||
{ missing_right_binop($$, $1, @2, "implication operator"); }
|
{ missing_right_binop($$, $1, @2, "implication operator"); }
|
||||||
| boolformula OP_EQUIV boolformula
|
| boolformula OP_EQUIV boolformula
|
||||||
{ $$ = binop::instance(binop::Equiv, $1, $3); }
|
{ $$ = fnode::binop(op::Equiv, $1, $3); }
|
||||||
| boolformula OP_EQUIV error
|
| boolformula OP_EQUIV error
|
||||||
{ missing_right_binop($$, $1, @2, "equivalent operator"); }
|
{ missing_right_binop($$, $1, @2, "equivalent operator"); }
|
||||||
| OP_NOT boolformula
|
| OP_NOT boolformula
|
||||||
{ $$ = unop::instance(unop::Not, $2); }
|
{ $$ = fnode::unop(op::Not, $2); }
|
||||||
| OP_NOT error
|
| OP_NOT error
|
||||||
{ missing_right_op($$, @1, "not operator"); }
|
{ missing_right_op($$, @1, "not operator"); }
|
||||||
|
|
||||||
subformula: booleanatom
|
subformula: booleanatom
|
||||||
| parenthesedsubformula
|
| parenthesedsubformula
|
||||||
| subformula OP_AND subformula
|
| subformula OP_AND subformula
|
||||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||||
| subformula OP_AND error
|
| subformula OP_AND error
|
||||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||||
| subformula OP_SHORT_AND subformula
|
| subformula OP_SHORT_AND subformula
|
||||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||||
| subformula OP_SHORT_AND error
|
| subformula OP_SHORT_AND error
|
||||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||||
| subformula OP_STAR subformula
|
| subformula OP_STAR subformula
|
||||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||||
| subformula OP_STAR error
|
| subformula OP_STAR error
|
||||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||||
| subformula OP_OR subformula
|
| subformula OP_OR subformula
|
||||||
{ $$ = multop::instance(multop::Or, $1, $3); }
|
{ $$ = fnode::multop(op::Or, {$1, $3}); }
|
||||||
| subformula OP_OR error
|
| subformula OP_OR error
|
||||||
{ missing_right_binop($$, $1, @2, "or operator"); }
|
{ missing_right_binop($$, $1, @2, "or operator"); }
|
||||||
| subformula OP_XOR subformula
|
| subformula OP_XOR subformula
|
||||||
{ $$ = binop::instance(binop::Xor, $1, $3); }
|
{ $$ = fnode::binop(op::Xor, $1, $3); }
|
||||||
| subformula OP_XOR error
|
| subformula OP_XOR error
|
||||||
{ missing_right_binop($$, $1, @2, "xor operator"); }
|
{ missing_right_binop($$, $1, @2, "xor operator"); }
|
||||||
| subformula OP_IMPLIES subformula
|
| subformula OP_IMPLIES subformula
|
||||||
{ $$ = binop::instance(binop::Implies, $1, $3); }
|
{ $$ = fnode::binop(op::Implies, $1, $3); }
|
||||||
| subformula OP_IMPLIES error
|
| subformula OP_IMPLIES error
|
||||||
{ missing_right_binop($$, $1, @2, "implication operator"); }
|
{ missing_right_binop($$, $1, @2, "implication operator"); }
|
||||||
| subformula OP_EQUIV subformula
|
| subformula OP_EQUIV subformula
|
||||||
{ $$ = binop::instance(binop::Equiv, $1, $3); }
|
{ $$ = fnode::binop(op::Equiv, $1, $3); }
|
||||||
| subformula OP_EQUIV error
|
| subformula OP_EQUIV error
|
||||||
{ missing_right_binop($$, $1, @2, "equivalent operator"); }
|
{ missing_right_binop($$, $1, @2, "equivalent operator"); }
|
||||||
| subformula OP_U subformula
|
| subformula OP_U subformula
|
||||||
{ $$ = binop::instance(binop::U, $1, $3); }
|
{ $$ = fnode::binop(op::U, $1, $3); }
|
||||||
| subformula OP_U error
|
| subformula OP_U error
|
||||||
{ missing_right_binop($$, $1, @2, "until operator"); }
|
{ missing_right_binop($$, $1, @2, "until operator"); }
|
||||||
| subformula OP_R subformula
|
| subformula OP_R subformula
|
||||||
{ $$ = binop::instance(binop::R, $1, $3); }
|
{ $$ = fnode::binop(op::R, $1, $3); }
|
||||||
| subformula OP_R error
|
| subformula OP_R error
|
||||||
{ missing_right_binop($$, $1, @2, "release operator"); }
|
{ missing_right_binop($$, $1, @2, "release operator"); }
|
||||||
| subformula OP_W subformula
|
| subformula OP_W subformula
|
||||||
{ $$ = binop::instance(binop::W, $1, $3); }
|
{ $$ = fnode::binop(op::W, $1, $3); }
|
||||||
| subformula OP_W error
|
| subformula OP_W error
|
||||||
{ missing_right_binop($$, $1, @2, "weak until operator"); }
|
{ missing_right_binop($$, $1, @2, "weak until operator"); }
|
||||||
| subformula OP_M subformula
|
| subformula OP_M subformula
|
||||||
{ $$ = binop::instance(binop::M, $1, $3); }
|
{ $$ = fnode::binop(op::M, $1, $3); }
|
||||||
| subformula OP_M error
|
| subformula OP_M error
|
||||||
{ missing_right_binop($$, $1, @2, "strong release operator"); }
|
{ missing_right_binop($$, $1, @2, "strong release operator"); }
|
||||||
| OP_F subformula
|
| OP_F subformula
|
||||||
{ $$ = unop::instance(unop::F, $2); }
|
{ $$ = fnode::unop(op::F, $2); }
|
||||||
| OP_F error
|
| OP_F error
|
||||||
{ missing_right_op($$, @1, "sometimes operator"); }
|
{ missing_right_op($$, @1, "sometimes operator"); }
|
||||||
| OP_G subformula
|
| OP_G subformula
|
||||||
{ $$ = unop::instance(unop::G, $2); }
|
{ $$ = fnode::unop(op::G, $2); }
|
||||||
| OP_G error
|
| OP_G error
|
||||||
{ missing_right_op($$, @1, "always operator"); }
|
{ missing_right_op($$, @1, "always operator"); }
|
||||||
| OP_X subformula
|
| OP_X subformula
|
||||||
{ $$ = unop::instance(unop::X, $2); }
|
{ $$ = fnode::unop(op::X, $2); }
|
||||||
| OP_X error
|
| OP_X error
|
||||||
{ missing_right_op($$, @1, "next operator"); }
|
{ missing_right_op($$, @1, "next operator"); }
|
||||||
| OP_NOT subformula
|
| OP_NOT subformula
|
||||||
{ $$ = unop::instance(unop::Not, $2); }
|
{ $$ = fnode::unop(op::Not, $2); }
|
||||||
| OP_NOT error
|
| OP_NOT error
|
||||||
{ missing_right_op($$, @1, "not operator"); }
|
{ missing_right_op($$, @1, "not operator"); }
|
||||||
| bracedsere
|
| bracedsere
|
||||||
{ $$ = unop::instance(unop::Closure, $1); }
|
{ $$ = fnode::unop(op::Closure, $1); }
|
||||||
| bracedsere OP_UCONCAT subformula
|
| bracedsere OP_UCONCAT subformula
|
||||||
{ $$ = binop::instance(binop::UConcat, $1, $3); }
|
{ $$ = fnode::binop(op::UConcat, $1, $3); }
|
||||||
| bracedsere parenthesedsubformula
|
| bracedsere parenthesedsubformula
|
||||||
{ $$ = binop::instance(binop::UConcat, $1, $2); }
|
{ $$ = fnode::binop(op::UConcat, $1, $2); }
|
||||||
| bracedsere OP_UCONCAT error
|
| bracedsere OP_UCONCAT error
|
||||||
{ missing_right_binop_hard($$, $1, @2,
|
{ missing_right_binop_hard($$, $1, @2,
|
||||||
"universal overlapping concat operator"); }
|
"universal overlapping concat operator"); }
|
||||||
| bracedsere OP_ECONCAT subformula
|
| bracedsere OP_ECONCAT subformula
|
||||||
{ $$ = binop::instance(binop::EConcat, $1, $3); }
|
{ $$ = fnode::binop(op::EConcat, $1, $3); }
|
||||||
| bracedsere OP_ECONCAT error
|
| bracedsere OP_ECONCAT error
|
||||||
{ missing_right_binop_hard($$, $1, @2,
|
{ missing_right_binop_hard($$, $1, @2,
|
||||||
"existential overlapping concat operator");
|
"existential overlapping concat operator");
|
||||||
}
|
}
|
||||||
| bracedsere OP_UCONCAT_NONO subformula
|
| bracedsere OP_UCONCAT_NONO subformula
|
||||||
/* {SERE}[]=>EXP = {SERE;1}[]->EXP */
|
/* {SERE}[]=>EXP = {SERE;1}[]->EXP */
|
||||||
{ $$ = binop::instance(binop::UConcat,
|
{ $$ = fnode::binop(op::UConcat,
|
||||||
multop::instance(multop::Concat, $1,
|
fnode::multop(op::Concat, {$1, fnode::tt()}),
|
||||||
constant::true_instance()), $3);
|
$3); }
|
||||||
}
|
|
||||||
| bracedsere OP_UCONCAT_NONO error
|
| bracedsere OP_UCONCAT_NONO error
|
||||||
{ missing_right_binop_hard($$, $1, @2,
|
{ missing_right_binop_hard($$, $1, @2,
|
||||||
"universal non-overlapping concat operator");
|
"universal non-overlapping concat operator");
|
||||||
}
|
}
|
||||||
| bracedsere OP_ECONCAT_NONO subformula
|
| bracedsere OP_ECONCAT_NONO subformula
|
||||||
/* {SERE}<>=>EXP = {SERE;1}<>->EXP */
|
/* {SERE}<>=>EXP = {SERE;1}<>->EXP */
|
||||||
{ $$ = binop::instance(binop::EConcat,
|
{ $$ = fnode::binop(op::EConcat,
|
||||||
multop::instance(multop::Concat, $1,
|
fnode::multop(op::Concat, {$1, fnode::tt()}),
|
||||||
constant::true_instance()), $3);
|
$3); }
|
||||||
}
|
|
||||||
| bracedsere OP_ECONCAT_NONO error
|
| bracedsere OP_ECONCAT_NONO error
|
||||||
{ missing_right_binop_hard($$, $1, @2,
|
{ missing_right_binop_hard($$, $1, @2,
|
||||||
"existential non-overlapping concat operator");
|
"existential non-overlapping concat operator");
|
||||||
}
|
}
|
||||||
| BRACE_OPEN sere BRACE_BANG_CLOSE
|
| BRACE_OPEN sere BRACE_BANG_CLOSE
|
||||||
/* {SERE}! = {SERE} <>-> 1 */
|
/* {SERE}! = {SERE} <>-> 1 */
|
||||||
{ $$ = binop::instance(binop::EConcat, $2,
|
{ $$ = fnode::binop(op::EConcat, $2, fnode::tt()); }
|
||||||
constant::true_instance()); }
|
|
||||||
| BRA_BANG_BLOCK
|
| BRA_BANG_BLOCK
|
||||||
{
|
{
|
||||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||||
debug_level(), parser_sere, error_list);
|
debug_level(), parser_sere, error_list)
|
||||||
|
.to_node_();
|
||||||
delete $1;
|
delete $1;
|
||||||
if (!$$)
|
if (!$$)
|
||||||
YYERROR;
|
YYERROR;
|
||||||
$$ = binop::instance(binop::EConcat, $$,
|
$$ = fnode::binop(op::EConcat, $$, fnode::tt());
|
||||||
constant::true_instance());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lbtformula: ATOMIC_PROP
|
lbtformula: ATOMIC_PROP
|
||||||
{
|
{
|
||||||
$$ = parse_environment.require(*$1);
|
$$ = parse_environment.require(*$1).to_node_();
|
||||||
if (! $$)
|
if (! $$)
|
||||||
{
|
{
|
||||||
std::string s = "atomic proposition `";
|
std::string s = "atomic proposition `";
|
||||||
|
|
@ -950,37 +950,37 @@ lbtformula: ATOMIC_PROP
|
||||||
delete $1;
|
delete $1;
|
||||||
}
|
}
|
||||||
| '!' lbtformula
|
| '!' lbtformula
|
||||||
{ $$ = unop::instance(unop::Not, $2); }
|
{ $$ = fnode::unop(op::Not, $2); }
|
||||||
| '&' lbtformula lbtformula
|
| '&' lbtformula lbtformula
|
||||||
{ $$ = multop::instance(multop::And, $2, $3); }
|
{ $$ = fnode::multop(op::And, {$2, $3}); }
|
||||||
| '|' lbtformula lbtformula
|
| '|' lbtformula lbtformula
|
||||||
{ $$ = multop::instance(multop::Or, $2, $3); }
|
{ $$ = fnode::multop(op::Or, {$2, $3}); }
|
||||||
| '^' lbtformula lbtformula
|
| '^' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::Xor, $2, $3); }
|
{ $$ = fnode::binop(op::Xor, $2, $3); }
|
||||||
| 'i' lbtformula lbtformula
|
| 'i' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::Implies, $2, $3); }
|
{ $$ = fnode::binop(op::Implies, $2, $3); }
|
||||||
| 'e' lbtformula lbtformula
|
| 'e' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::Equiv, $2, $3); }
|
{ $$ = fnode::binop(op::Equiv, $2, $3); }
|
||||||
| 'X' lbtformula
|
| 'X' lbtformula
|
||||||
{ $$ = unop::instance(unop::X, $2); }
|
{ $$ = fnode::unop(op::X, $2); }
|
||||||
| 'F' lbtformula
|
| 'F' lbtformula
|
||||||
{ $$ = unop::instance(unop::F, $2); }
|
{ $$ = fnode::unop(op::F, $2); }
|
||||||
| 'G' lbtformula
|
| 'G' lbtformula
|
||||||
{ $$ = unop::instance(unop::G, $2); }
|
{ $$ = fnode::unop(op::G, $2); }
|
||||||
| 'U' lbtformula lbtformula
|
| 'U' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::U, $2, $3); }
|
{ $$ = fnode::binop(op::U, $2, $3); }
|
||||||
| 'V' lbtformula lbtformula
|
| 'V' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::R, $2, $3); }
|
{ $$ = fnode::binop(op::R, $2, $3); }
|
||||||
| 'R' lbtformula lbtformula
|
| 'R' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::R, $2, $3); }
|
{ $$ = fnode::binop(op::R, $2, $3); }
|
||||||
| 'W' lbtformula lbtformula
|
| 'W' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::W, $2, $3); }
|
{ $$ = fnode::binop(op::W, $2, $3); }
|
||||||
| 'M' lbtformula lbtformula
|
| 'M' lbtformula lbtformula
|
||||||
{ $$ = binop::instance(binop::M, $2, $3); }
|
{ $$ = fnode::binop(op::M, $2, $3); }
|
||||||
| 't'
|
| 't'
|
||||||
{ $$ = constant::true_instance(); }
|
{ $$ = fnode::tt(); }
|
||||||
| 'f'
|
| 'f'
|
||||||
{ $$ = constant::false_instance(); }
|
{ $$ = fnode::ff(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
@ -995,13 +995,13 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
const formula*
|
formula
|
||||||
parse_infix_psl(const std::string& ltl_string,
|
parse_infix_psl(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)
|
||||||
{
|
{
|
||||||
const formula* result = 0;
|
formula result = nullptr;
|
||||||
flex_set_buffer(ltl_string,
|
flex_set_buffer(ltl_string,
|
||||||
ltlyy::parser::token::START_LTL,
|
ltlyy::parser::token::START_LTL,
|
||||||
lenient);
|
lenient);
|
||||||
|
|
@ -1012,13 +1012,13 @@ namespace spot
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const 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)
|
||||||
{
|
{
|
||||||
const formula* result = 0;
|
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);
|
||||||
|
|
@ -1029,13 +1029,13 @@ namespace spot
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const 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)
|
||||||
{
|
{
|
||||||
const formula* result = 0;
|
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);
|
||||||
|
|
@ -1046,14 +1046,14 @@ namespace spot
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const 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)
|
||||||
{
|
{
|
||||||
const formula* result = 0;
|
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);
|
||||||
|
|
@ -1064,16 +1064,16 @@ namespace spot
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
parse_formula(const std::string& ltl_string, environment& env)
|
parse_formula(const std::string& ltl_string, environment& env)
|
||||||
{
|
{
|
||||||
parse_error_list pel;
|
parse_error_list pel;
|
||||||
const formula* f = parse_infix_psl(ltl_string, pel, env);
|
formula f = parse_infix_psl(ltl_string, pel, env);
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
if (format_parse_errors(s, ltl_string, pel))
|
if (format_parse_errors(s, ltl_string, pel))
|
||||||
{
|
{
|
||||||
parse_error_list pel2;
|
parse_error_list pel2;
|
||||||
const formula* g = parse_prefix_ltl(ltl_string, pel2, env);
|
formula g = parse_prefix_ltl(ltl_string, pel2, env);
|
||||||
if (pel2.empty())
|
if (pel2.empty())
|
||||||
return g;
|
return g;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,8 @@ namespace spot
|
||||||
/// \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 pointer to the formula built from \a ltl_string, or
|
/// \return A formula built from \a ltl_string, or
|
||||||
/// 0 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
|
||||||
|
|
@ -66,12 +66,12 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// \warning This function is not reentrant.
|
/// \warning This function is not reentrant.
|
||||||
SPOT_API
|
SPOT_API
|
||||||
const 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.
|
||||||
|
|
@ -82,8 +82,8 @@ namespace spot
|
||||||
/// \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 pointer to the formula built from \a ltl_string, or
|
/// \return A formula built from \a ltl_string, or
|
||||||
/// 0 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
|
||||||
|
|
@ -92,12 +92,12 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// \warning This function is not reentrant.
|
/// \warning This function is not reentrant.
|
||||||
SPOT_API
|
SPOT_API
|
||||||
const 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.
|
||||||
|
|
@ -105,8 +105,8 @@ namespace spot
|
||||||
/// 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 pointer to the formula built from \a ltl_string, or
|
/// \return A formula built from \a ltl_string, or
|
||||||
/// 0 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
|
||||||
|
|
@ -119,11 +119,11 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// \warning This function is not reentrant.
|
/// \warning This function is not reentrant.
|
||||||
SPOT_API
|
SPOT_API
|
||||||
const 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().
|
||||||
///
|
///
|
||||||
|
|
@ -131,7 +131,7 @@ namespace spot
|
||||||
/// 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 const 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());
|
||||||
|
|
||||||
|
|
@ -144,8 +144,8 @@ namespace spot
|
||||||
/// \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 pointer to the formula built from \a sere_string, or
|
/// \return A formula built from \a sere_string, or
|
||||||
/// 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
|
||||||
|
|
@ -154,12 +154,12 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// \warning This function is not reentrant.
|
/// \warning This function is not reentrant.
|
||||||
SPOT_API
|
SPOT_API
|
||||||
const 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::ltl::parse
|
||||||
/// or spot::ltl::ratexp
|
/// or spot::ltl::ratexp
|
||||||
|
|
@ -181,11 +181,10 @@ namespace spot
|
||||||
|
|
||||||
/// \brief Fix location of diagnostics assuming the input is utf8.
|
/// \brief Fix location of diagnostics assuming the input is utf8.
|
||||||
///
|
///
|
||||||
/// The spot::ltl::parse() and spot::ltl::parse_sere() function
|
/// The different parser functions return a parse_error_list that
|
||||||
/// return a parse_error_list that contain locations specified at
|
/// contain locations specified at the byte level. Although these
|
||||||
/// the byte level. Although these parser recognize some
|
/// parser recognize some utf8 characters they only work byte by
|
||||||
/// utf8 characters they only work byte by byte and will report
|
/// byte and will report positions by counting byte.
|
||||||
/// 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
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,12 @@ ltlvisitdir = $(pkgincludedir)/ltlvisit
|
||||||
ltlvisit_HEADERS = \
|
ltlvisit_HEADERS = \
|
||||||
apcollect.hh \
|
apcollect.hh \
|
||||||
contain.hh \
|
contain.hh \
|
||||||
clone.hh \
|
|
||||||
dot.hh \
|
dot.hh \
|
||||||
dump.hh \
|
|
||||||
exclusive.hh \
|
exclusive.hh \
|
||||||
length.hh \
|
length.hh \
|
||||||
mutation.hh \
|
mutation.hh \
|
||||||
nenoform.hh \
|
nenoform.hh \
|
||||||
print.hh \
|
print.hh \
|
||||||
postfix.hh \
|
|
||||||
randomltl.hh \
|
randomltl.hh \
|
||||||
relabel.hh \
|
relabel.hh \
|
||||||
remove_x.hh \
|
remove_x.hh \
|
||||||
|
|
@ -49,9 +46,7 @@ noinst_LTLIBRARIES = libltlvisit.la
|
||||||
libltlvisit_la_SOURCES = \
|
libltlvisit_la_SOURCES = \
|
||||||
apcollect.cc \
|
apcollect.cc \
|
||||||
contain.cc \
|
contain.cc \
|
||||||
clone.cc \
|
|
||||||
dot.cc \
|
dot.cc \
|
||||||
dump.cc \
|
|
||||||
exclusive.cc \
|
exclusive.cc \
|
||||||
length.cc \
|
length.cc \
|
||||||
mark.cc \
|
mark.cc \
|
||||||
|
|
@ -59,7 +54,6 @@ libltlvisit_la_SOURCES = \
|
||||||
mutation.cc \
|
mutation.cc \
|
||||||
nenoform.cc \
|
nenoform.cc \
|
||||||
print.cc \
|
print.cc \
|
||||||
postfix.cc \
|
|
||||||
randomltl.cc \
|
randomltl.cc \
|
||||||
relabel.cc \
|
relabel.cc \
|
||||||
remove_x.cc \
|
remove_x.cc \
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2014 Laboratoire de Recherche et Développement
|
// Copyright (C) 2012, 2014, 2015 Laboratoire de Recherche et Développement
|
||||||
// de l'Epita (LRDE).
|
// de l'Epita (LRDE).
|
||||||
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "apcollect.hh"
|
#include "apcollect.hh"
|
||||||
#include "ltlvisit/postfix.hh"
|
|
||||||
#include "twa/twa.hh"
|
#include "twa/twa.hh"
|
||||||
#include "twa/bdddict.hh"
|
#include "twa/bdddict.hh"
|
||||||
|
|
||||||
|
|
@ -29,70 +28,40 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class atomic_prop_collector : public spot::ltl::postfix_visitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
atomic_prop_collector(atomic_prop_set* s)
|
|
||||||
: postfix_visitor(), sap(s)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~atomic_prop_collector()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void doit(const spot::ltl::atomic_prop* ap)
|
|
||||||
{
|
|
||||||
sap->insert(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
atomic_prop_set* sap;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_prop_set create_atomic_prop_set(unsigned n)
|
atomic_prop_set create_atomic_prop_set(unsigned n)
|
||||||
{
|
{
|
||||||
atomic_prop_set res;
|
atomic_prop_set res;
|
||||||
auto& e = spot::ltl::default_environment::instance();
|
|
||||||
for (unsigned i = 0; i < n; ++i)
|
for (unsigned i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
std::ostringstream p;
|
std::ostringstream p;
|
||||||
p << 'p' << i;
|
p << 'p' << i;
|
||||||
res.insert(e.require(p.str()));
|
res.insert(formula::ap(p.str()));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_atomic_prop_set(atomic_prop_set& aprops)
|
|
||||||
{
|
|
||||||
atomic_prop_set::const_iterator i = aprops.begin();
|
|
||||||
while (i != aprops.end())
|
|
||||||
(*(i++))->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
atomic_prop_set*
|
atomic_prop_set*
|
||||||
atomic_prop_collect(const 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;
|
||||||
atomic_prop_collector v(s);
|
f.traverse([&](const formula& f)
|
||||||
f->accept(v);
|
{
|
||||||
|
if (f.is(op::AP))
|
||||||
|
s->insert(f);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdd
|
bdd
|
||||||
atomic_prop_collect_as_bdd(const formula* f, const twa_ptr& a)
|
atomic_prop_collect_as_bdd(formula f, const twa_ptr& a)
|
||||||
{
|
{
|
||||||
spot::ltl::atomic_prop_set aps;
|
spot::ltl::atomic_prop_set aps;
|
||||||
atomic_prop_collect(f, &aps);
|
atomic_prop_collect(f, &aps);
|
||||||
bdd res = bddtrue;
|
bdd res = bddtrue;
|
||||||
for (atomic_prop_set::const_iterator i = aps.begin();
|
for (auto f: aps)
|
||||||
i != aps.end(); ++i)
|
res &= bdd_ithvar(a->register_ap(f));
|
||||||
res &= bdd_ithvar(a->register_ap(*i));
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ltlast/atomic_prop.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <bddx.h>
|
#include <bddx.h>
|
||||||
#include "twa/fwd.hh"
|
#include "twa/fwd.hh"
|
||||||
|
|
@ -35,18 +35,12 @@ namespace spot
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Set of atomic propositions.
|
/// Set of atomic propositions.
|
||||||
typedef std::set<const atomic_prop*,
|
typedef std::set<formula> atomic_prop_set;
|
||||||
formula_ptr_less_than> 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 Destroy all the atomic propositions in an
|
|
||||||
/// atomic_prop_set.
|
|
||||||
SPOT_API void
|
|
||||||
destroy_atomic_prop_set(atomic_prop_set& aprops);
|
|
||||||
|
|
||||||
/// \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
|
||||||
|
|
@ -55,10 +49,8 @@ namespace spot
|
||||||
/// \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.
|
||||||
/// The atomic propositions inserted into \a s are not cloned, so
|
|
||||||
/// they are only valid as long as \a f is.
|
|
||||||
SPOT_API atomic_prop_set*
|
SPOT_API atomic_prop_set*
|
||||||
atomic_prop_collect(const formula* f, atomic_prop_set* s = 0);
|
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.
|
||||||
|
|
@ -67,8 +59,7 @@ namespace spot
|
||||||
/// \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(const formula* f,
|
atomic_prop_collect_as_bdd(formula f, const twa_ptr& a);
|
||||||
const twa_ptr& a);
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "clone.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
clone_visitor::clone_visitor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
clone_visitor::~clone_visitor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
clone_visitor::result() const
|
|
||||||
{
|
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clone_visitor::visit(const atomic_prop* ap)
|
|
||||||
{
|
|
||||||
result_ = ap->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clone_visitor::visit(const constant* c)
|
|
||||||
{
|
|
||||||
result_ = c->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clone_visitor::visit(const bunop* bo)
|
|
||||||
{
|
|
||||||
result_ = bunop::instance(bo->op(), recurse(bo->child()),
|
|
||||||
bo->min(), bo->max());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clone_visitor::visit(const unop* uo)
|
|
||||||
{
|
|
||||||
result_ = unop::instance(uo->op(), recurse(uo->child()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clone_visitor::visit(const binop* bo)
|
|
||||||
{
|
|
||||||
const formula* first = recurse(bo->first());
|
|
||||||
result_ = binop::instance(bo->op(),
|
|
||||||
first, recurse(bo->second()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clone_visitor::visit(const multop* mo)
|
|
||||||
{
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
unsigned mos = mo->size();
|
|
||||||
res->reserve(mos);
|
|
||||||
for (unsigned i = 0; i < mos; ++i)
|
|
||||||
res->push_back(recurse(mo->nth(i)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
clone_visitor::recurse(const formula* f)
|
|
||||||
{
|
|
||||||
f->accept(*this);
|
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ltlast/formula.hh"
|
|
||||||
#include "ltlast/visitor.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
/// \ingroup ltl_visitor
|
|
||||||
/// \brief Clone a formula.
|
|
||||||
///
|
|
||||||
/// This visitor is public, because it's convenient
|
|
||||||
/// to derive from it and override part of its methods.
|
|
||||||
/// But if you just want the functionality, consider using
|
|
||||||
/// spot::ltl::formula::clone instead, it is way faster.
|
|
||||||
class SPOT_API clone_visitor : public visitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
clone_visitor();
|
|
||||||
virtual ~clone_visitor();
|
|
||||||
|
|
||||||
const formula* result() const;
|
|
||||||
|
|
||||||
void visit(const atomic_prop* ap);
|
|
||||||
void visit(const unop* uo);
|
|
||||||
void visit(const binop* bo);
|
|
||||||
void visit(const multop* mo);
|
|
||||||
void visit(const constant* c);
|
|
||||||
void visit(const bunop* c);
|
|
||||||
|
|
||||||
virtual const formula* recurse(const formula* f);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const formula* result_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -22,10 +22,7 @@
|
||||||
|
|
||||||
#include "contain.hh"
|
#include "contain.hh"
|
||||||
#include "simplify.hh"
|
#include "simplify.hh"
|
||||||
#include "ltlast/unop.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "ltlast/binop.hh"
|
|
||||||
#include "ltlast/multop.hh"
|
|
||||||
#include "ltlast/constant.hh"
|
|
||||||
#include "twaalgos/product.hh"
|
#include "twaalgos/product.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
|
|
@ -50,13 +47,7 @@ namespace spot
|
||||||
void
|
void
|
||||||
language_containment_checker::clear()
|
language_containment_checker::clear()
|
||||||
{
|
{
|
||||||
while (!translated_.empty())
|
translated_.clear();
|
||||||
{
|
|
||||||
trans_map::iterator i = translated_.begin();
|
|
||||||
const formula* f = i->first;
|
|
||||||
translated_.erase(i);
|
|
||||||
f->destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -75,31 +66,26 @@ namespace spot
|
||||||
|
|
||||||
// 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(const formula* l,
|
language_containment_checker::contained(formula l,
|
||||||
const formula* g)
|
formula g)
|
||||||
{
|
{
|
||||||
if (l == g)
|
if (l == g)
|
||||||
return true;
|
return true;
|
||||||
record_* rl = register_formula_(l);
|
record_* rl = register_formula_(l);
|
||||||
const formula* ng = unop::instance(unop::Not, g->clone());
|
record_* rng = register_formula_(formula::Not(g));
|
||||||
record_* rng = register_formula_(ng);
|
|
||||||
ng->destroy();
|
|
||||||
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(const formula* l,
|
language_containment_checker::neg_contained(formula l,
|
||||||
const formula* g)
|
formula g)
|
||||||
{
|
{
|
||||||
if (l == g)
|
if (l == g)
|
||||||
return false;
|
return false;
|
||||||
const formula* nl = unop::instance(unop::Not, l->clone());
|
formula nl = formula::Not(l);
|
||||||
record_* rnl = register_formula_(nl);
|
record_* rnl = register_formula_(nl);
|
||||||
const formula* ng = unop::instance(unop::Not, g->clone());
|
record_* rng = register_formula_(formula::Not(g));
|
||||||
record_* rng = register_formula_(ng);
|
|
||||||
nl->destroy();
|
|
||||||
ng->destroy();
|
|
||||||
if (nl == g)
|
if (nl == g)
|
||||||
return true;
|
return true;
|
||||||
return incompatible_(rnl, rng);
|
return incompatible_(rnl, rng);
|
||||||
|
|
@ -107,8 +93,8 @@ namespace spot
|
||||||
|
|
||||||
// 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(const formula* l,
|
language_containment_checker::contained_neg(formula l,
|
||||||
const formula* g)
|
formula g)
|
||||||
{
|
{
|
||||||
if (l == g)
|
if (l == g)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -119,13 +105,13 @@ namespace spot
|
||||||
|
|
||||||
// Check whether L(l) = L(g).
|
// Check whether L(l) = L(g).
|
||||||
bool
|
bool
|
||||||
language_containment_checker::equal(const formula* l, const 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_(const 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())
|
||||||
|
|
@ -133,17 +119,17 @@ namespace spot
|
||||||
|
|
||||||
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->clone()];
|
record_& r = translated_[f];
|
||||||
r.translation = e;
|
r.translation = e;
|
||||||
return &r;
|
return &r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
reduce_tau03(const formula* f, bool stronger)
|
reduce_tau03(formula f, bool stronger)
|
||||||
{
|
{
|
||||||
if (!f->is_psl_formula())
|
if (!f.is_psl_formula())
|
||||||
return f->clone();
|
return f;
|
||||||
|
|
||||||
ltl_simplifier_options opt(false, false, false,
|
ltl_simplifier_options opt(false, false, false,
|
||||||
true, stronger);
|
true, stronger);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace spot
|
||||||
typedef std::map<const record_*, bool> incomp_map;
|
typedef std::map<const record_*, bool> incomp_map;
|
||||||
incomp_map incompatible;
|
incomp_map incompatible;
|
||||||
};
|
};
|
||||||
typedef std::unordered_map<const formula*, record_> trans_map;
|
typedef std::unordered_map<formula, record_> trans_map;
|
||||||
public:
|
public:
|
||||||
/// This class uses spot::ltl_to_tgba_fm to translate LTL
|
/// This class uses spot::ltl_to_tgba_fm to translate LTL
|
||||||
/// formulae. See that function for the meaning of these options.
|
/// formulae. See that function for the meaning of these options.
|
||||||
|
|
@ -55,19 +55,19 @@ namespace spot
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
/// Check whether L(l) is a subset of L(g).
|
/// Check whether L(l) is a subset of L(g).
|
||||||
bool contained(const formula* l, const formula* g);
|
bool contained(formula l, formula g);
|
||||||
/// Check whether L(!l) is a subset of L(g).
|
/// Check whether L(!l) is a subset of L(g).
|
||||||
bool neg_contained(const formula* l, const formula* g);
|
bool neg_contained(formula l, formula g);
|
||||||
/// Check whether L(l) is a subset of L(!g).
|
/// Check whether L(l) is a subset of L(!g).
|
||||||
bool contained_neg(const formula* l, const formula* g);
|
bool contained_neg(formula l, formula g);
|
||||||
|
|
||||||
/// Check whether L(l) = L(g).
|
/// Check whether L(l) = L(g).
|
||||||
bool equal(const formula* l, const formula* g);
|
bool equal(formula l, formula g);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool incompatible_(record_* l, record_* g);
|
bool incompatible_(record_* l, record_* g);
|
||||||
|
|
||||||
record_* register_formula_(const formula* f);
|
record_* register_formula_(formula f);
|
||||||
|
|
||||||
/* Translation options */
|
/* Translation options */
|
||||||
bdd_dict_ptr dict_;
|
bdd_dict_ptr dict_;
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,9 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "misc/hash.hh"
|
|
||||||
#include "dot.hh"
|
#include "dot.hh"
|
||||||
#include "ltlast/visitor.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
#include <unordered_map>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
@ -33,160 +32,106 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class dotty_visitor: public visitor
|
struct dot_printer final
|
||||||
{
|
{
|
||||||
public:
|
std::ostream& os_;
|
||||||
typedef std::unordered_map<const formula*, int, ptr_hash<formula>> map;
|
std::unordered_map<formula, int> node_;
|
||||||
dotty_visitor(std::ostream& os, map& m)
|
std::ostringstream* sinks_;
|
||||||
: os_(os), father_(-1), node_(m), sinks_(new std::ostringstream)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual
|
dot_printer(std::ostream& os, formula f)
|
||||||
~dotty_visitor()
|
: os_(os), sinks_(new std::ostringstream)
|
||||||
{
|
{
|
||||||
}
|
os_ << "digraph G {\n";
|
||||||
|
rec(f);
|
||||||
|
os_ << " subgraph atoms {\n rank=sink;\n"
|
||||||
|
<< sinks_->str() << " }\n}\n";
|
||||||
|
}
|
||||||
|
|
||||||
void
|
~dot_printer()
|
||||||
visit(const atomic_prop* ap)
|
|
||||||
{
|
{
|
||||||
draw_node_(ap, ap->name(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const constant* c)
|
|
||||||
{
|
|
||||||
draw_node_(c, c->val_name(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const bunop* so)
|
|
||||||
{
|
|
||||||
if (draw_node_(so, so->format()))
|
|
||||||
{
|
|
||||||
childnum = 0;
|
|
||||||
so->child()->accept(*this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const binop* bo)
|
|
||||||
{
|
|
||||||
if (draw_node_(bo, bo->op_name()))
|
|
||||||
{
|
|
||||||
childnum = -1;
|
|
||||||
dotty_visitor v(*this);
|
|
||||||
bo->first()->accept(v);
|
|
||||||
childnum = -2;
|
|
||||||
bo->second()->accept(*this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const unop* uo)
|
|
||||||
{
|
|
||||||
if (draw_node_(uo, uo->op_name()))
|
|
||||||
{
|
|
||||||
childnum = 0;
|
|
||||||
uo->child()->accept(*this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
if (!draw_node_(mo, mo->op_name()))
|
|
||||||
return;
|
|
||||||
childnum = 0;
|
|
||||||
unsigned max = mo->size();
|
|
||||||
multop::type op = mo->op();
|
|
||||||
bool update_childnum = (op == multop::Fusion ||
|
|
||||||
op == multop::Concat);
|
|
||||||
|
|
||||||
for (unsigned n = 0; n < max; ++n)
|
|
||||||
{
|
|
||||||
if (update_childnum)
|
|
||||||
++childnum;
|
|
||||||
dotty_visitor v(*this);
|
|
||||||
mo->nth(n)->accept(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void finish()
|
|
||||||
{
|
|
||||||
os_ << (" subgraph atoms {\n"
|
|
||||||
" rank=sink;\n")
|
|
||||||
<< sinks_->str() << " }\n";
|
|
||||||
delete sinks_;
|
delete sinks_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int childnum;
|
int rec(formula f)
|
||||||
|
|
||||||
private:
|
|
||||||
std::ostream& os_;
|
|
||||||
int father_;
|
|
||||||
map& node_;
|
|
||||||
std::ostringstream* sinks_;
|
|
||||||
|
|
||||||
bool
|
|
||||||
draw_node_(const formula* f, const std::string& str, bool sink = false)
|
|
||||||
{
|
{
|
||||||
map::iterator i = node_.find(f);
|
auto i = node_.emplace(f, node_.size());
|
||||||
int node;
|
int src = i.first->second;
|
||||||
bool node_exists = false;
|
if (!i.second)
|
||||||
if (i != node_.end())
|
return src;
|
||||||
{
|
|
||||||
node = i->second;
|
op o = f.kind();
|
||||||
node_exists = true;
|
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
|
else
|
||||||
|
os_ << " " << src << " [label=\"" << str << "\"];\n";
|
||||||
|
|
||||||
|
int childnum = 0;
|
||||||
|
switch (o)
|
||||||
{
|
{
|
||||||
node = node_.size();
|
case op::False:
|
||||||
node_[f] = node;
|
case op::True:
|
||||||
|
case op::EmptyWord:
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
// the link
|
|
||||||
if (father_ >= 0)
|
for (auto c: f)
|
||||||
{
|
{
|
||||||
os_ << " " << father_ << " -> " << node;
|
os_ << " " << src << " -> " << rec(c);
|
||||||
if (childnum > 0)
|
if (childnum > 0)
|
||||||
os_ << " [taillabel=\"" << childnum << "\"]";
|
os_ << " [taillabel=\"" << childnum << "\"]";
|
||||||
if (childnum == -1)
|
if (childnum == -2)
|
||||||
os_ << " [taillabel=\"L\"]";
|
os_ << " [taillabel=\"L\"]";
|
||||||
else if (childnum == -2)
|
else if (childnum == -1)
|
||||||
os_ << " [taillabel=\"R\"]";
|
os_ << " [taillabel=\"R\"]";
|
||||||
os_ << ";\n";
|
os_ << ";\n";
|
||||||
|
++childnum;
|
||||||
}
|
}
|
||||||
father_ = node;
|
|
||||||
|
|
||||||
// the node
|
return src;
|
||||||
if (node_exists)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!sink)
|
|
||||||
{
|
|
||||||
os_ << " " << node << " [label=\"" << str << "\"];";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*sinks_ << " " << node
|
|
||||||
<< " [label=\"" << str << "\", shape=box];\n";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
print_dot_psl(std::ostream& os, const formula* f)
|
print_dot_psl(std::ostream& os, formula f)
|
||||||
{
|
{
|
||||||
dotty_visitor::map m;
|
dot_printer p(os, f);
|
||||||
dotty_visitor v(os, m);
|
|
||||||
os << "digraph G {\n";
|
|
||||||
f->accept(v);
|
|
||||||
v.finish();
|
|
||||||
os << '}' << std::endl;
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ltlast/formula.hh>
|
#include <ltlast/formula.hh>
|
||||||
#include <iosfwd>
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -37,6 +36,6 @@ namespace spot
|
||||||
/// \c dot is part of the GraphViz package
|
/// \c dot is part of the GraphViz package
|
||||||
/// http://www.graphviz.org/
|
/// http://www.graphviz.org/
|
||||||
SPOT_API
|
SPOT_API
|
||||||
std::ostream& print_dot_psl(std::ostream& os, const formula* f);
|
std::ostream& print_dot_psl(std::ostream& os, formula f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2015 Laboratoire de Recherche et Développement de
|
|
||||||
// l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "dump.hh"
|
|
||||||
#include "ltlast/visitor.hh"
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
std::ostream&
|
|
||||||
dump(std::ostream& os, const formula* f)
|
|
||||||
{
|
|
||||||
os << f->dump();
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2013 Laboratoire de Recherche et Développement de
|
|
||||||
// l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ltlast/formula.hh"
|
|
||||||
#include <iosfwd>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
/// \ingroup ltl_io
|
|
||||||
/// \brief Dump a formula tree.
|
|
||||||
/// \param os The stream where it should be output.
|
|
||||||
/// \param f The formula to dump.
|
|
||||||
///
|
|
||||||
/// This is useful to display a formula when debugging.
|
|
||||||
SPOT_API
|
|
||||||
std::ostream& dump(std::ostream& os, const formula* f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -18,10 +18,6 @@
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "exclusive.hh"
|
#include "exclusive.hh"
|
||||||
#include "ltlenv/defaultenv.hh"
|
|
||||||
#include "ltlast/multop.hh"
|
|
||||||
#include "ltlast/unop.hh"
|
|
||||||
#include "ltlast/constant.hh"
|
|
||||||
#include "twaalgos/mask.hh"
|
#include "twaalgos/mask.hh"
|
||||||
#include "misc/casts.hh"
|
#include "misc/casts.hh"
|
||||||
#include "misc/minato.hh"
|
#include "misc/minato.hh"
|
||||||
|
|
@ -29,20 +25,12 @@
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
exclusive_ap::~exclusive_ap()
|
|
||||||
{
|
|
||||||
for (auto& g: groups)
|
|
||||||
for (auto ap: g)
|
|
||||||
ap->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static const std::vector<const spot::ltl::atomic_prop*>
|
static const std::vector<ltl::formula>
|
||||||
split_aps(const char* arg)
|
split_aps(const char* arg)
|
||||||
{
|
{
|
||||||
auto& env = spot::ltl::default_environment::instance();
|
std::vector<ltl::formula> group;
|
||||||
std::vector<const spot::ltl::atomic_prop*> group;
|
|
||||||
auto start = arg;
|
auto start = arg;
|
||||||
while (*start)
|
while (*start)
|
||||||
{
|
{
|
||||||
|
|
@ -73,8 +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);
|
||||||
auto* t = env.require(ap);
|
group.emplace_back(ltl::formula::ap(ap));
|
||||||
group.push_back(down_cast<const spot::ltl::atomic_prop*>(t));
|
|
||||||
do
|
do
|
||||||
++end;
|
++end;
|
||||||
while (*end == ' ' || *end == '\t');
|
while (*end == ' ' || *end == '\t');
|
||||||
|
|
@ -99,8 +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);
|
||||||
auto* t = env.require(ap);
|
group.emplace_back(ltl::formula::ap(ap));
|
||||||
group.push_back(down_cast<const spot::ltl::atomic_prop*>(t));
|
|
||||||
if (*end == ',')
|
if (*end == ',')
|
||||||
start = end + 1;
|
start = end + 1;
|
||||||
else
|
else
|
||||||
|
|
@ -116,29 +102,27 @@ namespace spot
|
||||||
add_group(split_aps(ap_csv));
|
add_group(split_aps(ap_csv));
|
||||||
}
|
}
|
||||||
|
|
||||||
void exclusive_ap::add_group(std::vector<const ltl::atomic_prop*> ap)
|
void exclusive_ap::add_group(std::vector<ltl::formula> ap)
|
||||||
{
|
{
|
||||||
groups.push_back(ap);
|
groups.push_back(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const ltl::formula*
|
ltl::formula
|
||||||
nand(const ltl::formula* lhs, const ltl::formula* rhs)
|
nand(ltl::formula lhs, ltl::formula rhs)
|
||||||
{
|
{
|
||||||
auto f = ltl::multop::instance(ltl::multop::And,
|
return ltl::formula::Not(ltl::formula::And({lhs, rhs}));
|
||||||
lhs->clone(), rhs->clone());
|
|
||||||
return ltl::unop::instance(ltl::unop::Not, f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ltl::formula*
|
ltl::formula
|
||||||
exclusive_ap::constrain(const ltl::formula* f) const
|
exclusive_ap::constrain(ltl::formula f) const
|
||||||
{
|
{
|
||||||
spot::ltl::atomic_prop_set* s = atomic_prop_collect(f);
|
auto* s = atomic_prop_collect(f);
|
||||||
|
|
||||||
std::vector<const ltl::atomic_prop*> group;
|
std::vector<ltl::formula> group;
|
||||||
ltl::multop::vec* v = new ltl::multop::vec;
|
std::vector<ltl::formula> v;
|
||||||
|
|
||||||
for (auto& g: groups)
|
for (auto& g: groups)
|
||||||
{
|
{
|
||||||
|
|
@ -151,14 +135,11 @@ namespace spot
|
||||||
unsigned s = group.size();
|
unsigned s = group.size();
|
||||||
for (unsigned j = 0; j < s; ++j)
|
for (unsigned j = 0; j < s; ++j)
|
||||||
for (unsigned k = j + 1; k < s; ++k)
|
for (unsigned k = j + 1; k < s; ++k)
|
||||||
v->push_back(nand(group[j], group[k]));
|
v.push_back(nand(group[j], group[k]));
|
||||||
};
|
};
|
||||||
|
|
||||||
delete s;
|
delete s;
|
||||||
|
return ltl::formula::And({f, ltl::formula::G(ltl::formula::And(v))});
|
||||||
auto* c = ltl::unop::instance(ltl::unop::G,
|
|
||||||
ltl::multop::instance(ltl::multop::And, v));
|
|
||||||
return ltl::multop::instance(ltl::multop::And, f->clone(), c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
twa_graph_ptr exclusive_ap::constrain(const_twa_graph_ptr aut,
|
twa_graph_ptr exclusive_ap::constrain(const_twa_graph_ptr aut,
|
||||||
|
|
|
||||||
|
|
@ -20,19 +20,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "ltlast/atomic_prop.hh"
|
|
||||||
#include "ltlast/formula.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "twa/twagraph.hh"
|
#include "twa/twagraph.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
class SPOT_API exclusive_ap
|
class SPOT_API exclusive_ap final
|
||||||
{
|
{
|
||||||
std::vector<std::vector<const ltl::atomic_prop*>> groups;
|
std::vector<std::vector<ltl::formula>> groups;
|
||||||
public:
|
public:
|
||||||
~exclusive_ap();
|
|
||||||
#ifndef SWIG
|
#ifndef SWIG
|
||||||
void add_group(std::vector<const ltl::atomic_prop*> ap);
|
void add_group(std::vector<ltl::formula> ap);
|
||||||
#endif
|
#endif
|
||||||
void add_group(const char* ap_csv);
|
void add_group(const char* ap_csv);
|
||||||
|
|
||||||
|
|
@ -41,7 +39,7 @@ namespace spot
|
||||||
return groups.empty();
|
return groups.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ltl::formula* constrain(const ltl::formula* f) const;
|
ltl::formula constrain(ltl::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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2010, 2012, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2010, 2012, 2014, 2015 Laboratoire de Recherche et
|
||||||
// Développement de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
|
@ -21,111 +21,59 @@
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "length.hh"
|
#include "length.hh"
|
||||||
#include "ltlvisit/postfix.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "ltlast/multop.hh"
|
|
||||||
#include "ltlast/unop.hh"
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
namespace
|
int
|
||||||
|
length(formula f)
|
||||||
{
|
{
|
||||||
class length_visitor: public postfix_visitor
|
int len = 0;
|
||||||
{
|
f.traverse([&len](const formula& x)
|
||||||
public:
|
{
|
||||||
length_visitor()
|
auto s = x.size();
|
||||||
: result_(0)
|
if (s > 1)
|
||||||
{
|
len += s - 1;
|
||||||
}
|
else
|
||||||
|
++len;
|
||||||
int
|
return false;
|
||||||
result() const
|
});
|
||||||
{
|
return len;
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
unsigned s = mo->size();
|
|
||||||
for (unsigned i = 0; i < s; ++i)
|
|
||||||
mo->nth(i)->accept(*this);
|
|
||||||
// "a & b & c" should count for 5, even though it is
|
|
||||||
// stored as And(a,b,c).
|
|
||||||
result_ += s - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
doit_default(const formula*)
|
|
||||||
{
|
|
||||||
++result_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int result_; // size of the formula
|
|
||||||
};
|
|
||||||
|
|
||||||
class length_boolone_visitor: public length_visitor
|
|
||||||
{
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
visit(const unop* uo)
|
|
||||||
{
|
|
||||||
++result_;
|
|
||||||
// Boolean formulas have length one.
|
|
||||||
if (!uo->is_boolean())
|
|
||||||
uo->child()->accept(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
// Boolean formulas have length one.
|
|
||||||
if (mo->is_boolean())
|
|
||||||
{
|
|
||||||
++result_;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned s = mo->size();
|
|
||||||
unsigned bool_seen = 0;
|
|
||||||
for (unsigned i = 0; i < s; ++i)
|
|
||||||
{
|
|
||||||
const formula* f = mo->nth(i);
|
|
||||||
// Ignore all Boolean children. We only want to count them once.
|
|
||||||
if (f->is_boolean())
|
|
||||||
++bool_seen;
|
|
||||||
else
|
|
||||||
f->accept(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// "a & b & c" should count for 5, even though it is stored
|
|
||||||
// as And(a,b,c). So add the number of operators here (it
|
|
||||||
// is either s - 1 or s - bool_seen depending on whether
|
|
||||||
// Boolean children were encountered). If Boolean were
|
|
||||||
// seen, also add one (!!bool_seen) to account for the
|
|
||||||
// "global" Boolean term.
|
|
||||||
result_ += s - !bool_seen - bool_seen + !!bool_seen;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
length(const formula* f)
|
length_boolone(formula f)
|
||||||
{
|
{
|
||||||
length_visitor v;
|
int len = 0;
|
||||||
f->accept(v);
|
f.traverse([&len](const formula& x)
|
||||||
return v.result();
|
{
|
||||||
}
|
if (x.is_boolean())
|
||||||
|
{
|
||||||
int
|
++len;
|
||||||
length_boolone(const formula* f)
|
return true;
|
||||||
{
|
}
|
||||||
length_boolone_visitor v;
|
auto s = x.size();
|
||||||
f->accept(v);
|
if (s > 2)
|
||||||
return v.result();
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Developement de
|
// Copyright (C) 2012, 2013, 2015 Laboratoire de Recherche et
|
||||||
// l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
// et Marie Curie.
|
// et Marie Curie.
|
||||||
|
|
@ -33,15 +33,14 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// The length of a formula is the number of atomic propositions,
|
/// The length of a formula is the number of atomic propositions,
|
||||||
/// constants, and operators (logical and temporal) occurring in
|
/// constants, and operators (logical and temporal) occurring in
|
||||||
/// the formula. spot::ltl::multop instances with n arguments
|
/// the formula. n-ary operators count for n-1; for instance
|
||||||
/// count for n-1; for instance <code>a | b | c</code> has length
|
/// <code>a | b | c</code> has length 5, even if there is only as
|
||||||
/// 5, even if there is only as single <code>|</code> node
|
/// single <code>|</code> node internally.
|
||||||
/// internally.
|
|
||||||
///
|
///
|
||||||
/// If squash_boolean is set, all Boolean formulae are assumed
|
/// If squash_boolean is set, all Boolean formulae are assumed
|
||||||
/// to have length one.
|
/// to have length one.
|
||||||
SPOT_API
|
SPOT_API
|
||||||
int length(const formula* f);
|
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
|
||||||
|
|
@ -49,6 +48,6 @@ namespace spot
|
||||||
/// This is similar to spot::ltl::length(), except all Boolean
|
/// This is similar to spot::ltl::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(const formula* f);
|
int length_boolone(formula f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,344 +18,176 @@
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "mark.hh"
|
#include "mark.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "misc/casts.hh"
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
namespace
|
formula
|
||||||
{
|
mark_tools::mark_concat_ops(formula f)
|
||||||
class simplify_mark_visitor : public visitor
|
|
||||||
{
|
|
||||||
const formula* result_;
|
|
||||||
mark_tools* tools_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
simplify_mark_visitor(mark_tools* t)
|
|
||||||
: tools_(t)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~simplify_mark_visitor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
result()
|
|
||||||
{
|
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const atomic_prop* ao)
|
|
||||||
{
|
|
||||||
result_ = ao->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const constant* c)
|
|
||||||
{
|
|
||||||
result_ = c->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const bunop* bo)
|
|
||||||
{
|
|
||||||
result_ = bo->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const unop* uo)
|
|
||||||
{
|
|
||||||
result_ = uo->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
unsigned mos = mo->size();
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
switch (mo->op())
|
|
||||||
{
|
|
||||||
case multop::OrRat:
|
|
||||||
case multop::AndNLM:
|
|
||||||
case multop::AndRat:
|
|
||||||
case multop::Concat:
|
|
||||||
case multop::Fusion:
|
|
||||||
SPOT_UNIMPLEMENTED();
|
|
||||||
case multop::Or:
|
|
||||||
for (unsigned i = 0; i < mos; ++i)
|
|
||||||
res->push_back(recurse(mo->nth(i)));
|
|
||||||
break;
|
|
||||||
case multop::And:
|
|
||||||
{
|
|
||||||
typedef std::set<std::pair<const formula*,
|
|
||||||
const formula*> > pset;
|
|
||||||
pset empairs;
|
|
||||||
typedef std::set<const formula*> sset;
|
|
||||||
sset nmset;
|
|
||||||
typedef std::vector<const binop*> unbinop;
|
|
||||||
unbinop elist;
|
|
||||||
typedef std::vector<const unop*> ununop;
|
|
||||||
ununop nlist;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < mos; ++i)
|
|
||||||
{
|
|
||||||
const formula* f = mo->nth(i);
|
|
||||||
if (const binop* bo = is_binop(f))
|
|
||||||
{
|
|
||||||
switch (bo->op())
|
|
||||||
{
|
|
||||||
case binop::EConcatMarked:
|
|
||||||
empairs.emplace(bo->first(), bo->second());
|
|
||||||
// fall through
|
|
||||||
case binop::Xor:
|
|
||||||
case binop::Implies:
|
|
||||||
case binop::Equiv:
|
|
||||||
case binop::U:
|
|
||||||
case binop::W:
|
|
||||||
case binop::M:
|
|
||||||
case binop::R:
|
|
||||||
case binop::UConcat:
|
|
||||||
res->push_back(recurse(f));
|
|
||||||
break;
|
|
||||||
case binop::EConcat:
|
|
||||||
elist.push_back(bo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (const unop* uo = is_unop(f))
|
|
||||||
{
|
|
||||||
switch (uo->op())
|
|
||||||
{
|
|
||||||
case unop::NegClosureMarked:
|
|
||||||
nmset.insert(uo->child());
|
|
||||||
// fall through
|
|
||||||
case unop::Not:
|
|
||||||
case unop::X:
|
|
||||||
case unop::F:
|
|
||||||
case unop::G:
|
|
||||||
case unop::Closure:
|
|
||||||
res->push_back(recurse(f));
|
|
||||||
break;
|
|
||||||
case unop::NegClosure:
|
|
||||||
nlist.push_back(uo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res->push_back(recurse(f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Keep only the non-marked EConcat for which we
|
|
||||||
// have not seen a similar EConcatMarked.
|
|
||||||
for (unbinop::const_iterator i = elist.begin();
|
|
||||||
i != elist.end(); ++i)
|
|
||||||
if (empairs.find(std::make_pair((*i)->first(),
|
|
||||||
(*i)->second()))
|
|
||||||
== empairs.end())
|
|
||||||
res->push_back((*i)->clone());
|
|
||||||
// Keep only the non-marked NegClosure for which we
|
|
||||||
// have not seen a similar NegClosureMarked.
|
|
||||||
for (ununop::const_iterator i = nlist.begin();
|
|
||||||
i != nlist.end(); ++i)
|
|
||||||
if (nmset.find((*i)->child()) == nmset.end())
|
|
||||||
res->push_back((*i)->clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const binop* bo)
|
|
||||||
{
|
|
||||||
result_ = bo->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
recurse(const formula* f)
|
|
||||||
{
|
|
||||||
return tools_->simplify_mark(f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class mark_visitor : public visitor
|
|
||||||
{
|
|
||||||
const formula* result_;
|
|
||||||
mark_tools* tools_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
mark_visitor(mark_tools* t)
|
|
||||||
: tools_(t)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~mark_visitor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
result()
|
|
||||||
{
|
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const atomic_prop* ap)
|
|
||||||
{
|
|
||||||
result_ = ap->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const constant* c)
|
|
||||||
{
|
|
||||||
result_ = c->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const bunop* bo)
|
|
||||||
{
|
|
||||||
result_ = bo->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const unop* uo)
|
|
||||||
{
|
|
||||||
switch (uo->op())
|
|
||||||
{
|
|
||||||
case unop::Not:
|
|
||||||
case unop::X:
|
|
||||||
case unop::F:
|
|
||||||
case unop::G:
|
|
||||||
case unop::Closure:
|
|
||||||
case unop::NegClosureMarked:
|
|
||||||
result_ = uo->clone();
|
|
||||||
return;
|
|
||||||
case unop::NegClosure:
|
|
||||||
result_ = unop::instance(unop::NegClosureMarked,
|
|
||||||
uo->child()->clone());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
unsigned mos = mo->size();
|
|
||||||
for (unsigned i = 0; i < mos; ++i)
|
|
||||||
res->push_back(recurse(mo->nth(i)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const binop* bo)
|
|
||||||
{
|
|
||||||
switch (bo->op())
|
|
||||||
{
|
|
||||||
case binop::Xor:
|
|
||||||
case binop::Implies:
|
|
||||||
case binop::Equiv:
|
|
||||||
SPOT_UNIMPLEMENTED();
|
|
||||||
case binop::U:
|
|
||||||
case binop::W:
|
|
||||||
case binop::M:
|
|
||||||
case binop::R:
|
|
||||||
case binop::UConcat:
|
|
||||||
case binop::EConcatMarked:
|
|
||||||
result_ = bo->clone();
|
|
||||||
return;
|
|
||||||
case binop::EConcat:
|
|
||||||
{
|
|
||||||
const formula* f1 = bo->first()->clone();
|
|
||||||
const formula* f2 = bo->second()->clone();
|
|
||||||
result_ = binop::instance(binop::EConcatMarked, f1, f2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
recurse(const formula* f)
|
|
||||||
{
|
|
||||||
return tools_->mark_concat_ops(f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mark_tools::mark_tools()
|
|
||||||
: simpvisitor_(new simplify_mark_visitor(this)),
|
|
||||||
markvisitor_(new mark_visitor(this))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
mark_tools::~mark_tools()
|
|
||||||
{
|
|
||||||
delete simpvisitor_;
|
|
||||||
delete markvisitor_;
|
|
||||||
{
|
|
||||||
f2f_map::iterator i = simpmark_.begin();
|
|
||||||
f2f_map::iterator end = simpmark_.end();
|
|
||||||
while (i != end)
|
|
||||||
{
|
|
||||||
f2f_map::iterator old = i++;
|
|
||||||
old->second->destroy();
|
|
||||||
old->first->destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
f2f_map::iterator i = markops_.begin();
|
|
||||||
f2f_map::iterator end = markops_.end();
|
|
||||||
while (i != end)
|
|
||||||
{
|
|
||||||
f2f_map::iterator old = i++;
|
|
||||||
old->second->destroy();
|
|
||||||
old->first->destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
mark_tools::mark_concat_ops(const formula* f)
|
|
||||||
{
|
{
|
||||||
f2f_map::iterator i = markops_.find(f);
|
f2f_map::iterator i = markops_.find(f);
|
||||||
if (i != markops_.end())
|
if (i != markops_.end())
|
||||||
return i->second->clone();
|
return i->second;
|
||||||
|
|
||||||
f->accept(*markvisitor_);
|
ltl::formula res;
|
||||||
|
switch (f.kind())
|
||||||
|
{
|
||||||
|
case op::False:
|
||||||
|
case op::True:
|
||||||
|
case op::EmptyWord:
|
||||||
|
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 = ltl::formula::NegClosureMarked(f.nth(0));
|
||||||
|
break;
|
||||||
|
case op::EConcat:
|
||||||
|
res = ltl::formula::EConcatMarked(f.nth(0), f.nth(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();
|
||||||
|
}
|
||||||
|
|
||||||
const formula* r = down_cast<mark_visitor*>(markvisitor_)->result();
|
markops_[f] = res;
|
||||||
markops_[f->clone()] = r->clone();
|
return res;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
mark_tools::simplify_mark(const formula* f)
|
mark_tools::simplify_mark(formula f)
|
||||||
{
|
{
|
||||||
if (!f->is_marked())
|
if (!f.is_marked())
|
||||||
return f->clone();
|
return f;
|
||||||
|
|
||||||
f2f_map::iterator i = simpmark_.find(f);
|
f2f_map::iterator i = simpmark_.find(f);
|
||||||
if (i != simpmark_.end())
|
if (i != simpmark_.end())
|
||||||
return i->second->clone();
|
return i->second;
|
||||||
|
|
||||||
f->accept(*simpvisitor_);
|
auto recurse = [this](formula f)
|
||||||
|
{
|
||||||
|
return this->simplify_mark(f);
|
||||||
|
};
|
||||||
|
|
||||||
const formula* r =
|
ltl::formula res;
|
||||||
down_cast<simplify_mark_visitor*>(simpvisitor_)->result();
|
switch (f.kind())
|
||||||
simpmark_[f->clone()] = r->clone();
|
{
|
||||||
return r;
|
case op::False:
|
||||||
|
case op::True:
|
||||||
|
case op::EmptyWord:
|
||||||
|
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.nth(0), c.nth(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.nth(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.nth(0), e.nth(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.nth(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2010, 2011, 2012, 2013 Laboratoire de Recherche et
|
// Copyright (C) 2010, 2011, 2012, 2013, 2015 Laboratoire de Recherche
|
||||||
// Développement de l'Epita (LRDE).
|
// et Développement de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -20,34 +20,27 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ltlast/formula.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "ltlast/visitor.hh"
|
|
||||||
#include "misc/hash.hh"
|
#include "misc/hash.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
class mark_tools
|
class mark_tools final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \ingroup ltl_rewriting
|
/// \ingroup ltl_rewriting
|
||||||
/// \brief Mark operators NegClosure and EConcat.
|
/// \brief Mark operators NegClosure and EConcat.
|
||||||
///
|
///
|
||||||
/// \param f The formula to rewrite.
|
/// \param f The formula to rewrite.
|
||||||
const formula* mark_concat_ops(const formula* f);
|
formula mark_concat_ops(formula f);
|
||||||
|
|
||||||
const formula* simplify_mark(const formula* f);
|
formula simplify_mark(formula f);
|
||||||
|
|
||||||
mark_tools();
|
|
||||||
~mark_tools();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::unordered_map<const formula*, const formula*,
|
typedef std::unordered_map<formula, formula> f2f_map;
|
||||||
ptr_hash<formula>> f2f_map;
|
|
||||||
f2f_map simpmark_;
|
f2f_map simpmark_;
|
||||||
f2f_map markops_;
|
f2f_map markops_;
|
||||||
visitor* simpvisitor_;
|
|
||||||
visitor* markvisitor_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,28 +17,18 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "ltlvisit/apcollect.hh"
|
#include "ltlvisit/apcollect.hh"
|
||||||
#include "ltlvisit/clone.hh"
|
|
||||||
#include "ltlvisit/mutation.hh"
|
#include "ltlvisit/mutation.hh"
|
||||||
#include "ltlvisit/length.hh"
|
#include "ltlvisit/length.hh"
|
||||||
#include "misc/hash.hh"
|
|
||||||
|
|
||||||
#define Implies_(x, y) \
|
#define And_(x, y) formula::And({(x), (y)})
|
||||||
spot::ltl::binop::instance(spot::ltl::binop::Implies, (x), (y))
|
#define AndRat_(x, y) formula::AndRat({(x), (y)})
|
||||||
#define And_(x, y) \
|
#define AndNLM_(x) formula::AndNLM(x)
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::And, (x), (y))
|
#define Concat_(x, y) formula::Concat({(x), (y)})
|
||||||
#define AndRat_(x, y) \
|
#define Not_(x) formula::Not(x)
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::AndRat, (x), (y))
|
|
||||||
#define AndNLM_(x) \
|
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::AndNLM, (x))
|
|
||||||
#define Concat_(x, y) \
|
|
||||||
spot::ltl::multop::instance(spot::ltl::multop::Concat, (x), (y))
|
|
||||||
#define Not_(x) \
|
|
||||||
spot::ltl::unop::instance(spot::ltl::unop::Not, (x))
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -46,355 +36,307 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class replace_visitor final : public clone_visitor
|
formula substitute_ap(formula f, formula ap_src, formula ap_dst)
|
||||||
{
|
{
|
||||||
public:
|
return f.map([&](formula f)
|
||||||
void visit(const atomic_prop* ap)
|
{
|
||||||
{
|
if (f == ap_src)
|
||||||
if (ap == ap1_)
|
return ap_dst;
|
||||||
result_ = ap2_->clone();
|
else
|
||||||
else
|
return substitute_ap(f, ap_src, ap_dst);
|
||||||
result_ = ap->clone();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
typedef std::vector<formula> vec;
|
||||||
replace(const formula* f,
|
class mutator final
|
||||||
const atomic_prop* ap1,
|
|
||||||
const atomic_prop* ap2)
|
|
||||||
{
|
|
||||||
ap1_ = ap1;
|
|
||||||
ap2_ = ap2;
|
|
||||||
return recurse(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const atomic_prop* ap1_;
|
|
||||||
const atomic_prop* ap2_;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector<const formula*> vec;
|
|
||||||
class mutation_visitor final : public clone_visitor
|
|
||||||
{
|
{
|
||||||
|
int mutation_counter_ = 0;
|
||||||
|
formula f_;
|
||||||
|
unsigned opts_;
|
||||||
public:
|
public:
|
||||||
mutation_visitor(const formula* f, unsigned opts) : f_(f), opts_(opts)
|
mutator(formula f, unsigned opts) : f_(f), opts_(opts)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const atomic_prop* ap)
|
formula mutate(formula f)
|
||||||
{
|
{
|
||||||
result_ = 0;
|
auto recurse = [this](formula f)
|
||||||
if (opts_ & Mut_Ap2Const)
|
|
||||||
{
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = constant::true_instance();
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = constant::false_instance();
|
|
||||||
}
|
|
||||||
if (!result_)
|
|
||||||
result_ = ap->clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const unop* uo)
|
|
||||||
{
|
|
||||||
result_ = 0;
|
|
||||||
if (opts_ & Mut_Remove_Ops)
|
|
||||||
{
|
|
||||||
if ((uo->op() == unop::G
|
|
||||||
|| uo->op() == unop::F
|
|
||||||
|| uo->op() == unop::X
|
|
||||||
|| uo->op() == unop::Not)
|
|
||||||
&& mutation_counter_-- == 0)
|
|
||||||
result_ = uo->child()->clone();
|
|
||||||
}
|
|
||||||
if (!result_)
|
|
||||||
{
|
|
||||||
if (mutation_counter_ < 0)
|
|
||||||
result_ = uo->clone();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result_ = unop::instance(uo->op(), recurse(uo->child()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const binop* bo)
|
|
||||||
{
|
|
||||||
const formula* first = bo->first();
|
|
||||||
const formula* second = bo->second();
|
|
||||||
result_ = 0;
|
|
||||||
auto op = bo->op();
|
|
||||||
bool left_is_sere = op == binop::EConcat
|
|
||||||
|| op == binop::EConcatMarked
|
|
||||||
|| op == binop::UConcat;
|
|
||||||
|
|
||||||
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
|
|
||||||
{
|
{
|
||||||
if (!left_is_sere)
|
return this->mutate(f);
|
||||||
result_ = first->clone();
|
};
|
||||||
else if (op == binop::UConcat)
|
|
||||||
result_ = unop::instance(unop::NegClosure, first->clone());
|
|
||||||
else // EConcat or EConcatMarked
|
|
||||||
result_ = unop::instance(unop::Closure, first->clone());
|
|
||||||
}
|
|
||||||
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
|
|
||||||
result_ = second->clone();
|
|
||||||
if (opts_ & Mut_Rewrite_Ops)
|
|
||||||
{
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case binop::U:
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = binop::instance(binop::W, first->clone(),
|
|
||||||
second->clone());
|
|
||||||
break;
|
|
||||||
case binop::M:
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = binop::instance(binop::R, first->clone(),
|
|
||||||
second->clone());
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = binop::instance(binop::U, second->clone(),
|
|
||||||
first->clone());
|
|
||||||
break;
|
|
||||||
case binop::R:
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = binop::instance(binop::W, second->clone(),
|
|
||||||
first->clone());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opts_ & Mut_Split_Ops)
|
|
||||||
{
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case binop::Equiv:
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = Implies_(first->clone(), second->clone());
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = Implies_(second->clone(), first->clone());
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = And_(first->clone(), second->clone());
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
{
|
|
||||||
// Negate the two argument sequentially (in this
|
|
||||||
// case right before left, otherwise different
|
|
||||||
// compilers will make different choices.
|
|
||||||
auto right = Not_(second->clone());
|
|
||||||
result_ = And_(Not_(first->clone()), right);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case binop::Xor:
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = And_(first->clone(), Not_(second->clone()));
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = And_(Not_(first->clone()), second->clone());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!result_)
|
|
||||||
{
|
|
||||||
if (mutation_counter_ < 0)
|
|
||||||
{
|
|
||||||
result_ = bo->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For historical reasons, we evaluate the right
|
|
||||||
// side before the left one. The other order would
|
|
||||||
// be OK as well but require changing the test
|
|
||||||
// suite. Evaluating both sides during the call to
|
|
||||||
// instance() is incorrect, because each compiler
|
|
||||||
// could decide of a different order.
|
|
||||||
auto right = recurse(second);
|
|
||||||
result_ = binop::instance(op, recurse(first), right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const bunop* bu)
|
switch (f.kind())
|
||||||
{
|
{
|
||||||
const formula* c = bu->child()->clone();
|
case op::False:
|
||||||
result_ = nullptr;
|
case op::True:
|
||||||
auto op = bu->op();
|
case op::EmptyWord:
|
||||||
|
return f;
|
||||||
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
|
case op::AP:
|
||||||
result_ = c;
|
if (opts_ & Mut_Ap2Const)
|
||||||
if (opts_ & Mut_Simplify_Bounds)
|
|
||||||
{
|
|
||||||
auto min = bu->min();
|
|
||||||
auto max = bu->max();
|
|
||||||
if (min > 0)
|
|
||||||
{
|
{
|
||||||
if (mutation_counter_-- == 0)
|
if (mutation_counter_-- == 0)
|
||||||
result_ = bunop::instance(op, c, min - 1, max);
|
return formula::tt();
|
||||||
if (mutation_counter_-- == 0)
|
if (mutation_counter_-- == 0)
|
||||||
result_ = bunop::instance(op, c, 0, max);
|
return formula::ff();
|
||||||
}
|
|
||||||
if (max != bunop::unbounded)
|
|
||||||
{
|
|
||||||
if (max > min && mutation_counter_-- == 0)
|
|
||||||
result_ = bunop::instance(op, c, min, max - 1);
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = bunop::instance(op, c, min, bunop::unbounded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!result_)
|
|
||||||
{
|
|
||||||
c->destroy();
|
|
||||||
if (mutation_counter_ < 0)
|
|
||||||
result_ = bu->clone();
|
|
||||||
else
|
|
||||||
result_ = bunop::instance(op, recurse(c), bu->min(), bu->max());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const multop* mo)
|
|
||||||
{
|
|
||||||
int mos = mo->size();
|
|
||||||
int i;
|
|
||||||
result_ = 0;
|
|
||||||
|
|
||||||
if (opts_ & Mut_Remove_Multop_Operands)
|
|
||||||
{
|
|
||||||
for (i = 0; i < mos; ++i)
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
result_ = mo->all_but(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts_ & Mut_Split_Ops && mo->op() == multop::AndNLM)
|
|
||||||
{
|
|
||||||
if (mutation_counter_ >= 0 && mutation_counter_ < 2 * (mos - 1))
|
|
||||||
{
|
|
||||||
vec* v1 = new vec();
|
|
||||||
vec* v2 = new vec();
|
|
||||||
v1->push_back(mo->nth(0)->clone());
|
|
||||||
bool reverse = false;
|
|
||||||
i = 1;
|
|
||||||
while (i < mos)
|
|
||||||
{
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
break;
|
|
||||||
if (mutation_counter_-- == 0)
|
|
||||||
{
|
|
||||||
reverse = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
v1->push_back(mo->nth(i++)->clone());
|
|
||||||
}
|
|
||||||
for (; i < mos; ++i)
|
|
||||||
v2->push_back(mo->nth(i)->clone());
|
|
||||||
const formula* tstar =
|
|
||||||
bunop::instance(bunop::Star, constant::true_instance(),
|
|
||||||
0,
|
|
||||||
bunop::unbounded);
|
|
||||||
const formula* first = AndNLM_(v1);
|
|
||||||
const formula* second = AndNLM_(v2);
|
|
||||||
if (!reverse)
|
|
||||||
result_ = AndRat_(Concat_(first, tstar), second);
|
|
||||||
else
|
|
||||||
result_ = AndRat_(Concat_(second, tstar), first);
|
|
||||||
}
|
}
|
||||||
|
return f;
|
||||||
|
case op::Not:
|
||||||
|
case op::X:
|
||||||
|
case op::F:
|
||||||
|
case op::G:
|
||||||
|
if ((opts_ & Mut_Remove_Ops)
|
||||||
|
&& mutation_counter_-- == 0)
|
||||||
|
return f.nth(0);
|
||||||
|
// fall through
|
||||||
|
case op::Closure:
|
||||||
|
case op::NegClosure:
|
||||||
|
case op::NegClosureMarked:
|
||||||
|
if (mutation_counter_ < 0)
|
||||||
|
return f;
|
||||||
else
|
else
|
||||||
mutation_counter_ -= 2 * (mos - 1);
|
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 (!result_)
|
if (opts_ & Mut_Split_Ops && f.is(op::AndNLM))
|
||||||
{
|
{
|
||||||
if (mutation_counter_ < 0)
|
if (mutation_counter_ >= 0
|
||||||
result_ = mo->clone();
|
&& mutation_counter_ < 2 * (mos - 1))
|
||||||
else
|
{
|
||||||
{
|
vec v1;
|
||||||
vec* v = new vec();
|
vec v2;
|
||||||
for (i = 0; i < mos; ++i)
|
v1.push_back(f.nth(0));
|
||||||
v->push_back(recurse(mo->nth(i)));
|
bool reverse = false;
|
||||||
result_ = multop::instance(mo->op(), v);
|
int i = 1;
|
||||||
}
|
while (i < mos)
|
||||||
}
|
{
|
||||||
|
if (mutation_counter_-- == 0)
|
||||||
|
break;
|
||||||
|
if (mutation_counter_-- == 0)
|
||||||
|
{
|
||||||
|
reverse = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v1.push_back(f.nth(i++));
|
||||||
|
}
|
||||||
|
for (; i < mos; ++i)
|
||||||
|
v2.push_back(f.nth(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.nth(0);
|
||||||
|
formula second = f.nth(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.nth(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();
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
recurse(const formula* f)
|
|
||||||
{
|
|
||||||
f->accept(*this);
|
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
get_mutation(int n)
|
get_mutation(int n)
|
||||||
{
|
{
|
||||||
mutation_counter_ = n;
|
mutation_counter_ = n;
|
||||||
const formula* mut = recurse(f_);
|
formula mut = mutate(f_);
|
||||||
if (mut == f_)
|
if (mut == f_)
|
||||||
{
|
return nullptr;
|
||||||
mut->destroy();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mut;
|
return mut;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
const formula* f_;
|
|
||||||
int mutation_counter_ = 0;
|
|
||||||
unsigned opts_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
formula_length_less_than(const formula* left, const formula* right)
|
formula_length_less_than(formula left, formula right)
|
||||||
{
|
{
|
||||||
assert(left);
|
assert(left != nullptr);
|
||||||
assert(right);
|
assert(right != nullptr);
|
||||||
if (left == right)
|
if (left == right)
|
||||||
return false;
|
return false;
|
||||||
return length(left) < length(right);
|
auto ll = length(left);
|
||||||
|
auto lr = length(right);
|
||||||
|
if (ll < lr)
|
||||||
|
return true;
|
||||||
|
if (ll > lr)
|
||||||
|
return false;
|
||||||
|
return left < right;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::set<const formula*, formula_ptr_less_than> fset_t;
|
typedef std::set<formula> fset_t;
|
||||||
|
|
||||||
void
|
void
|
||||||
single_mutation_rec(const formula* f, fset_t& mutations, unsigned opts,
|
single_mutation_rec(formula f, fset_t& mutations, unsigned opts,
|
||||||
unsigned& n, unsigned m)
|
unsigned& n, unsigned m)
|
||||||
{
|
{
|
||||||
if (m == 0)
|
if (m == 0)
|
||||||
{
|
{
|
||||||
if (mutations.insert(f).second)
|
if (mutations.insert(f).second)
|
||||||
{
|
--n;
|
||||||
f->clone();
|
|
||||||
--n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const formula* mut(nullptr);
|
formula mut;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
mutation_visitor mv(f, opts);
|
mutator mv(f, opts);
|
||||||
while (n > 0 && (mut = mv.get_mutation(i++)))
|
while (n > 0 && ((mut = mv.get_mutation(i++)) != nullptr))
|
||||||
{
|
single_mutation_rec(mut, mutations, opts, n, m - 1);
|
||||||
single_mutation_rec(mut, mutations, opts, n, m - 1);
|
|
||||||
mut->destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
replace_ap_rec(const formula* f, fset_t& mutations, unsigned opts,
|
replace_ap_rec(formula f, fset_t& mutations, unsigned opts,
|
||||||
unsigned& n, unsigned m)
|
unsigned& n, unsigned m)
|
||||||
{
|
{
|
||||||
if (m == 0)
|
if (m == 0)
|
||||||
{
|
{
|
||||||
if (mutations.insert(f).second)
|
if (mutations.insert(f).second)
|
||||||
{
|
--n;
|
||||||
f->clone();
|
|
||||||
--n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
replace_visitor rv;
|
|
||||||
auto aps =
|
auto aps =
|
||||||
std::unique_ptr<atomic_prop_set>(atomic_prop_collect(f));
|
std::unique_ptr<atomic_prop_set>(atomic_prop_collect(f));
|
||||||
for (auto ap1: *aps)
|
for (auto ap1: *aps)
|
||||||
|
|
@ -402,9 +344,8 @@ namespace spot
|
||||||
{
|
{
|
||||||
if (ap1 == ap2)
|
if (ap1 == ap2)
|
||||||
continue;
|
continue;
|
||||||
auto mut = rv.replace(f, ap1, ap2);
|
auto mut = substitute_ap(f, ap1, ap2);
|
||||||
replace_ap_rec(mut, mutations, opts, n, m - 1);
|
replace_ap_rec(mut, mutations, opts, n, m - 1);
|
||||||
mut->destroy();
|
|
||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -412,8 +353,8 @@ namespace spot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const formula*>
|
std::vector<formula>
|
||||||
mutate(const formula* f, unsigned opts, unsigned max_output,
|
mutate(formula f, unsigned opts, unsigned max_output,
|
||||||
unsigned mutation_count, bool sort)
|
unsigned mutation_count, bool sort)
|
||||||
{
|
{
|
||||||
fset_t mutations;
|
fset_t mutations;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2014 Laboratoire de Recherche et Développement de
|
// Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement
|
||||||
// l'Epita (LRDE).
|
// de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ltlast/formula.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
|
|
@ -40,10 +39,10 @@ namespace spot
|
||||||
};
|
};
|
||||||
|
|
||||||
SPOT_API
|
SPOT_API
|
||||||
std::vector<const formula*> mutate(const 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013 Laboratoire de Recherche
|
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2015 Laboratoire de
|
||||||
// et Développement de l'Epita (LRDE).
|
// Recherche et Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
// et Marie Curie.
|
// et Marie Curie.
|
||||||
|
|
@ -27,11 +27,11 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
const formula*
|
formula
|
||||||
negative_normal_form(const formula* f, bool negated)
|
negative_normal_form(formula f, bool negated)
|
||||||
{
|
{
|
||||||
if (!negated && f->is_in_nenoform())
|
if (!negated && f.is_in_nenoform())
|
||||||
return f->clone();
|
return f;
|
||||||
|
|
||||||
ltl_simplifier s;
|
ltl_simplifier s;
|
||||||
return s.negative_normal_form(f, negated);
|
return s.negative_normal_form(f, negated);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2011, 2012, 2013 Laboratoire de Recherche et
|
// Copyright (C) 2011, 2012, 2013, 2015 Laboratoire de Recherche et
|
||||||
// Développement de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
|
@ -39,11 +39,11 @@ namespace spot
|
||||||
/// \c !f
|
/// \c !f
|
||||||
///
|
///
|
||||||
/// Note that this will not remove abbreviated operators. If you
|
/// Note that this will not remove abbreviated operators. If you
|
||||||
/// want to remove abbreviations, call spot::ltl::unabbreviate_logic
|
/// want to remove abbreviations, call spot::ltl::unabbreviate
|
||||||
/// or spot::ltl::unabbreviate_ltl first. (Calling these functions
|
/// first. (Calling this function after
|
||||||
/// after spot::ltl::negative_normal_form would likely produce a
|
/// spot::ltl::negative_normal_form would likely produce a formula
|
||||||
/// formula which is not in negative normal form.)
|
/// which is not in negative normal form.)
|
||||||
SPOT_API const formula*
|
SPOT_API formula
|
||||||
negative_normal_form(const formula* f, bool negated = false);
|
negative_normal_form(formula f, bool negated = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2011, 2012, 2014 Laboratoire de Recherche
|
|
||||||
// et Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "ltlvisit/postfix.hh"
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
postfix_visitor::postfix_visitor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
postfix_visitor::~postfix_visitor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::visit(const atomic_prop* ap)
|
|
||||||
{
|
|
||||||
doit(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::visit(const unop* uo)
|
|
||||||
{
|
|
||||||
uo->child()->accept(*this);
|
|
||||||
doit(uo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::visit(const binop* bo)
|
|
||||||
{
|
|
||||||
bo->first()->accept(*this);
|
|
||||||
bo->second()->accept(*this);
|
|
||||||
doit(bo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::visit(const multop* mo)
|
|
||||||
{
|
|
||||||
unsigned s = mo->size();
|
|
||||||
for (unsigned i = 0; i < s; ++i)
|
|
||||||
mo->nth(i)->accept(*this);
|
|
||||||
doit(mo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::visit(const bunop* so)
|
|
||||||
{
|
|
||||||
so->child()->accept(*this);
|
|
||||||
doit(so);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::visit(const constant* c)
|
|
||||||
{
|
|
||||||
doit(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::doit(const atomic_prop* ap)
|
|
||||||
{
|
|
||||||
doit_default(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::doit(const unop* uo)
|
|
||||||
{
|
|
||||||
doit_default(uo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::doit(const binop* bo)
|
|
||||||
{
|
|
||||||
doit_default(bo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::doit(const multop* mo)
|
|
||||||
{
|
|
||||||
doit_default(mo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::doit(const bunop* so)
|
|
||||||
{
|
|
||||||
doit_default(so);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::doit(const constant* c)
|
|
||||||
{
|
|
||||||
doit_default(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
postfix_visitor::doit_default(const formula* f)
|
|
||||||
{
|
|
||||||
(void)f;
|
|
||||||
// Dummy implementation that does nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita (LRDE).
|
|
||||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
||||||
// et Marie Curie.
|
|
||||||
//
|
|
||||||
// This file is part of Spot, a model checking library.
|
|
||||||
//
|
|
||||||
// Spot is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
// License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ltlast/formula.hh"
|
|
||||||
#include "ltlast/visitor.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace ltl
|
|
||||||
{
|
|
||||||
/// \ingroup ltl_visitor
|
|
||||||
/// \brief Apply an algorithm on each node of an AST,
|
|
||||||
/// during a postfix traversal.
|
|
||||||
///
|
|
||||||
/// Override one or more of the postifix_visitor::doit methods
|
|
||||||
/// with the algorithm to apply.
|
|
||||||
class SPOT_API postfix_visitor : public visitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
postfix_visitor();
|
|
||||||
virtual ~postfix_visitor();
|
|
||||||
|
|
||||||
void visit(const atomic_prop* ap);
|
|
||||||
void visit(const unop* uo);
|
|
||||||
void visit(const binop* bo);
|
|
||||||
void visit(const multop* mo);
|
|
||||||
void visit(const constant* c);
|
|
||||||
void visit(const bunop* c);
|
|
||||||
|
|
||||||
virtual void doit(const atomic_prop* ap);
|
|
||||||
virtual void doit(const unop* uo);
|
|
||||||
virtual void doit(const binop* bo);
|
|
||||||
virtual void doit(const multop* mo);
|
|
||||||
virtual void doit(const constant* c);
|
|
||||||
virtual void doit(const bunop* c);
|
|
||||||
virtual void doit_default(const formula* f);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -38,14 +38,14 @@ namespace spot
|
||||||
/// \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, const 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(const 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.
|
||||||
|
|
@ -53,7 +53,7 @@ namespace spot
|
||||||
/// \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, const formula* f,
|
print_utf8_psl(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 Convert a PSL formula into a utf-8 string which is parsable
|
||||||
|
|
@ -61,7 +61,7 @@ namespace spot
|
||||||
/// \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_utf8_psl(const formula* f, bool full_parent = false);
|
str_utf8_psl(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a SERE formula as a string which is parsable.
|
/// \brief Output a SERE formula as a string which is parsable.
|
||||||
/// \param f The formula to translate.
|
/// \param f The formula to translate.
|
||||||
|
|
@ -69,14 +69,14 @@ namespace spot
|
||||||
/// \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_sere(std::ostream& os, const formula* f, bool full_parent = false);
|
print_sere(std::ostream& os, formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Convert a SERE formula into a string which is parsable
|
/// \brief Convert a SERE 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_sere(const formula* f, bool full_parent = false);
|
str_sere(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a SERE formula as a utf-8 string which is parsable.
|
/// \brief Output a SERE formula as a utf-8 string which is parsable.
|
||||||
/// \param os The stream where it should be output.
|
/// \param os The stream where it should be output.
|
||||||
|
|
@ -84,7 +84,7 @@ namespace spot
|
||||||
/// \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_sere(std::ostream& os, const formula* f,
|
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 Convert a SERE formula into a string which is parsable
|
||||||
|
|
@ -92,7 +92,7 @@ namespace spot
|
||||||
/// \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_utf8_sere(const formula* f, bool full_parent = false);
|
str_utf8_sere(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output an LTL formula as a string parsable by Spin.
|
/// \brief Output an LTL formula as a string parsable by Spin.
|
||||||
/// \param os The stream where it should be output.
|
/// \param os The stream where it should be output.
|
||||||
|
|
@ -100,7 +100,7 @@ namespace spot
|
||||||
/// \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_spin_ltl(std::ostream& os, const formula* f,
|
print_spin_ltl(std::ostream& os, formula f,
|
||||||
bool full_parent = false);
|
bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Convert an LTL formula into a string parsable by Spin.
|
/// \brief Convert an LTL formula into a string parsable by Spin.
|
||||||
|
|
@ -108,18 +108,18 @@ namespace spot
|
||||||
/// \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_spin_ltl(const formula* f, bool full_parent = false);
|
str_spin_ltl(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output an LTL formula as a string parsable by Wring.
|
/// \brief Output an LTL formula as a string parsable by Wring.
|
||||||
/// \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.
|
||||||
SPOT_API std::ostream&
|
SPOT_API std::ostream&
|
||||||
print_wring_ltl(std::ostream& os, const formula* f);
|
print_wring_ltl(std::ostream& os, formula f);
|
||||||
|
|
||||||
/// \brief Convert a formula into a string parsable by Wring
|
/// \brief Convert a formula into a string parsable by Wring
|
||||||
/// \param f The formula to translate.
|
/// \param f The formula to translate.
|
||||||
SPOT_API std::string
|
SPOT_API std::string
|
||||||
str_wring_ltl(const formula* f);
|
str_wring_ltl(formula f);
|
||||||
|
|
||||||
/// \brief Output a PSL formula as a LaTeX string.
|
/// \brief Output a PSL formula as a LaTeX string.
|
||||||
/// \param os The stream where it should be output.
|
/// \param os The stream where it should be output.
|
||||||
|
|
@ -127,7 +127,7 @@ namespace spot
|
||||||
/// \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_latex_psl(std::ostream& os, const formula* f,
|
print_latex_psl(std::ostream& os, formula f,
|
||||||
bool full_parent = false);
|
bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a formula as a LaTeX string which is parsable.
|
/// \brief Output a formula as a LaTeX string which is parsable.
|
||||||
|
|
@ -136,7 +136,7 @@ namespace spot
|
||||||
/// \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_latex_psl(const formula* f, bool full_parent = false);
|
str_latex_psl(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a SERE formula as a LaTeX string.
|
/// \brief Output a SERE formula as a LaTeX string.
|
||||||
/// \param os The stream where it should be output.
|
/// \param os The stream where it should be output.
|
||||||
|
|
@ -144,7 +144,7 @@ namespace spot
|
||||||
/// \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_latex_sere(std::ostream& os, const formula* f,
|
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 LaTeX string which is parsable.
|
||||||
|
|
@ -153,7 +153,7 @@ namespace spot
|
||||||
/// \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_latex_sere(const formula* f, bool full_parent = false);
|
str_latex_sere(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a PSL formula as a self-contained LaTeX string.
|
/// \brief Output a PSL formula as a self-contained LaTeX string.
|
||||||
///
|
///
|
||||||
|
|
@ -163,7 +163,7 @@ namespace spot
|
||||||
/// \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_sclatex_psl(std::ostream& os, const formula* f,
|
print_sclatex_psl(std::ostream& os, formula f,
|
||||||
bool full_parent = false);
|
bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a PSL formula as a self-contained LaTeX string.
|
/// \brief Output a PSL formula as a self-contained LaTeX string.
|
||||||
|
|
@ -173,7 +173,7 @@ namespace spot
|
||||||
/// \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_sclatex_psl(const formula* f, bool full_parent = false);
|
str_sclatex_psl(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a SERE formula as a self-contained LaTeX string.
|
/// \brief Output a SERE formula as a self-contained LaTeX string.
|
||||||
///
|
///
|
||||||
|
|
@ -183,7 +183,7 @@ namespace spot
|
||||||
/// \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_sclatex_sere(std::ostream& os, const formula* f,
|
print_sclatex_sere(std::ostream& os, formula f,
|
||||||
bool full_parent = false);
|
bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output a SERE formula as a self-contained LaTeX string.
|
/// \brief Output a SERE formula as a self-contained LaTeX string.
|
||||||
|
|
@ -193,7 +193,7 @@ namespace spot
|
||||||
/// \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_sclatex_sere(const formula* f, bool full_parent = false);
|
str_sclatex_sere(formula f, bool full_parent = false);
|
||||||
|
|
||||||
/// \brief Output an LTL formula as a string in LBT's format.
|
/// \brief Output an LTL formula as a string in LBT's format.
|
||||||
///
|
///
|
||||||
|
|
@ -206,7 +206,7 @@ namespace spot
|
||||||
/// \param f The formula to translate.
|
/// \param f The formula to translate.
|
||||||
/// \param os The stream where it should be output.
|
/// \param os The stream where it should be output.
|
||||||
SPOT_API std::ostream&
|
SPOT_API std::ostream&
|
||||||
print_lbt_ltl(std::ostream& os, const formula* f);
|
print_lbt_ltl(std::ostream& os, formula f);
|
||||||
|
|
||||||
/// \brief Output an LTL formula as a string in LBT's format.
|
/// \brief Output an LTL formula as a string in LBT's format.
|
||||||
///
|
///
|
||||||
|
|
@ -218,7 +218,7 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// \param f The formula to translate.
|
/// \param f The formula to translate.
|
||||||
SPOT_API std::string
|
SPOT_API std::string
|
||||||
str_lbt_ltl(const formula* f);
|
str_lbt_ltl(formula f);
|
||||||
/// @}
|
/// @}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "randomltl.hh"
|
#include "randomltl.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "misc/random.hh"
|
#include "misc/random.hh"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
@ -37,25 +36,41 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static const formula*
|
static formula
|
||||||
ap_builder(const random_formula* rl, int n)
|
ap_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n == 1);
|
assert(n == 1);
|
||||||
(void) n;
|
(void) n;
|
||||||
atomic_prop_set::const_iterator i = rl->ap()->begin();
|
atomic_prop_set::const_iterator i = rl->ap()->begin();
|
||||||
std::advance(i, mrand(rl->ap()->size()));
|
std::advance(i, mrand(rl->ap()->size()));
|
||||||
return (*i)->clone();
|
return *i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const formula*
|
static formula
|
||||||
true_builder(const random_formula*, int n)
|
true_builder(const random_formula*, int n)
|
||||||
{
|
{
|
||||||
assert(n == 1);
|
assert(n == 1);
|
||||||
(void) n;
|
(void) n;
|
||||||
return constant::true_instance();
|
return formula::tt();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const formula*
|
static formula
|
||||||
|
false_builder(const random_formula*, int n)
|
||||||
|
{
|
||||||
|
assert(n == 1);
|
||||||
|
(void) n;
|
||||||
|
return formula::ff();
|
||||||
|
}
|
||||||
|
|
||||||
|
static formula
|
||||||
|
eword_builder(const random_formula*, int n)
|
||||||
|
{
|
||||||
|
assert(n == 1);
|
||||||
|
(void) n;
|
||||||
|
return formula::eword();
|
||||||
|
}
|
||||||
|
|
||||||
|
static formula
|
||||||
boolform_builder(const random_formula* rl, int n)
|
boolform_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 1);
|
assert(n >= 1);
|
||||||
|
|
@ -63,40 +78,24 @@ namespace spot
|
||||||
return rs->rb.generate(n);
|
return rs->rb.generate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const formula*
|
template <op Op>
|
||||||
false_builder(const random_formula*, int n)
|
static formula
|
||||||
{
|
|
||||||
assert(n == 1);
|
|
||||||
(void) n;
|
|
||||||
return constant::false_instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const formula*
|
|
||||||
eword_builder(const random_formula*, int n)
|
|
||||||
{
|
|
||||||
assert(n == 1);
|
|
||||||
(void) n;
|
|
||||||
return constant::empty_word_instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <unop::type Op>
|
|
||||||
static const formula*
|
|
||||||
unop_builder(const random_formula* rl, int n)
|
unop_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 2);
|
assert(n >= 2);
|
||||||
return unop::instance(Op, rl->generate(n - 1));
|
return formula::unop(Op, rl->generate(n - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const formula*
|
static formula
|
||||||
closure_builder(const random_formula* rl, int n)
|
closure_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 2);
|
assert(n >= 2);
|
||||||
const random_psl* rp = static_cast<const random_psl*>(rl);
|
const random_psl* rp = static_cast<const random_psl*>(rl);
|
||||||
return unop::instance(unop::Closure, rp->rs.generate(n - 1));
|
return formula::Closure(rp->rs.generate(n - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <binop::type Op>
|
template <op Op>
|
||||||
static const formula*
|
static formula
|
||||||
binop_builder(const random_formula* rl, int n)
|
binop_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 3);
|
assert(n >= 3);
|
||||||
|
|
@ -109,11 +108,11 @@ namespace spot
|
||||||
// discovering that clang would perform the nested calls from
|
// discovering that clang would perform the nested calls from
|
||||||
// left to right.
|
// left to right.
|
||||||
auto right = rl->generate(n - l);
|
auto right = rl->generate(n - l);
|
||||||
return binop::instance(Op, rl->generate(l), right);
|
return formula::binop(Op, rl->generate(l), right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <binop::type Op>
|
template <op Op>
|
||||||
static const formula*
|
static formula
|
||||||
binop_SERELTL_builder(const random_formula* rl, int n)
|
binop_SERELTL_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 3);
|
assert(n >= 3);
|
||||||
|
|
@ -122,41 +121,41 @@ namespace spot
|
||||||
int l = rrand(1, n - 1);
|
int l = rrand(1, n - 1);
|
||||||
// See comment in binop_builder.
|
// See comment in binop_builder.
|
||||||
auto right = rl->generate(n - l);
|
auto right = rl->generate(n - l);
|
||||||
return binop::instance(Op, rp->rs.generate(l), right);
|
return formula::binop(Op, rp->rs.generate(l), right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bunop::type Op>
|
template <op Op>
|
||||||
static const formula*
|
static formula
|
||||||
bunop_unbounded_builder(const random_formula* rl, int n)
|
bunop_unbounded_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 2);
|
assert(n >= 2);
|
||||||
return bunop::instance(Op, rl->generate(n - 1));
|
return formula::bunop(Op, rl->generate(n - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bunop::type Op>
|
template <op Op>
|
||||||
static const formula*
|
static formula
|
||||||
bunop_bounded_builder(const random_formula* rl, int n)
|
bunop_bounded_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 2);
|
assert(n >= 2);
|
||||||
int min = rrand(0, 2);
|
int min = rrand(0, 2);
|
||||||
int max = rrand(min, 3);
|
int max = rrand(min, 3);
|
||||||
return bunop::instance(Op, rl->generate(n - 1), min, max);
|
return formula::bunop(Op, rl->generate(n - 1), min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bunop::type Op>
|
template <op Op>
|
||||||
static const formula*
|
static formula
|
||||||
bunop_bool_bounded_builder(const random_formula* rl, int n)
|
bunop_bool_bounded_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 2);
|
assert(n >= 2);
|
||||||
int min = rrand(0, 2);
|
int min = rrand(0, 2);
|
||||||
int max = rrand(min, 3);
|
int max = rrand(min, 3);
|
||||||
const random_sere* rp = static_cast<const random_sere*>(rl);
|
const random_sere* rp = static_cast<const random_sere*>(rl);
|
||||||
return bunop::instance(Op, rp->rb.generate(n - 1), min, max);
|
return formula::bunop(Op, rp->rb.generate(n - 1), min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <multop::type Op>
|
template <op Op>
|
||||||
static const formula*
|
static formula
|
||||||
multop_builder(const random_formula* rl, int n)
|
multop_builder(const random_formula* rl, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 3);
|
assert(n >= 3);
|
||||||
|
|
@ -164,7 +163,7 @@ namespace spot
|
||||||
int l = rrand(1, n - 1);
|
int l = rrand(1, n - 1);
|
||||||
// See comment in binop_builder.
|
// See comment in binop_builder.
|
||||||
auto right = rl->generate(n - l);
|
auto right = rl->generate(n - l);
|
||||||
return multop::instance(Op, rl->generate(l), right);
|
return formula::multop(Op, {rl->generate(l), right});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous
|
} // anonymous
|
||||||
|
|
@ -208,7 +207,7 @@ namespace spot
|
||||||
assert(total_2_and_more_ >= total_2_);
|
assert(total_2_and_more_ >= total_2_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
random_formula::generate(int n) const
|
random_formula::generate(int n) const
|
||||||
{
|
{
|
||||||
assert(n > 0);
|
assert(n > 0);
|
||||||
|
|
@ -319,15 +318,15 @@ namespace spot
|
||||||
proba_2_ = proba_ + 1;
|
proba_2_ = proba_ + 1;
|
||||||
proba_2_or_more_ = proba_ + 1;
|
proba_2_or_more_ = proba_ + 1;
|
||||||
proba_[1].setup("boolform", 1, boolform_builder);
|
proba_[1].setup("boolform", 1, boolform_builder);
|
||||||
proba_[2].setup("star", 2, bunop_unbounded_builder<bunop::Star>);
|
proba_[2].setup("star", 2, bunop_unbounded_builder<op::Star>);
|
||||||
proba_[3].setup("star_b", 2, bunop_bounded_builder<bunop::Star>);
|
proba_[3].setup("star_b", 2, bunop_bounded_builder<op::Star>);
|
||||||
proba_[4].setup("fstar", 2, bunop_unbounded_builder<bunop::FStar>);
|
proba_[4].setup("fstar", 2, bunop_unbounded_builder<op::FStar>);
|
||||||
proba_[5].setup("fstar_b", 2, bunop_bounded_builder<bunop::FStar>);
|
proba_[5].setup("fstar_b", 2, bunop_bounded_builder<op::FStar>);
|
||||||
proba_[6].setup("and", 3, multop_builder<multop::AndRat>);
|
proba_[6].setup("and", 3, multop_builder<op::AndRat>);
|
||||||
proba_[7].setup("andNLM", 3, multop_builder<multop::AndNLM>);
|
proba_[7].setup("andNLM", 3, multop_builder<op::AndNLM>);
|
||||||
proba_[8].setup("or", 3, multop_builder<multop::OrRat>);
|
proba_[8].setup("or", 3, multop_builder<op::OrRat>);
|
||||||
proba_[9].setup("concat", 3, multop_builder<multop::Concat>);
|
proba_[9].setup("concat", 3, multop_builder<op::Concat>);
|
||||||
proba_[10].setup("fusion", 3, multop_builder<multop::Fusion>);
|
proba_[10].setup("fusion", 3, multop_builder<op::Fusion>);
|
||||||
|
|
||||||
update_sums();
|
update_sums();
|
||||||
}
|
}
|
||||||
|
|
@ -341,12 +340,12 @@ namespace spot
|
||||||
proba_[1].setup("false", 1, false_builder);
|
proba_[1].setup("false", 1, false_builder);
|
||||||
proba_[2].setup("true", 1, true_builder);
|
proba_[2].setup("true", 1, true_builder);
|
||||||
proba_2_or_more_ = proba_2_ = proba_ + 3;
|
proba_2_or_more_ = proba_2_ = proba_ + 3;
|
||||||
proba_[3].setup("not", 2, unop_builder<unop::Not>);
|
proba_[3].setup("not", 2, unop_builder<op::Not>);
|
||||||
proba_[4].setup("equiv", 3, binop_builder<binop::Equiv>);
|
proba_[4].setup("equiv", 3, binop_builder<op::Equiv>);
|
||||||
proba_[5].setup("implies", 3, binop_builder<binop::Implies>);
|
proba_[5].setup("implies", 3, binop_builder<op::Implies>);
|
||||||
proba_[6].setup("xor", 3, binop_builder<binop::Xor>);
|
proba_[6].setup("xor", 3, binop_builder<op::Xor>);
|
||||||
proba_[7].setup("and", 3, multop_builder<multop::And>);
|
proba_[7].setup("and", 3, multop_builder<op::And>);
|
||||||
proba_[8].setup("or", 3, multop_builder<multop::Or>);
|
proba_[8].setup("or", 3, multop_builder<op::Or>);
|
||||||
|
|
||||||
update_sums();
|
update_sums();
|
||||||
}
|
}
|
||||||
|
|
@ -360,19 +359,19 @@ namespace spot
|
||||||
proba_[1].setup("false", 1, false_builder);
|
proba_[1].setup("false", 1, false_builder);
|
||||||
proba_[2].setup("true", 1, true_builder);
|
proba_[2].setup("true", 1, true_builder);
|
||||||
proba_2_or_more_ = proba_2_ = proba_ + 3;
|
proba_2_or_more_ = proba_2_ = proba_ + 3;
|
||||||
proba_[3].setup("not", 2, unop_builder<unop::Not>);
|
proba_[3].setup("not", 2, unop_builder<op::Not>);
|
||||||
proba_[4].setup("F", 2, unop_builder<unop::F>);
|
proba_[4].setup("F", 2, unop_builder<op::F>);
|
||||||
proba_[5].setup("G", 2, unop_builder<unop::G>);
|
proba_[5].setup("G", 2, unop_builder<op::G>);
|
||||||
proba_[6].setup("X", 2, unop_builder<unop::X>);
|
proba_[6].setup("X", 2, unop_builder<op::X>);
|
||||||
proba_[7].setup("equiv", 3, binop_builder<binop::Equiv>);
|
proba_[7].setup("equiv", 3, binop_builder<op::Equiv>);
|
||||||
proba_[8].setup("implies", 3, binop_builder<binop::Implies>);
|
proba_[8].setup("implies", 3, binop_builder<op::Implies>);
|
||||||
proba_[9].setup("xor", 3, binop_builder<binop::Xor>);
|
proba_[9].setup("xor", 3, binop_builder<op::Xor>);
|
||||||
proba_[10].setup("R", 3, binop_builder<binop::R>);
|
proba_[10].setup("R", 3, binop_builder<op::R>);
|
||||||
proba_[11].setup("U", 3, binop_builder<binop::U>);
|
proba_[11].setup("U", 3, binop_builder<op::U>);
|
||||||
proba_[12].setup("W", 3, binop_builder<binop::W>);
|
proba_[12].setup("W", 3, binop_builder<op::W>);
|
||||||
proba_[13].setup("M", 3, binop_builder<binop::M>);
|
proba_[13].setup("M", 3, binop_builder<op::M>);
|
||||||
proba_[14].setup("and", 3, multop_builder<multop::And>);
|
proba_[14].setup("and", 3, multop_builder<op::And>);
|
||||||
proba_[15].setup("or", 3, multop_builder<multop::Or>);
|
proba_[15].setup("or", 3, multop_builder<op::Or>);
|
||||||
}
|
}
|
||||||
|
|
||||||
random_ltl::random_ltl(const atomic_prop_set* ap)
|
random_ltl::random_ltl(const atomic_prop_set* ap)
|
||||||
|
|
@ -399,8 +398,8 @@ namespace spot
|
||||||
((proba_ + 16) - (proba_ + 7)) * sizeof(*proba_));
|
((proba_ + 16) - (proba_ + 7)) * sizeof(*proba_));
|
||||||
|
|
||||||
proba_[7].setup("Closure", 2, closure_builder);
|
proba_[7].setup("Closure", 2, closure_builder);
|
||||||
proba_[17].setup("EConcat", 3, binop_SERELTL_builder<binop::EConcat>);
|
proba_[17].setup("EConcat", 3, binop_SERELTL_builder<op::EConcat>);
|
||||||
proba_[18].setup("UConcat", 3, binop_SERELTL_builder<binop::UConcat>);
|
proba_[18].setup("UConcat", 3, binop_SERELTL_builder<op::UConcat>);
|
||||||
update_sums();
|
update_sums();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -490,16 +489,13 @@ namespace spot
|
||||||
randltlgenerator::~randltlgenerator()
|
randltlgenerator::~randltlgenerator()
|
||||||
{
|
{
|
||||||
delete rf_;
|
delete rf_;
|
||||||
// Cleanup the unicity table.
|
|
||||||
for (auto i: unique_set_)
|
|
||||||
i->destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* randltlgenerator::next()
|
formula randltlgenerator::next()
|
||||||
{
|
{
|
||||||
unsigned trials = MAX_TRIALS;
|
unsigned trials = MAX_TRIALS;
|
||||||
bool ignore;
|
bool ignore;
|
||||||
const formula* f = nullptr;
|
formula f = nullptr;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
ignore = false;
|
ignore = false;
|
||||||
|
|
@ -512,29 +508,14 @@ namespace spot
|
||||||
{
|
{
|
||||||
atomic_prop_set s = aprops_;
|
atomic_prop_set s = aprops_;
|
||||||
remove_some_props(s);
|
remove_some_props(s);
|
||||||
f = multop::instance(multop::And,
|
f = formula::And({f, GF_n()});
|
||||||
f, GF_n());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_simpl_level_)
|
if (opt_simpl_level_)
|
||||||
{
|
f = simpl_.simplify(f);
|
||||||
const spot::ltl::formula* tmp = simpl_.simplify(f);
|
|
||||||
f->destroy();
|
|
||||||
f = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt_unique_)
|
if (opt_unique_ && !unique_set_.insert(f).second)
|
||||||
{
|
ignore = true;
|
||||||
if (unique_set_.insert(f).second)
|
|
||||||
{
|
|
||||||
f->clone();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ignore = true;
|
|
||||||
f->destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ignore && --trials);
|
} while (ignore && --trials);
|
||||||
if (trials <= 0)
|
if (trials <= 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -557,17 +538,15 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
// GF(p_1) & GF(p_2) & ... & GF(p_n)
|
// GF(p_1) & GF(p_2) & ... & GF(p_n)
|
||||||
const formula*
|
formula
|
||||||
randltlgenerator::GF_n()
|
randltlgenerator::GF_n()
|
||||||
{
|
{
|
||||||
const formula* res = 0;
|
formula res = nullptr;
|
||||||
for (auto v: aprops_)
|
for (auto v: aprops_)
|
||||||
{
|
{
|
||||||
const formula* f =
|
formula f = formula::G(formula::F(v));
|
||||||
unop::instance(unop::F, v->clone());
|
|
||||||
f = unop::instance(unop::G, f);
|
|
||||||
if (res)
|
if (res)
|
||||||
res = multop::instance(multop::And, f, res);
|
res = formula::And({f, res});
|
||||||
else
|
else
|
||||||
res = f;
|
res = f;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ namespace spot
|
||||||
/// n, because some simple simplifications are performed by the
|
/// n, because some simple simplifications are performed by the
|
||||||
/// AST. (For instance the formula <code>a | a</code> is
|
/// AST. (For instance the formula <code>a | a</code> is
|
||||||
/// automatically reduced to <code>a</code> by spot::ltl::multop.)
|
/// automatically reduced to <code>a</code> by spot::ltl::multop.)
|
||||||
const formula* generate(int n) const;
|
formula generate(int n) const;
|
||||||
|
|
||||||
/// \brief Print the priorities of each operator, constants,
|
/// \brief Print the priorities of each operator, constants,
|
||||||
/// and atomic propositions.
|
/// and atomic propositions.
|
||||||
|
|
@ -93,7 +93,7 @@ namespace spot
|
||||||
const char* name;
|
const char* name;
|
||||||
int min_n;
|
int min_n;
|
||||||
double proba;
|
double proba;
|
||||||
typedef const formula* (*builder)(const random_formula* rl, int n);
|
typedef formula (*builder)(const random_formula* rl, int n);
|
||||||
builder build;
|
builder build;
|
||||||
void setup(const char* name, int min_n, builder build);
|
void setup(const char* name, int min_n, builder build);
|
||||||
};
|
};
|
||||||
|
|
@ -304,9 +304,7 @@ namespace spot
|
||||||
|
|
||||||
class SPOT_API randltlgenerator
|
class SPOT_API randltlgenerator
|
||||||
{
|
{
|
||||||
typedef
|
typedef std::unordered_set<formula> fset_t;
|
||||||
std::unordered_set<const spot::ltl::formula*,
|
|
||||||
const spot::ptr_hash<const spot::ltl::formula>> fset_t;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -322,7 +320,7 @@ namespace spot
|
||||||
|
|
||||||
~randltlgenerator();
|
~randltlgenerator();
|
||||||
|
|
||||||
const spot::ltl::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);
|
||||||
|
|
@ -331,7 +329,7 @@ namespace spot
|
||||||
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);
|
||||||
|
|
||||||
const formula* GF_n();
|
formula GF_n();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
fset_t unique_set_;
|
fset_t unique_set_;
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,7 @@
|
||||||
|
|
||||||
#include "relabel.hh"
|
#include "relabel.hh"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "clone.hh"
|
|
||||||
#include "misc/hash.hh"
|
#include "misc/hash.hh"
|
||||||
#include "ltlenv/defaultenv.hh"
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
@ -41,7 +38,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
struct ap_generator
|
struct ap_generator
|
||||||
{
|
{
|
||||||
virtual const formula* next() = 0;
|
virtual formula next() = 0;
|
||||||
virtual ~ap_generator() {}
|
virtual ~ap_generator() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -53,11 +50,11 @@ namespace spot
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* next()
|
formula next()
|
||||||
{
|
{
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << 'p' << nn++;
|
s << 'p' << nn++;
|
||||||
return default_environment::instance().require(s.str());
|
return formula::ap(s.str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -71,7 +68,7 @@ namespace spot
|
||||||
|
|
||||||
unsigned nn;
|
unsigned nn;
|
||||||
|
|
||||||
const formula* next()
|
formula next()
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
unsigned n = nn++;
|
unsigned n = nn++;
|
||||||
|
|
@ -81,16 +78,15 @@ namespace spot
|
||||||
n /= 26;
|
n /= 26;
|
||||||
}
|
}
|
||||||
while (n);
|
while (n);
|
||||||
|
return formula::ap(s);
|
||||||
return default_environment::instance().require(s);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class relabeler: public clone_visitor
|
class relabeler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::unordered_map<const formula*, const formula*> map;
|
typedef std::unordered_map<formula, formula> map;
|
||||||
map newname;
|
map newname;
|
||||||
ap_generator* gen;
|
ap_generator* gen;
|
||||||
relabeling_map* oldnames;
|
relabeling_map* oldnames;
|
||||||
|
|
@ -105,29 +101,33 @@ namespace spot
|
||||||
delete gen;
|
delete gen;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* rename(const formula* old)
|
formula rename(formula old)
|
||||||
{
|
{
|
||||||
auto r = newname.emplace(old, nullptr);
|
auto r = newname.emplace(old, nullptr);
|
||||||
if (!r.second)
|
if (!r.second)
|
||||||
{
|
{
|
||||||
return r.first->second->clone();
|
return r.first->second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const formula* res;
|
formula res = gen->next();
|
||||||
r.first->second = res = gen->next();
|
r.first->second = res;
|
||||||
if (oldnames)
|
if (oldnames)
|
||||||
(*oldnames)[res] = old->clone();
|
(*oldnames)[res] = old;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using clone_visitor::visit;
|
formula
|
||||||
|
visit(formula f)
|
||||||
void
|
|
||||||
visit(const atomic_prop* ap)
|
|
||||||
{
|
{
|
||||||
result_ = rename(ap);
|
if (f.is(op::AP))
|
||||||
|
return rename(f);
|
||||||
|
else
|
||||||
|
return f.map([this](formula f)
|
||||||
|
{
|
||||||
|
return this->visit(f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -135,9 +135,8 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
relabel(const formula* f, relabeling_style style,
|
relabel(formula f, relabeling_style style, relabeling_map* m)
|
||||||
relabeling_map* m)
|
|
||||||
{
|
{
|
||||||
ap_generator* gen = 0;
|
ap_generator* gen = 0;
|
||||||
switch (style)
|
switch (style)
|
||||||
|
|
@ -149,8 +148,9 @@ namespace spot
|
||||||
gen = new abc_generator;
|
gen = new abc_generator;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
relabeler rel(gen, m);
|
|
||||||
return rel.recurse(f);
|
relabeler r(gen, m);
|
||||||
|
return r.visit(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -227,16 +227,16 @@ namespace spot
|
||||||
// stop a, b, and !c, producing (p0&p1)U(p1&p2).
|
// stop a, b, and !c, producing (p0&p1)U(p1&p2).
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
typedef std::vector<const formula*> succ_vec;
|
typedef std::vector<formula> succ_vec;
|
||||||
typedef std::map<const formula*, succ_vec> fgraph;
|
typedef std::map<formula, succ_vec> fgraph;
|
||||||
|
|
||||||
// Convert the formula's syntax tree into an undirected graph
|
// Convert the formula's syntax tree into an undirected graph
|
||||||
// labeled by subformulas.
|
// labeled by subformulas.
|
||||||
class formula_to_fgraph: public visitor
|
class formula_to_fgraph final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
fgraph& g;
|
fgraph& g;
|
||||||
std::stack<const formula*> s;
|
std::stack<formula> s;
|
||||||
|
|
||||||
formula_to_fgraph(fgraph& g):
|
formula_to_fgraph(fgraph& g):
|
||||||
g(g)
|
g(g)
|
||||||
|
|
@ -248,104 +248,63 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
visit(const atomic_prop*)
|
visit(formula f)
|
||||||
{
|
{
|
||||||
}
|
{
|
||||||
|
// Connect to parent
|
||||||
|
auto in = g.emplace(f, succ_vec());
|
||||||
|
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);
|
||||||
|
|
||||||
void
|
unsigned sz = f.size();
|
||||||
visit(const constant*)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const bunop* bo)
|
|
||||||
{
|
|
||||||
recurse(bo->child());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const unop* uo)
|
|
||||||
{
|
|
||||||
recurse(uo->child());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const binop* bo)
|
|
||||||
{
|
|
||||||
const formula* l = bo->first();
|
|
||||||
recurse(l);
|
|
||||||
const formula* r = bo->second();
|
|
||||||
recurse(r);
|
|
||||||
// Link operands of Boolean operators.
|
|
||||||
if (bo->is_boolean())
|
|
||||||
{
|
|
||||||
g[l].push_back(r);
|
|
||||||
g[r].push_back(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
unsigned mos = mo->size();
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
const formula* b = mo->is_boolean() ? 0 : mo->boolean_operands(&i);
|
if (sz > 2 && !f.is_boolean())
|
||||||
if (b)
|
|
||||||
{
|
{
|
||||||
recurse(b);
|
/// If we have a formula like (a & b & Xc), consider
|
||||||
b->destroy();
|
/// 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 < mos; ++i)
|
for (; i < sz; ++i)
|
||||||
recurse(mo->nth(i));
|
visit(f.nth(i));
|
||||||
// For Boolean nodes, connect all children in a loop. This
|
if (sz > 1 && f.is_boolean())
|
||||||
// way the node can only be a cut-point if it separates all
|
|
||||||
// children from the reset of the graph (not only one).
|
|
||||||
if (mo->is_boolean())
|
|
||||||
{
|
{
|
||||||
const formula* pred = mo->nth(0);
|
// For Boolean nodes, connect all children in a
|
||||||
for (i = 1; i < mos; ++i)
|
// 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.nth(0);
|
||||||
|
for (i = 1; i < sz; ++i)
|
||||||
{
|
{
|
||||||
const formula* next = mo->nth(i);
|
formula next = f.nth(i);
|
||||||
// Note that we only add an edge in one direction,
|
// Note that we only add an edge in one
|
||||||
// because we are building a cycle between all
|
// direction, because we are building a cycle
|
||||||
// children anyway.
|
// between all children anyway.
|
||||||
g[pred].push_back(next);
|
g[pred].push_back(next);
|
||||||
pred = next;
|
pred = next;
|
||||||
}
|
}
|
||||||
g[pred].push_back(mo->nth(0));
|
g[pred].push_back(f.nth(0));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
recurse(const formula* f)
|
|
||||||
{
|
|
||||||
auto i = g.emplace(f, succ_vec());
|
|
||||||
if (!s.empty())
|
|
||||||
{
|
|
||||||
const formula* top = s.top();
|
|
||||||
i.first->second.push_back(top);
|
|
||||||
g[top].push_back(f);
|
|
||||||
if (!i.second)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(i.second);
|
|
||||||
}
|
|
||||||
f->clone();
|
|
||||||
s.push(f);
|
|
||||||
f->accept(*this);
|
|
||||||
s.pop();
|
s.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::set<const formula*> fset;
|
typedef std::set<formula> fset;
|
||||||
struct data_entry // for each node of the graph
|
struct data_entry // for each node of the graph
|
||||||
{
|
{
|
||||||
unsigned num; // serial number, in pre-order
|
unsigned num; // serial number, in pre-order
|
||||||
|
|
@ -355,11 +314,11 @@ namespace spot
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef std::unordered_map<const formula*, data_entry> fmap_t;
|
typedef std::unordered_map<formula, data_entry> fmap_t;
|
||||||
struct stack_entry
|
struct stack_entry
|
||||||
{
|
{
|
||||||
const formula* grand_parent;
|
formula grand_parent;
|
||||||
const formula* parent; // current node
|
formula parent; // current node
|
||||||
succ_vec::const_iterator current_child;
|
succ_vec::const_iterator current_child;
|
||||||
succ_vec::const_iterator last_child;
|
succ_vec::const_iterator last_child;
|
||||||
};
|
};
|
||||||
|
|
@ -377,7 +336,7 @@ namespace spot
|
||||||
// cut-point, but since we only return Boolean cut-points it's
|
// 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
|
// OK: if the top-most formula is Boolean we want to replace it
|
||||||
// as a whole).
|
// as a whole).
|
||||||
void cut_points(const fgraph& g, fset& c, const formula* start)
|
void cut_points(const fgraph& g, fset& c, formula start)
|
||||||
{
|
{
|
||||||
stack_t s;
|
stack_t s;
|
||||||
|
|
||||||
|
|
@ -397,7 +356,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
// Skip the edge if it is just the reverse of the one
|
// Skip the edge if it is just the reverse of the one
|
||||||
// we took.
|
// we took.
|
||||||
const formula* child = *e.current_child;
|
formula child = *e.current_child;
|
||||||
if (child == e.grand_parent)
|
if (child == e.grand_parent)
|
||||||
{
|
{
|
||||||
++e.current_child;
|
++e.current_child;
|
||||||
|
|
@ -428,15 +387,15 @@ namespace spot
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const formula* grand_parent = e.grand_parent;
|
formula grand_parent = e.grand_parent;
|
||||||
const formula* parent = e.parent;
|
formula parent = e.parent;
|
||||||
s.pop();
|
s.pop();
|
||||||
if (!s.empty())
|
if (!s.empty())
|
||||||
{
|
{
|
||||||
data_entry& dparent = data[parent];
|
data_entry& dparent = data[parent];
|
||||||
data_entry& dgrand_parent = data[grand_parent];
|
data_entry& dgrand_parent = data[grand_parent];
|
||||||
if (dparent.low >= dgrand_parent.num // cut-point
|
if (dparent.low >= dgrand_parent.num // cut-point
|
||||||
&& grand_parent->is_boolean())
|
&& grand_parent.is_boolean())
|
||||||
c.insert(grand_parent);
|
c.insert(grand_parent);
|
||||||
if (dparent.low < dgrand_parent.low)
|
if (dparent.low < dgrand_parent.low)
|
||||||
dgrand_parent.low = dparent.low;
|
dgrand_parent.low = dparent.low;
|
||||||
|
|
@ -450,7 +409,6 @@ namespace spot
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
fset& c;
|
fset& c;
|
||||||
|
|
||||||
bse_relabeler(ap_generator* gen, fset& c,
|
bse_relabeler(ap_generator* gen, fset& c,
|
||||||
relabeling_map* m)
|
relabeling_map* m)
|
||||||
: relabeler(gen, m), c(c)
|
: relabeler(gen, m), c(c)
|
||||||
|
|
@ -459,57 +417,51 @@ namespace spot
|
||||||
|
|
||||||
using relabeler::visit;
|
using relabeler::visit;
|
||||||
|
|
||||||
void
|
formula
|
||||||
visit(const multop* mo)
|
visit(formula f)
|
||||||
{
|
{
|
||||||
unsigned mos = mo->size();
|
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
|
/// If we have a formula like (a & b & Xc), consider
|
||||||
/// it as ((a & b) & Xc) in the graph to isolate the
|
/// it as ((a & b) & Xc) in the graph to isolate the
|
||||||
/// Boolean operands as a single node.
|
/// Boolean operands as a single node.
|
||||||
unsigned i = 0;
|
formula b = f.boolean_operands(&i);
|
||||||
const formula* b = mo->is_boolean() ? 0 : mo->boolean_operands(&i);
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
if (b)
|
if (b)
|
||||||
{
|
{
|
||||||
res->reserve(mos - i + 1);
|
res.reserve(sz - i + 1);
|
||||||
res->push_back(recurse(b));
|
res.push_back(visit(b));
|
||||||
b->destroy();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res->reserve(mos);
|
res.reserve(sz);
|
||||||
}
|
}
|
||||||
for (; i < mos; ++i)
|
for (; i < sz; ++i)
|
||||||
res->push_back(recurse(mo->nth(i)));
|
res.push_back(visit(f.nth(i)));
|
||||||
result_ = multop::instance(mo->op(), res);
|
return formula::multop(f.kind(), res);
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
recurse(const formula* f)
|
|
||||||
{
|
|
||||||
fset::const_iterator it = c.find(f);
|
|
||||||
if (it != c.end())
|
|
||||||
result_ = rename(f);
|
|
||||||
else
|
|
||||||
f->accept(*this);
|
|
||||||
return result_;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
relabel_bse(const formula* f, relabeling_style style,
|
relabel_bse(formula f, relabeling_style style, relabeling_map* m)
|
||||||
relabeling_map* m)
|
|
||||||
{
|
{
|
||||||
fgraph g;
|
fgraph g;
|
||||||
|
|
||||||
// Build the graph g from the formula f.
|
// Build the graph g from the formula f.
|
||||||
{
|
{
|
||||||
formula_to_fgraph conv(g);
|
formula_to_fgraph conv(g);
|
||||||
conv.recurse(f);
|
conv.visit(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute its cut-points
|
// Compute its cut-points
|
||||||
|
|
@ -529,18 +481,7 @@ namespace spot
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bse_relabeler rel(gen, c, m);
|
bse_relabeler rel(gen, c, m);
|
||||||
f = rel.recurse(f);
|
return rel.visit(f);
|
||||||
|
|
||||||
// Cleanup.
|
|
||||||
fgraph::const_iterator i = g.begin();
|
|
||||||
while (i != g.end())
|
|
||||||
{
|
|
||||||
const formula* f = i->first;
|
|
||||||
++i;
|
|
||||||
f->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,25 +29,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
enum relabeling_style { Abc, Pnn };
|
enum relabeling_style { Abc, Pnn };
|
||||||
|
|
||||||
|
typedef std::map<formula, formula> relabeling_map;
|
||||||
struct relabeling_map: public std::map<const formula*,
|
|
||||||
const formula*,
|
|
||||||
formula_ptr_less_than>
|
|
||||||
{
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
iterator i = begin();
|
|
||||||
while (i != end())
|
|
||||||
i++->second->destroy();
|
|
||||||
this->std::map<const formula*, const formula*,
|
|
||||||
formula_ptr_less_than>::clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
~relabeling_map()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \ingroup ltl_rewriting
|
/// \ingroup ltl_rewriting
|
||||||
/// \brief Relabel the atomic propositions in a formula.
|
/// \brief Relabel the atomic propositions in a formula.
|
||||||
|
|
@ -55,8 +37,8 @@ namespace spot
|
||||||
/// 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
|
||||||
const formula* relabel(const formula* f, relabeling_style style,
|
formula relabel(formula f, relabeling_style style,
|
||||||
relabeling_map* m = 0);
|
relabeling_map* m = 0);
|
||||||
|
|
||||||
|
|
||||||
/// \ingroup ltl_rewriting
|
/// \ingroup ltl_rewriting
|
||||||
|
|
@ -66,7 +48,7 @@ namespace spot
|
||||||
/// 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
|
||||||
const formula* relabel_bse(const formula* f, relabeling_style style,
|
formula relabel_bse(formula f, relabeling_style style,
|
||||||
relabeling_map* m = 0);
|
relabeling_map* m = 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,7 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "ltlvisit/simplify.hh"
|
#include "ltlvisit/simplify.hh"
|
||||||
#include "ltlvisit/clone.hh"
|
|
||||||
#include "ltlvisit/apcollect.hh"
|
#include "ltlvisit/apcollect.hh"
|
||||||
#include "ltlvisit/remove_x.hh"
|
#include "ltlvisit/remove_x.hh"
|
||||||
|
|
||||||
|
|
@ -29,104 +27,76 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
static formula
|
||||||
#define AND(x, y) multop::instance(multop::And, (x), (y))
|
remove_x_rec(formula f, atomic_prop_set& aps)
|
||||||
#define OR(x, y) multop::instance(multop::Or, (x), (y))
|
|
||||||
#define NOT(x) unop::instance(unop::Not, (x))
|
|
||||||
#define G(x) unop::instance(unop::G, (x))
|
|
||||||
#define U(x, y) binop::instance(binop::U, (x), (y))
|
|
||||||
|
|
||||||
class remove_x_visitor final : public clone_visitor
|
|
||||||
{
|
{
|
||||||
typedef clone_visitor super;
|
if (f.is_syntactic_stutter_invariant())
|
||||||
atomic_prop_set aps;
|
return f;
|
||||||
|
|
||||||
public:
|
auto rec = [&aps](formula f)
|
||||||
remove_x_visitor(const formula* f)
|
{
|
||||||
{
|
return remove_x_rec(f, aps);
|
||||||
atomic_prop_collect(f, &aps);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
virtual
|
if (!f.is(op::X))
|
||||||
~remove_x_visitor()
|
return f.map(rec);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
using super::visit;
|
formula c = rec(f.nth(0));
|
||||||
void visit(const unop* uo)
|
|
||||||
{
|
|
||||||
const formula* c = recurse(uo->child());
|
|
||||||
|
|
||||||
unop::type op = uo->op();
|
std::vector<formula> vo;
|
||||||
if (op != unop::X)
|
for (auto i: aps)
|
||||||
{
|
{
|
||||||
result_ = unop::instance(op, c);
|
// First line
|
||||||
return;
|
std::vector<formula> va1;
|
||||||
}
|
formula npi = formula::Not(i);
|
||||||
multop::vec* vo = new multop::vec;
|
va1.push_back(i);
|
||||||
for (atomic_prop_set::const_iterator i = aps.begin();
|
va1.push_back(formula::U(i, formula::And({npi, c})));
|
||||||
i != aps.end(); ++i)
|
|
||||||
{
|
|
||||||
// First line
|
|
||||||
multop::vec* va1 = new multop::vec;
|
|
||||||
const formula* npi = NOT((*i)->clone());
|
|
||||||
va1->push_back((*i)->clone());
|
|
||||||
va1->push_back(U((*i)->clone(), AND(npi, c->clone())));
|
|
||||||
for (atomic_prop_set::const_iterator j = aps.begin();
|
|
||||||
j != aps.end(); ++j)
|
|
||||||
if (*j != *i)
|
|
||||||
{
|
|
||||||
// make sure the arguments of OR are created in a
|
|
||||||
// deterministic order
|
|
||||||
auto tmp = U(NOT((*j)->clone()), npi->clone());
|
|
||||||
va1->push_back(OR(U((*j)->clone(), npi->clone()), tmp));
|
|
||||||
}
|
|
||||||
vo->push_back(multop::instance(multop::And, va1));
|
|
||||||
// Second line
|
|
||||||
multop::vec* va2 = new multop::vec;
|
|
||||||
va2->push_back(npi->clone());
|
|
||||||
va2->push_back(U(npi->clone(), AND((*i)->clone(), c->clone())));
|
|
||||||
for (atomic_prop_set::const_iterator j = aps.begin();
|
|
||||||
j != aps.end(); ++j)
|
|
||||||
if (*j != *i)
|
|
||||||
{
|
|
||||||
// make sure the arguments of OR are created in a
|
|
||||||
// deterministic order
|
|
||||||
auto tmp = U(NOT((*j)->clone()), (*i)->clone());
|
|
||||||
va2->push_back(OR(U((*j)->clone(), (*i)->clone()), tmp));
|
|
||||||
}
|
|
||||||
vo->push_back(multop::instance(multop::And, va2));
|
|
||||||
}
|
|
||||||
const formula* l12 = multop::instance(multop::Or, vo);
|
|
||||||
// Third line
|
|
||||||
multop::vec* va3 = new multop::vec;
|
|
||||||
for (atomic_prop_set::const_iterator i = aps.begin();
|
|
||||||
i != aps.end(); ++i)
|
|
||||||
{
|
|
||||||
// make sure the arguments of OR are created in a
|
|
||||||
// deterministic order
|
|
||||||
auto tmp = G(NOT((*i)->clone()));
|
|
||||||
va3->push_back(OR(G((*i)->clone()), tmp));
|
|
||||||
}
|
|
||||||
result_ = OR(l12, AND(multop::instance(multop::And, va3), c));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const formula* recurse(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->is_syntactic_stutter_invariant())
|
|
||||||
return f->clone();
|
|
||||||
f->accept(*this);
|
|
||||||
return this->result();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* remove_x(const formula* f)
|
formula remove_x(formula f)
|
||||||
{
|
{
|
||||||
remove_x_visitor v(f);
|
if (f.is_syntactic_stutter_invariant())
|
||||||
return v.recurse(f);
|
return f;
|
||||||
|
atomic_prop_set aps;
|
||||||
|
atomic_prop_collect(f, &aps);
|
||||||
|
return remove_x_rec(f, aps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2013 Laboratoire de Recherche et Developpement de
|
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Developpement
|
||||||
// l'Epita (LRDE).
|
// de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -19,14 +19,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "misc/common.hh"
|
#include "ltlast/formula.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
class formula;
|
|
||||||
|
|
||||||
/// \brief Rewrite a stutter-insensitive formula \a f without
|
/// \brief Rewrite a stutter-insensitive formula \a f without
|
||||||
/// using the X operator.
|
/// using the X operator.
|
||||||
///
|
///
|
||||||
|
|
@ -46,6 +44,6 @@ namespace spot
|
||||||
}
|
}
|
||||||
\endverbatim */
|
\endverbatim */
|
||||||
SPOT_API
|
SPOT_API
|
||||||
const formula* remove_x(const formula* f);
|
formula remove_x(formula f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2010, 2012, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2010, 2012, 2014, 2015 Laboratoire de Recherche et
|
||||||
// Développement de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
|
@ -20,87 +20,28 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "ltlvisit/clone.hh"
|
|
||||||
#include "simpfg.hh"
|
#include "simpfg.hh"
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
|
formula simplify_f_g(formula p)
|
||||||
simplify_f_g_visitor::simplify_f_g_visitor()
|
|
||||||
{
|
{
|
||||||
|
// 1 U p = Fp
|
||||||
|
if (p.is(op::U) && p.nth(0).is_true())
|
||||||
|
return formula::F(p.nth(1));
|
||||||
|
// 0 R p = Gp
|
||||||
|
if (p.is(op::R) && p.nth(0).is_false())
|
||||||
|
return formula::G(p.nth(1));
|
||||||
|
// p W 0 = Gp
|
||||||
|
if (p.is(op::W) && p.nth(1).is_false())
|
||||||
|
return formula::G(p.nth(0));
|
||||||
|
// p M 1 = Fp
|
||||||
|
if (p.is(op::M) && p.nth(1).is_true())
|
||||||
|
return formula::F(p.nth(0));
|
||||||
|
return p.map(simplify_f_g);
|
||||||
}
|
}
|
||||||
|
|
||||||
simplify_f_g_visitor::~simplify_f_g_visitor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
simplify_f_g_visitor::visit(const binop* bo)
|
|
||||||
{
|
|
||||||
const formula* f1 = recurse(bo->first());
|
|
||||||
const formula* f2 = recurse(bo->second());
|
|
||||||
binop::type op = bo->op();
|
|
||||||
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case binop::Xor:
|
|
||||||
case binop::Implies:
|
|
||||||
case binop::Equiv:
|
|
||||||
case binop::UConcat:
|
|
||||||
case binop::EConcat:
|
|
||||||
case binop::EConcatMarked:
|
|
||||||
result_ = binop::instance(op, f1, f2);
|
|
||||||
return;
|
|
||||||
/* true U f2 == F(f2) */
|
|
||||||
case binop::U:
|
|
||||||
if (f1 == constant::true_instance())
|
|
||||||
result_ = unop::instance(unop::F, f2);
|
|
||||||
else
|
|
||||||
result_ = binop::instance(binop::U, f1, f2);
|
|
||||||
return;
|
|
||||||
/* false R f2 == G(f2) */
|
|
||||||
case binop::R:
|
|
||||||
if (f1 == constant::false_instance())
|
|
||||||
result_ = unop::instance(unop::G, f2);
|
|
||||||
else
|
|
||||||
result_ = binop::instance(binop::R, f1, f2);
|
|
||||||
return;
|
|
||||||
/* f1 W false == G(f1) */
|
|
||||||
case binop::W:
|
|
||||||
if (f2 == constant::false_instance())
|
|
||||||
result_ = unop::instance(unop::G, f1);
|
|
||||||
else
|
|
||||||
result_ = binop::instance(binop::W, f1, f2);
|
|
||||||
return;
|
|
||||||
/* f1 M true == F(f1) */
|
|
||||||
case binop::M:
|
|
||||||
if (f2 == constant::true_instance())
|
|
||||||
result_ = unop::instance(unop::F, f1);
|
|
||||||
else
|
|
||||||
result_ = binop::instance(binop::M, f1, f2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
simplify_f_g_visitor::recurse(const formula* f)
|
|
||||||
{
|
|
||||||
return simplify_f_g(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
|
||||||
simplify_f_g(const formula* f)
|
|
||||||
{
|
|
||||||
if (f->is_boolean())
|
|
||||||
return f->clone();
|
|
||||||
simplify_f_g_visitor v;
|
|
||||||
f->accept(v);
|
|
||||||
return v.result();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2010, 2012, 2013 Laboratoire de Recherche et
|
// Copyright (C) 2010, 2012, 2013, 2015 Laboratoire de Recherche et
|
||||||
// Développement de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
|
@ -22,36 +22,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "clone.hh"
|
#include "ltlast/formula.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
/// \ingroup ltl_visitor
|
|
||||||
/// \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):
|
|
||||||
///
|
|
||||||
/// - true U a = F a
|
|
||||||
/// - a M true = F a
|
|
||||||
/// - false R a = G a
|
|
||||||
/// - a W false = G a
|
|
||||||
///
|
|
||||||
class SPOT_API simplify_f_g_visitor : public clone_visitor
|
|
||||||
{
|
|
||||||
typedef clone_visitor super;
|
|
||||||
public:
|
|
||||||
simplify_f_g_visitor();
|
|
||||||
virtual ~simplify_f_g_visitor();
|
|
||||||
|
|
||||||
using super::visit;
|
|
||||||
void visit(const binop* bo);
|
|
||||||
|
|
||||||
virtual const formula* recurse(const formula* f);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \ingroup ltl_rewriting
|
/// \ingroup ltl_rewriting
|
||||||
/// \brief Replace <code>true U f</code> and <code>false R g</code> by
|
/// \brief Replace <code>true U f</code> and <code>false R g</code> by
|
||||||
/// <code>F f</code> and <code>G g</code>.
|
/// <code>F f</code> and <code>G g</code>.
|
||||||
|
|
@ -63,6 +39,6 @@ namespace spot
|
||||||
/// - false R a = G a
|
/// - false R a = G a
|
||||||
/// - a W false = G a
|
/// - a W false = G a
|
||||||
///
|
///
|
||||||
SPOT_API const formula* simplify_f_g(const formula* f);
|
SPOT_API formula simplify_f_g(formula f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2011, 2012, 2013, 2014, 2015 Laboratoire de Recherche
|
||||||
// Developpement de l'Epita (LRDE).
|
// et Developpement de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -106,7 +106,7 @@ namespace spot
|
||||||
|
|
||||||
/// Simplify the formula \a f (using options supplied to the
|
/// Simplify the formula \a f (using options supplied to the
|
||||||
/// constructor).
|
/// constructor).
|
||||||
const formula* simplify(const formula* f);
|
formula simplify(formula f);
|
||||||
|
|
||||||
/// Build the negative normal form of formula \a f.
|
/// Build the negative normal form of formula \a f.
|
||||||
/// All negations of the formula are pushed in front of the
|
/// All negations of the formula are pushed in front of the
|
||||||
|
|
@ -116,8 +116,8 @@ namespace spot
|
||||||
/// \param f The formula to normalize.
|
/// \param f The formula to normalize.
|
||||||
/// \param negated If \c true, return the negative normal form of
|
/// \param negated If \c true, return the negative normal form of
|
||||||
/// \c !f
|
/// \c !f
|
||||||
const formula*
|
formula
|
||||||
negative_normal_form(const formula* f, bool negated = false);
|
negative_normal_form(formula f, bool negated = false);
|
||||||
|
|
||||||
/// \brief Syntactic implication.
|
/// \brief Syntactic implication.
|
||||||
///
|
///
|
||||||
|
|
@ -138,20 +138,20 @@ namespace spot
|
||||||
}
|
}
|
||||||
\endverbatim */
|
\endverbatim */
|
||||||
///
|
///
|
||||||
bool syntactic_implication(const formula* f, const 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(const formula* f, const 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(const formula* f, const 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.
|
||||||
|
|
@ -159,13 +159,13 @@ namespace spot
|
||||||
/// 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(const formula* f, const 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(const formula* f);
|
bdd as_bdd(formula f);
|
||||||
|
|
||||||
/// \brief Clear the as_bdd() cache.
|
/// \brief Clear the as_bdd() cache.
|
||||||
///
|
///
|
||||||
|
|
@ -182,14 +182,14 @@ namespace spot
|
||||||
bdd_dict_ptr get_dict() const;
|
bdd_dict_ptr get_dict() const;
|
||||||
|
|
||||||
/// Cached version of spot::ltl::star_normal_form().
|
/// Cached version of spot::ltl::star_normal_form().
|
||||||
const formula* star_normal_form(const 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.
|
||||||
const formula* boolean_to_isop(const 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;
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "snf.hh"
|
#include "snf.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include "ltlast/visitor.hh"
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -27,82 +25,51 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// E°
|
// E° if bounded=false
|
||||||
class snf_visitor: public visitor
|
// E^□ if nounded=true
|
||||||
|
template<bool bounded>
|
||||||
|
class snf_visitor
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const formula* result_;
|
formula result_;
|
||||||
snf_cache* cache_;
|
snf_cache* cache_;
|
||||||
public:
|
public:
|
||||||
|
snf_visitor(snf_cache* c)
|
||||||
snf_visitor(snf_cache* c): cache_(c)
|
: cache_(c)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
formula visit(formula f)
|
||||||
result() const
|
|
||||||
{
|
{
|
||||||
return result_;
|
if (!f.accepts_eword())
|
||||||
}
|
return f;
|
||||||
|
|
||||||
void
|
snf_cache::const_iterator i = cache_->find(f);
|
||||||
visit(const atomic_prop*)
|
if (i != cache_->end())
|
||||||
{
|
return i->second;
|
||||||
SPOT_UNIMPLEMENTED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
formula out;
|
||||||
visit(const constant* c)
|
switch (f.kind())
|
||||||
{
|
|
||||||
assert(c == constant::empty_word_instance());
|
|
||||||
(void)c;
|
|
||||||
result_ = constant::false_instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const bunop* bo)
|
|
||||||
{
|
|
||||||
bunop::type op = bo->op();
|
|
||||||
switch (op)
|
|
||||||
{
|
{
|
||||||
case bunop::Star:
|
case op::EmptyWord:
|
||||||
assert(bo->accepts_eword());
|
out = formula::ff();
|
||||||
// Strip the star.
|
|
||||||
result_ = recurse(bo->child());
|
|
||||||
break;
|
break;
|
||||||
case bunop::FStar:
|
case op::Star:
|
||||||
// FIXME: Can we deal with FStar in a better way?
|
if (!bounded)
|
||||||
result_ = bo->clone();
|
out = visit(f.nth(0)); // Strip the star.
|
||||||
|
else
|
||||||
|
out = formula::Star(visit(f.nth(0)),
|
||||||
|
std::max(unsigned(f.min()), 1U), f.max());
|
||||||
break;
|
break;
|
||||||
|
case op::Concat:
|
||||||
}
|
if (bounded)
|
||||||
}
|
{
|
||||||
|
out = f;
|
||||||
void
|
break;
|
||||||
visit(const unop*)
|
}
|
||||||
{
|
// Fall through
|
||||||
SPOT_UNIMPLEMENTED();
|
case op::OrRat:
|
||||||
}
|
case op::AndNLM:
|
||||||
|
|
||||||
void
|
|
||||||
visit(const binop*)
|
|
||||||
{
|
|
||||||
SPOT_UNIMPLEMENTED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
multop::type op = mo->op();
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case multop::And:
|
|
||||||
case multop::Or:
|
|
||||||
case multop::Fusion:
|
|
||||||
SPOT_UNIMPLEMENTED();
|
|
||||||
break;
|
|
||||||
case multop::Concat:
|
|
||||||
case multop::AndNLM:
|
|
||||||
// Let F designate expressions that accept [*0],
|
// Let F designate expressions that accept [*0],
|
||||||
// and G designate expressions that do not.
|
// and G designate expressions that do not.
|
||||||
|
|
||||||
|
|
@ -112,100 +79,70 @@ namespace spot
|
||||||
//
|
//
|
||||||
// AndNLM can be dealt with similarly.
|
// AndNLM can be dealt with similarly.
|
||||||
//
|
//
|
||||||
// This case is already handled in recurse().
|
// The above cases are already handled by the
|
||||||
// if we reach this switch, we only have to
|
// accepts_eword() tests at the top of this method. So
|
||||||
// deal with...
|
// we reach this switch, we only have to deal with...
|
||||||
//
|
//
|
||||||
// (F₁;F₂;F₃)° = (F₁°)|(F₂°)|(F₃°)
|
// (F₁;F₂;F₃)° = (F₁°)|(F₂°)|(F₃°)
|
||||||
// (F₁&F₂&F₃)° = (F₁°)|(F₂°)|(F₃°)
|
// (F₁&F₂&F₃)° = (F₁°)|(F₂°)|(F₃°)
|
||||||
// so we fall through to the OrRat case...
|
// (F₁|G₂|F₃)° = (F₁°)|(G₂°)|(F₃°)
|
||||||
case multop::OrRat:
|
|
||||||
assert(mo->accepts_eword());
|
|
||||||
{
|
{
|
||||||
unsigned s = mo->size();
|
unsigned s = f.size();
|
||||||
multop::vec* v = new multop::vec;
|
std::vector<formula> v;
|
||||||
v->reserve(s);
|
v.reserve(s);
|
||||||
for (unsigned pos = 0; pos < s; ++pos)
|
for (unsigned pos = 0; pos < s; ++pos)
|
||||||
v->push_back(recurse(mo->nth(pos)));
|
v.emplace_back(visit(f.nth(pos)));
|
||||||
result_ = multop::instance(multop::OrRat, v);
|
out = formula::OrRat(v);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
case op::False:
|
||||||
case multop::AndRat:
|
case op::True:
|
||||||
// FIXME: Can we deal with AndRat in a better way
|
case op::AP:
|
||||||
// when it accepts [*0]?
|
case op::Not:
|
||||||
result_ = mo->clone();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const formula*
|
return (*cache_)[f] = out;
|
||||||
recurse(const formula* f)
|
|
||||||
{
|
|
||||||
if (!f->accepts_eword())
|
|
||||||
return f->clone();
|
|
||||||
|
|
||||||
snf_cache::const_iterator i = cache_->find(f);
|
|
||||||
if (i != cache_->end())
|
|
||||||
return i->second->clone();
|
|
||||||
|
|
||||||
f->accept(*this);
|
|
||||||
|
|
||||||
(*cache_)[f->clone()] = result_->clone();
|
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// E^□
|
|
||||||
class snf_visitor_bounded: public snf_visitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
snf_visitor_bounded(snf_cache* c): snf_visitor(c)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const bunop* bo)
|
|
||||||
{
|
|
||||||
bunop::type op = bo->op();
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case bunop::Star:
|
|
||||||
assert(bo->accepts_eword());
|
|
||||||
result_ = bunop::instance(bunop::Star,
|
|
||||||
recurse(bo->child()),
|
|
||||||
std::max(bo->min(), 1U),
|
|
||||||
bo->max());
|
|
||||||
break;
|
|
||||||
case bunop::FStar:
|
|
||||||
result_ = bo->clone();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(const multop* mo)
|
|
||||||
{
|
|
||||||
if (mo->op() == multop::Concat)
|
|
||||||
result_ = mo->clone();
|
|
||||||
else
|
|
||||||
this->snf_visitor::visit(mo);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
star_normal_form(const formula* sere, snf_cache* cache)
|
star_normal_form(formula sere, snf_cache* cache)
|
||||||
{
|
{
|
||||||
snf_visitor v(cache);
|
snf_visitor<false> v(cache);
|
||||||
return v.recurse(sere);
|
return v.visit(sere);
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula*
|
formula
|
||||||
star_normal_form_bounded(const formula* sere, snf_cache* cache)
|
star_normal_form_bounded(formula sere, snf_cache* cache)
|
||||||
{
|
{
|
||||||
snf_visitor_bounded v(cache);
|
snf_visitor<true> v(cache);
|
||||||
return v.recurse(sere);
|
return v.visit(sere);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2012, 2013, 2014, 2015 Laboratoire de Recherche et
|
||||||
// Developpement de l'Epita (LRDE).
|
// Developpement de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
|
|
@ -20,15 +20,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ltlast/formula.hh"
|
#include "ltlast/formula.hh"
|
||||||
#include "misc/hash.hh"
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef std::unordered_map<const formula*, const formula*,
|
typedef std::unordered_map<formula, formula> snf_cache;
|
||||||
ptr_hash<formula>> snf_cache;
|
|
||||||
|
|
||||||
/// Helper to rewrite a sere in Star Normal Form.
|
/// Helper to rewrite a sere in Star Normal Form.
|
||||||
///
|
///
|
||||||
|
|
@ -49,11 +48,11 @@ namespace spot
|
||||||
///
|
///
|
||||||
/// \param sere the SERE to rewrite
|
/// \param sere the SERE to rewrite
|
||||||
/// \param cache an optional cache
|
/// \param cache an optional cache
|
||||||
SPOT_API const formula*
|
SPOT_API formula
|
||||||
star_normal_form(const formula* sere, snf_cache* cache = 0);
|
star_normal_form(formula sere, snf_cache* cache = 0);
|
||||||
|
|
||||||
/// A variant of star_normal_form() for r[*0..j] where j < ω.
|
/// A variant of star_normal_form() for r[*0..j] where j < ω.
|
||||||
SPOT_API const formula*
|
SPOT_API formula
|
||||||
star_normal_form_bounded(const formula* sere, snf_cache* cache = 0);
|
star_normal_form_bounded(formula sere, snf_cache* cache = 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
|
|
||||||
#include "unabbrev.hh"
|
#include "unabbrev.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -70,242 +68,183 @@ namespace spot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unabbreviator::~unabbreviator()
|
formula unabbreviator::run(formula in)
|
||||||
{
|
|
||||||
auto i = cache_.begin();
|
|
||||||
auto end = cache_.end();
|
|
||||||
while (i != end)
|
|
||||||
{
|
|
||||||
auto old = i++;
|
|
||||||
old->second->destroy();
|
|
||||||
old->first->destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const formula* unabbreviator::run(const formula* in)
|
|
||||||
{
|
{
|
||||||
auto entry = cache_.emplace(in, nullptr);
|
auto entry = cache_.emplace(in, nullptr);
|
||||||
if (!entry.second)
|
if (!entry.second)
|
||||||
return entry.first->second->clone();
|
return entry.first->second;
|
||||||
in->clone();
|
|
||||||
|
|
||||||
// Skip recursion whenever possible
|
// Skip recursion whenever possible
|
||||||
bool no_boolean_rewrite = !re_some_bool_ || in->is_sugar_free_boolean();
|
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();
|
bool no_f_g_rewrite = !re_some_f_g_ || in.is_sugar_free_ltl();
|
||||||
if (no_boolean_rewrite
|
if (no_boolean_rewrite
|
||||||
&& (in->is_boolean() || (no_f_g_rewrite && !re_some_other_)))
|
&& (in.is_boolean() || (no_f_g_rewrite && !re_some_other_)))
|
||||||
|
return entry.first->second = in;
|
||||||
|
|
||||||
|
auto rec = [this](formula f)
|
||||||
{
|
{
|
||||||
entry.first->second = in->clone();
|
return this->run(f);
|
||||||
return in->clone();
|
};
|
||||||
|
|
||||||
|
formula out = in;
|
||||||
|
if (in.size() > 0)
|
||||||
|
out = in.map(rec);
|
||||||
|
|
||||||
|
switch (out.kind())
|
||||||
|
{
|
||||||
|
case op::False:
|
||||||
|
case op::True:
|
||||||
|
case op::EmptyWord:
|
||||||
|
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.nth(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.nth(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!re_w_)
|
||||||
|
{
|
||||||
|
out = formula::W(out.nth(0), formula::ff());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto nc = formula::Not(out.nth(0));
|
||||||
|
if (!re_f_)
|
||||||
|
{
|
||||||
|
out = formula::Not(formula::F(nc));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out = formula::Not(formula::U(formula::tt(), nc));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case op::Xor:
|
||||||
|
// f1 ^ f2 == !(f1 <-> f2)
|
||||||
|
// f1 ^ f2 == (f1 & !f2) | (f2 & !f1)
|
||||||
|
if (!re_xor_)
|
||||||
|
break;
|
||||||
|
{
|
||||||
|
auto f1 = out.nth(0);
|
||||||
|
auto f2 = out.nth(1);
|
||||||
|
if (!re_e_)
|
||||||
|
{
|
||||||
|
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.nth(0)), out.nth(1)});
|
||||||
|
break;
|
||||||
|
case op::Equiv:
|
||||||
|
// f1 <=> f2 == (f1 & f2) | (!f1 & !f2)
|
||||||
|
if (!re_e_)
|
||||||
|
break;
|
||||||
|
{
|
||||||
|
auto f1 = out.nth(0);
|
||||||
|
auto f2 = out.nth(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.nth(0);
|
||||||
|
auto f2 = out.nth(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.nth(0);
|
||||||
|
auto f2 = out.nth(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.nth(1);
|
||||||
|
out = formula::U(f2, formula::And({f2, out.nth(0)}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return entry.first->second = out;
|
||||||
const formula* out = nullptr;
|
|
||||||
switch (in->kind())
|
|
||||||
{
|
|
||||||
case formula::AtomicProp:
|
|
||||||
case formula::Constant:
|
|
||||||
out = in->clone();
|
|
||||||
break;
|
|
||||||
case formula::UnOp:
|
|
||||||
{
|
|
||||||
const unop* uo = static_cast<const unop*>(in);
|
|
||||||
auto c = run(uo->child());
|
|
||||||
switch (auto op = uo->op())
|
|
||||||
{
|
|
||||||
// F f = true U f
|
|
||||||
case unop::F:
|
|
||||||
if (!re_f_)
|
|
||||||
goto unop_clone;
|
|
||||||
out = binop::instance(binop::U, constant::true_instance(), c);
|
|
||||||
break;
|
|
||||||
// G f = false R f
|
|
||||||
// G f = f W false
|
|
||||||
// G f = !F!f
|
|
||||||
// G f = !(true U !f)
|
|
||||||
case unop::G:
|
|
||||||
if (!re_g_)
|
|
||||||
goto unop_clone;
|
|
||||||
if (!re_r_)
|
|
||||||
{
|
|
||||||
out = binop::instance(binop::R,
|
|
||||||
constant::false_instance(), c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!re_w_)
|
|
||||||
{
|
|
||||||
out = binop::instance(binop::W,
|
|
||||||
c, constant::false_instance());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto nc = unop::instance(unop::Not, c);
|
|
||||||
if (!re_f_)
|
|
||||||
{
|
|
||||||
out = unop::instance(unop::Not,
|
|
||||||
unop::instance(unop::F, nc));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto u = binop::instance(binop::U,
|
|
||||||
constant::true_instance(), nc);
|
|
||||||
out = unop::instance(unop::Not, u);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case unop::Not:
|
|
||||||
case unop::X:
|
|
||||||
case unop::Closure:
|
|
||||||
case unop::NegClosure:
|
|
||||||
case unop::NegClosureMarked:
|
|
||||||
unop_clone:
|
|
||||||
out = unop::instance(op, c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case formula::BinOp:
|
|
||||||
{
|
|
||||||
const binop* bo = static_cast<const binop*>(in);
|
|
||||||
auto f1 = run(bo->first());
|
|
||||||
auto f2 = run(bo->second());
|
|
||||||
switch (auto op = bo->op())
|
|
||||||
{
|
|
||||||
// f1 ^ f2 == !(f1 <-> f2)
|
|
||||||
// f1 ^ f2 == (f1 & !f2) | (f2 & !f1)
|
|
||||||
case binop::Xor:
|
|
||||||
{
|
|
||||||
if (!re_xor_)
|
|
||||||
goto binop_clone;
|
|
||||||
if (!re_e_)
|
|
||||||
{
|
|
||||||
out = unop::instance(unop::Not,
|
|
||||||
binop::instance(binop::Equiv,
|
|
||||||
f1, f2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto a = multop::instance(multop::And, f1->clone(),
|
|
||||||
unop::instance(unop::Not,
|
|
||||||
f2->clone()));
|
|
||||||
auto b = multop::instance(multop::And, f2,
|
|
||||||
unop::instance(unop::Not, f1));
|
|
||||||
out = multop::instance(multop::Or, a, b);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// f1 => f2 == !f1 | f2
|
|
||||||
case binop::Implies:
|
|
||||||
if (!re_i_)
|
|
||||||
goto binop_clone;
|
|
||||||
out = multop::instance(multop::Or,
|
|
||||||
unop::instance(unop::Not, f1), f2);
|
|
||||||
break;
|
|
||||||
// f1 <=> f2 == (f1 & f2) | (!f1 & !f2)
|
|
||||||
case binop::Equiv:
|
|
||||||
if (!re_e_)
|
|
||||||
goto binop_clone;
|
|
||||||
{
|
|
||||||
auto nf1 = unop::instance(unop::Not, f1->clone());
|
|
||||||
auto nf2 = unop::instance(unop::Not, f2->clone());
|
|
||||||
auto term1 = multop::instance(multop::And, f1, f2);
|
|
||||||
auto term2 = multop::instance(multop::And, nf1, nf2);
|
|
||||||
out = multop::instance(multop::Or, term1, term2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// 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))
|
|
||||||
case binop::W:
|
|
||||||
if (!re_w_)
|
|
||||||
goto binop_clone;
|
|
||||||
if (!re_r_)
|
|
||||||
{
|
|
||||||
out = binop::instance(binop::R, f2,
|
|
||||||
multop::instance(multop::Or,
|
|
||||||
f2->clone(), f1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
f1->clone();
|
|
||||||
out = unop::instance(unop::G, f1);
|
|
||||||
if (re_g_)
|
|
||||||
{
|
|
||||||
auto tmp = out;
|
|
||||||
out = run(out);
|
|
||||||
tmp->destroy();
|
|
||||||
}
|
|
||||||
out = binop::instance(binop::U, f1,
|
|
||||||
multop::instance(multop::Or, f2, out));
|
|
||||||
break;
|
|
||||||
// f1 M f2 = f2 U (g2 & f1)
|
|
||||||
case binop::M:
|
|
||||||
if (!re_m_)
|
|
||||||
goto binop_clone;
|
|
||||||
out = binop::instance(binop::U, f2,
|
|
||||||
multop::instance(multop::And,
|
|
||||||
f2->clone(), f1));
|
|
||||||
break;
|
|
||||||
// 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))
|
|
||||||
case binop::R:
|
|
||||||
if (!re_r_)
|
|
||||||
goto binop_clone;
|
|
||||||
{
|
|
||||||
auto f12 = multop::instance(multop::And, f1, f2->clone());
|
|
||||||
if (!re_w_)
|
|
||||||
{
|
|
||||||
out = binop::instance(binop::W, f2, f12);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out = unop::instance(unop::G, f2->clone());
|
|
||||||
if (re_g_)
|
|
||||||
{
|
|
||||||
auto tmp = out;
|
|
||||||
out = run(tmp);
|
|
||||||
tmp->destroy();
|
|
||||||
}
|
|
||||||
out = binop::instance(binop::U, f2,
|
|
||||||
multop::instance(multop::Or, f12, out));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case binop::U:
|
|
||||||
case binop::UConcat:
|
|
||||||
case binop::EConcat:
|
|
||||||
case binop::EConcatMarked:
|
|
||||||
binop_clone:
|
|
||||||
out = binop::instance(op, f1, f2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case formula::MultOp:
|
|
||||||
{
|
|
||||||
const multop* mo = static_cast<const multop*>(in);
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
unsigned mos = mo->size();
|
|
||||||
res->reserve(mos);
|
|
||||||
for (unsigned i = 0; i < mos; ++i)
|
|
||||||
res->push_back(run(mo->nth(i)));
|
|
||||||
out = multop::instance(mo->op(), res);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case formula::BUnOp:
|
|
||||||
{
|
|
||||||
const bunop* bo = static_cast<const bunop*>(in);
|
|
||||||
out = bunop::instance(bo->op(), run(bo->child()),
|
|
||||||
bo->min(), bo->max());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(out != nullptr);
|
|
||||||
|
|
||||||
entry.first->second = out;
|
|
||||||
return out->clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const formula* unabbreviate(const 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);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace spot
|
||||||
bool re_some_f_g_ = false; // rewrite F or G
|
bool re_some_f_g_ = false; // rewrite F or G
|
||||||
bool re_some_other_ = false; // rewrite W, M, or R
|
bool re_some_other_ = false; // rewrite W, M, or R
|
||||||
// Cache of rewritten subformulas
|
// Cache of rewritten subformulas
|
||||||
std::unordered_map<const formula*, const formula*> cache_;
|
std::unordered_map<formula, formula> cache_;
|
||||||
public:
|
public:
|
||||||
/// \brief Constructor
|
/// \brief Constructor
|
||||||
///
|
///
|
||||||
|
|
@ -55,8 +55,7 @@ namespace spot
|
||||||
/// which in which each letter denote an operator (using LBT's
|
/// which in which each letter denote an operator (using LBT's
|
||||||
/// convention).
|
/// convention).
|
||||||
unabbreviator(const char* opt = default_unabbrev_string);
|
unabbreviator(const char* opt = default_unabbrev_string);
|
||||||
const formula* run(const formula* in);
|
formula run(formula in);
|
||||||
~unabbreviator();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \ingroup ltl_rewriting
|
/// \ingroup ltl_rewriting
|
||||||
|
|
@ -66,8 +65,8 @@ namespace spot
|
||||||
/// The set of operators to remove should be passed as a string
|
/// The set of operators to remove should be passed as a string
|
||||||
/// which in which each letter denote an operator (using LBT's
|
/// which in which each letter denote an operator (using LBT's
|
||||||
/// convention).
|
/// convention).
|
||||||
SPOT_API const formula*
|
SPOT_API formula
|
||||||
unabbreviate(const formula* in, const char* opt= default_unabbrev_string);
|
unabbreviate(formula in, const char* opt= default_unabbrev_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "ltlast/constant.hh"
|
|
||||||
#include "twa/formula2bdd.hh"
|
#include "twa/formula2bdd.hh"
|
||||||
#include "public.hh"
|
#include "public.hh"
|
||||||
#include "priv/accmap.hh"
|
#include "priv/accmap.hh"
|
||||||
|
|
@ -45,9 +44,10 @@
|
||||||
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 formula* over and
|
and it would be a waste of time to parse them to ltl::formula
|
||||||
over, and to register all their atomic_propositions in the
|
over and over, and to register all their atomic_propositions in
|
||||||
bdd_dict. Keep the bdd result around so we can reuse it. */
|
the bdd_dict. Keep the bdd result around so we can reuse
|
||||||
|
it. */
|
||||||
typedef std::map<std::string, bdd> formula_cache;
|
typedef std::map<std::string, bdd> formula_cache;
|
||||||
|
|
||||||
typedef std::pair<int, std::string*> pair;
|
typedef std::pair<int, std::string*> pair;
|
||||||
|
|
@ -152,7 +152,6 @@
|
||||||
%code
|
%code
|
||||||
{
|
{
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "ltlast/constant.hh"
|
|
||||||
#include "ltlparse/public.hh"
|
#include "ltlparse/public.hh"
|
||||||
|
|
||||||
/* parseaut.hh and parsedecl.hh include each other recursively.
|
/* parseaut.hh and parsedecl.hh include each other recursively.
|
||||||
|
|
@ -561,9 +560,7 @@ ap-name: STRING
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "unknown atomic proposition \"" << *$1 << "\"";
|
out << "unknown atomic proposition \"" << *$1 << "\"";
|
||||||
error(@1, out.str());
|
error(@1, out.str());
|
||||||
f = spot::ltl::default_environment::instance()
|
b = res.h->aut->register_ap("$unknown$");
|
||||||
.require("$unknown$");
|
|
||||||
b = res.h->aut->register_ap(f);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -575,7 +572,6 @@ ap-name: STRING
|
||||||
error(@1, out.str());
|
error(@1, out.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f->destroy();
|
|
||||||
res.ap.push_back(b);
|
res.ap.push_back(b);
|
||||||
}
|
}
|
||||||
delete $1;
|
delete $1;
|
||||||
|
|
@ -1422,11 +1418,7 @@ nc-formula: nc-formula-or-ident
|
||||||
}
|
}
|
||||||
bdd cond = bddfalse;
|
bdd cond = bddfalse;
|
||||||
if (f)
|
if (f)
|
||||||
{
|
cond = spot::formula_to_bdd(f, res.h->aut->get_dict(), res.h->aut);
|
||||||
cond = spot::formula_to_bdd(f, res.h->aut->get_dict(),
|
|
||||||
res.h->aut);
|
|
||||||
f->destroy();
|
|
||||||
}
|
|
||||||
$$ = (res.fcache[*$1] = cond).id();
|
$$ = (res.fcache[*$1] = cond).id();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1587,7 +1579,7 @@ lbtt-acc: { $$ = 0U; }
|
||||||
lbtt-guard: STRING
|
lbtt-guard: STRING
|
||||||
{
|
{
|
||||||
spot::ltl::parse_error_list pel;
|
spot::ltl::parse_error_list pel;
|
||||||
auto* f = spot::ltl::parse_prefix_ltl(*$1, pel, *res.env);
|
auto f = spot::ltl::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: ";
|
||||||
|
|
@ -1611,7 +1603,7 @@ lbtt-guard: STRING
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!f->is_boolean())
|
if (!f.is_boolean())
|
||||||
{
|
{
|
||||||
error(@$,
|
error(@$,
|
||||||
"non-Boolean transition label (replaced by true)");
|
"non-Boolean transition label (replaced by true)");
|
||||||
|
|
@ -1622,7 +1614,6 @@ lbtt-guard: STRING
|
||||||
res.cur_label =
|
res.cur_label =
|
||||||
formula_to_bdd(f, res.h->aut->get_dict(), res.h->aut);
|
formula_to_bdd(f, res.h->aut->get_dict(), res.h->aut);
|
||||||
}
|
}
|
||||||
f->destroy();
|
|
||||||
}
|
}
|
||||||
delete $1;
|
delete $1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ for dir in "${INCDIR-..}" "${INCDIR-..}"/../iface; do
|
||||||
perl -pe 'sub f {my $a = shift; $a =~ s:[^\n]*://:g; return "$a"}
|
perl -pe 'sub f {my $a = shift; $a =~ s:[^\n]*://:g; return "$a"}
|
||||||
s,/\*(.*?)\*/,f($1),sge;
|
s,/\*(.*?)\*/,f($1),sge;
|
||||||
s,//.*?\n,//\n,g;
|
s,//.*?\n,//\n,g;
|
||||||
s,"[^"\n]*","",g;
|
s,"(\\.|[^"\\\n])*","",g;
|
||||||
s,SPOT_API ,,g' -0777 <$file >$tmp
|
s,SPOT_API ,,g' -0777 <$file >$tmp
|
||||||
|
|
||||||
$GREP '[ ]$' $tmp &&
|
$GREP '[ ]$' $tmp &&
|
||||||
|
|
@ -231,10 +231,14 @@ for dir in "${INCDIR-..}" "${INCDIR-..}"/../iface; do
|
||||||
$GREP -v 'for (.*;;)' $tmp | $GREP ';[^ ")'"']" &&
|
$GREP -v 'for (.*;;)' $tmp | $GREP ';[^ ")'"']" &&
|
||||||
diag 'Must have space or newline after semicolon.'
|
diag 'Must have space or newline after semicolon.'
|
||||||
|
|
||||||
$GREP '}.*}' $tmp &&
|
# Allow several { or } on the same line only if they are mixed
|
||||||
|
# with parentheses, as this often occur with lambdas or
|
||||||
|
# initializer lists. What we want to forbid is cases where
|
||||||
|
# multiple scopes are opened/closed on the same line.
|
||||||
|
$GREP '^[^()]*}[^()]*}[^()]*$' $tmp &&
|
||||||
diag 'No two } on the same line.'
|
diag 'No two } on the same line.'
|
||||||
|
|
||||||
$GREP '{.*{' $tmp &&
|
$GREP '^[^()]{[^()]*{[^()]$' $tmp &&
|
||||||
diag 'No two { on the same line.'
|
diag 'No two { on the same line.'
|
||||||
|
|
||||||
$GREP 'delete[ ]*[(][^(]*[)];' $tmp &&
|
$GREP 'delete[ ]*[(][^(]*[)];' $tmp &&
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,6 @@
|
||||||
#define trace while (0) std::clog
|
#define trace while (0) std::clog
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ltlast/atomic_prop.hh"
|
|
||||||
#include "ltlast/constant.hh"
|
|
||||||
#include "taexplicit.hh"
|
#include "taexplicit.hh"
|
||||||
#include "twa/formula2bdd.hh"
|
#include "twa/formula2bdd.hh"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "ltlast/atomic_prop.hh"
|
|
||||||
#include "ltlast/constant.hh"
|
|
||||||
#include "tgtaexplicit.hh"
|
#include "tgtaexplicit.hh"
|
||||||
#include "twa/formula2bdd.hh"
|
#include "twa/formula2bdd.hh"
|
||||||
#include "twa/bddprint.hh"
|
#include "twa/bddprint.hh"
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue