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
|
||||
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)
|
||||
|
||||
* The CGI script for LTL translation offers a HOA download link
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include "twaalgos/stutter.hh"
|
||||
#include "twaalgos/dupexp.hh"
|
||||
#include "twaalgos/stats.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlvisit/apcollect.hh"
|
||||
#include "ltlvisit/length.hh"
|
||||
#include "misc/timer.hh"
|
||||
|
|
@ -64,14 +63,10 @@ namespace
|
|||
}
|
||||
|
||||
int
|
||||
process_formula(const spot::ltl::formula* f,
|
||||
const char*, int)
|
||||
process_formula(spot::ltl::formula f, 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 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);
|
||||
bdd apdict = spot::ltl::atomic_prop_collect_as_bdd(f, a);
|
||||
|
||||
|
|
@ -103,9 +98,6 @@ namespace
|
|||
prev = res;
|
||||
}
|
||||
std::cout << prev << '\n';
|
||||
|
||||
f->destroy();
|
||||
nf->destroy();
|
||||
delete ap;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,5 @@ main(int argc, char** argv)
|
|||
break;
|
||||
}
|
||||
dict->unregister_all_my_variables(&ap);
|
||||
spot::ltl::destroy_atomic_prop_set(ap);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,10 +72,9 @@ exceptions.
|
|||
int main()
|
||||
{
|
||||
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_spin_ltl(std::cout, f, true) << '\n';
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
#+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
|
||||
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
|
||||
the potential formulas (like =f= or =t=) that have different meanings
|
||||
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";
|
||||
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 (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
print_latex_psl(std::cout, f) << '\n';
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
|
@ -165,14 +153,14 @@ with the "fixed" formula if you wish. Here is an example:
|
|||
{
|
||||
std::string input = "(a U b))";
|
||||
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
|
||||
// show the output of std::cout in this documentation.
|
||||
(void) spot::ltl::format_parse_errors(std::cout, input, pel);
|
||||
if (f == nullptr)
|
||||
return 1;
|
||||
print_latex_psl(std::cout, f) << '\n';
|
||||
f->destroy();
|
||||
std::cout << "Parsed formula: ";
|
||||
print_psl(std::cout, f) << '\n';
|
||||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
|
@ -186,7 +174,7 @@ with the "fixed" formula if you wish. Here is an example:
|
|||
: ^
|
||||
: ignoring trailing garbage
|
||||
:
|
||||
: a \U b
|
||||
: Parsed formula: a U b
|
||||
|
||||
|
||||
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";
|
||||
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 (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
print_lbt_ltl(std::cout, f) << '\n';
|
||||
print_spin_ltl(std::cout, f, true) << '\n';
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
#+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))";
|
||||
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 (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
print_spin_ltl(std::cout, f) << '\n';
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
#+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))";
|
||||
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 (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
if (!f->is_ltl_formula())
|
||||
if (!f.is_ltl_formula())
|
||||
{
|
||||
f->destroy();
|
||||
std::cerr << "Only LTL formulas are supported.\n";
|
||||
return 1;
|
||||
}
|
||||
print_spin_ltl(std::cout, f) << '\n';
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
#+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
|
||||
(maybe because it was carefully chosen...):
|
||||
|
||||
#+BEGIN_SRC C++ :results verbatim :exports code
|
||||
#+BEGIN_SRC C++ :results verbatim :exports both
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#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))";
|
||||
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 (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
if (!f->is_ltl_formula())
|
||||
if (!f.is_ltl_formula())
|
||||
{
|
||||
spot::ltl::ltl_simplifier simp;
|
||||
const formula* g = simp.simplify(f);
|
||||
f->destroy();
|
||||
f = g;
|
||||
f = simp.simplify(f);
|
||||
}
|
||||
if (!f->is_ltl_formula())
|
||||
if (!f.is_ltl_formula())
|
||||
{
|
||||
f->destroy();
|
||||
std::cerr << "Only LTL formulas are supported.\n";
|
||||
return 1;
|
||||
}
|
||||
print_spin_ltl(std::cout, f) << '\n';
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ ltlfilt -ps --relabel=pnn --define -f '"Proc@Here" U ("var > 10" | "var < 4")'
|
|||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: #define p0 ((Proc@Here))
|
||||
: #define p1 ((var < 4))
|
||||
: #define p2 ((var > 10))
|
||||
: #define p0 (Proc@Here)
|
||||
: #define p1 (var < 4)
|
||||
: #define p2 (var > 10)
|
||||
: (p0) U ((p1) || (p2))
|
||||
|
||||
When is this output interesting, you may ask? It is useful for
|
||||
|
|
@ -34,9 +34,9 @@ rm tmp.defs tmp.ltl
|
|||
|
||||
#+RESULTS:
|
||||
#+begin_example
|
||||
#define p0 ((Proc@Here))
|
||||
#define p1 ((var < 4))
|
||||
#define p2 ((var > 10))
|
||||
#define p0 (Proc@Here)
|
||||
#define p1 (var < 4)
|
||||
#define p2 (var > 10)
|
||||
never { /* (p0) U ((p1) || (p2))
|
||||
*/
|
||||
T0_init:
|
||||
|
|
@ -88,32 +88,26 @@ destructor.
|
|||
{
|
||||
std::string input = "\"Proc@Here\" U (\"var > 10\" | \"var < 4\")";
|
||||
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 (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
std::cout << "#define ";
|
||||
print_psl(std::cout, i.first) << " (";
|
||||
print_spin_ltl(std::cout, i.second, true) << ")\n";
|
||||
}
|
||||
print_spin_ltl(std::cout, g, true) << '\n';
|
||||
g->destroy();
|
||||
f->destroy();
|
||||
print_spin_ltl(std::cout, f, true) << '\n';
|
||||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: #define p0 ((Proc@Here))
|
||||
: #define p1 ((var < 4))
|
||||
: #define p2 ((var > 10))
|
||||
: #define p0 (Proc@Here)
|
||||
: #define p1 (var < 4)
|
||||
: #define p2 (var > 10)
|
||||
: (p0) U ((p1) || (p2))
|
||||
|
||||
|
||||
|
|
@ -135,7 +129,7 @@ ltlfilt -ps --relabel-bool=pnn --define -f '"Proc@Here" U ("var > 10" | "var < 4
|
|||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: #define p0 ((Proc@Here))
|
||||
: #define p0 (Proc@Here)
|
||||
: #define p1 ((var < 4) || (var > 10))
|
||||
: (p0) U (p1)
|
||||
|
||||
|
|
@ -151,8 +145,8 @@ ltlfilt -ps --relabel-bool=pnn --define -f 'a U (a & b)'
|
|||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: #define p0 ((a))
|
||||
: #define p1 ((b))
|
||||
: #define p0 (a)
|
||||
: #define p1 (b)
|
||||
: (p0) U ((p0) && (p1))
|
||||
|
||||
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";
|
||||
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 (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
spot::translator trans;
|
||||
trans.set_type(spot::postprocessor::BA);
|
||||
spot::twa_graph_ptr aut = trans.run(f);
|
||||
print_never_claim(std::cout, aut) << '\n';
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#+HTML_LINK_UP: tut.html
|
||||
|
||||
This example demonstrates how to create an automaton in C++, and then print it.
|
||||
The interface
|
||||
|
||||
#+BEGIN_SRC C++ :results verbatim :exports both
|
||||
#include <iostream>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2011, 2012, 2014 Laboratoire de Recherche et Développement
|
||||
// de l'Epita (LRDE)
|
||||
// Copyright (C) 2011, 2012, 2014, 2015 Laboratoire de Recherche et
|
||||
// Développement de l'Epita (LRDE)
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
//
|
||||
|
|
@ -326,7 +326,7 @@ namespace spot
|
|||
convert_aps(const ltl::atomic_prop_set* aps,
|
||||
const spins_interface* d,
|
||||
bdd_dict_ptr dict,
|
||||
const ltl::formula* dead,
|
||||
ltl::formula dead,
|
||||
prop_set& out)
|
||||
{
|
||||
int errors = 0;
|
||||
|
|
@ -359,7 +359,7 @@ namespace spot
|
|||
if (*ap == dead)
|
||||
continue;
|
||||
|
||||
std::string str = (*ap)->name();
|
||||
const std::string& str = ap->ap_name();
|
||||
const char* s = str.c_str();
|
||||
|
||||
// Skip any leading blank.
|
||||
|
|
@ -602,7 +602,7 @@ namespace spot
|
|||
public:
|
||||
|
||||
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)
|
||||
: kripke(dict),
|
||||
d_(d),
|
||||
|
|
@ -646,12 +646,12 @@ namespace spot
|
|||
// appropriately. ALIVE_PROP is the bdd that should be ANDed
|
||||
// to all transitions leaving a live state, while DEAD_PROP should
|
||||
// be ANDed to all transitions leaving a dead state.
|
||||
if (dead == ltl::constant::false_instance())
|
||||
if (dead.is_false())
|
||||
{
|
||||
alive_prop = bddtrue;
|
||||
dead_prop = bddfalse;
|
||||
}
|
||||
else if (dead == ltl::constant::true_instance())
|
||||
else if (dead.is_true())
|
||||
{
|
||||
alive_prop = bddtrue;
|
||||
dead_prop = bddtrue;
|
||||
|
|
@ -1016,7 +1016,7 @@ namespace spot
|
|||
kripke_ptr
|
||||
load_ltsmin(const std::string& file_arg, const bdd_dict_ptr& dict,
|
||||
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;
|
||||
if (file_arg.find_first_of("/\\") != std::string::npos)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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)
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "kripke/kripke.hh"
|
||||
#include "ltlvisit/apcollect.hh"
|
||||
#include "ltlast/constant.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -59,6 +58,6 @@ namespace spot
|
|||
SPOT_API kripke_ptr
|
||||
load_ltsmin(const std::string& file, const bdd_dict_ptr& dict,
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "ltsmin.hh"
|
||||
#include "twaalgos/dot.hh"
|
||||
#include "ltlenv/defaultenv.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlparse/public.hh"
|
||||
#include "twaalgos/translate.hh"
|
||||
#include "twaalgos/emptiness.hh"
|
||||
|
|
@ -163,16 +162,16 @@ checked_main(int argc, char **argv)
|
|||
spot::emptiness_check_instantiator_ptr echeck_inst = nullptr;
|
||||
int exit_code = 0;
|
||||
spot::postprocessor post;
|
||||
const spot::ltl::formula* deadf = nullptr;
|
||||
const spot::ltl::formula* f = nullptr;
|
||||
spot::ltl::formula deadf = nullptr;
|
||||
spot::ltl::formula f = nullptr;
|
||||
|
||||
if (!dead || !strcasecmp(dead, "true"))
|
||||
{
|
||||
deadf = spot::ltl::constant::true_instance();
|
||||
deadf = spot::ltl::formula::tt();
|
||||
}
|
||||
else if (!strcasecmp(dead, "false"))
|
||||
{
|
||||
deadf = spot::ltl::constant::false_instance();
|
||||
deadf = spot::ltl::formula::ff();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -355,11 +354,6 @@ checked_main(int argc, char **argv)
|
|||
}
|
||||
|
||||
safe_exit:
|
||||
if (f)
|
||||
f->destroy();
|
||||
|
||||
deadf->destroy();
|
||||
|
||||
if (use_timer)
|
||||
tm.print(std::cout);
|
||||
tm.reset_all(); // This helps valgrind.
|
||||
|
|
@ -372,15 +366,6 @@ main(int argc, char **argv)
|
|||
auto exit_code = checked_main(argc, argv);
|
||||
|
||||
// Additional checks to debug reference counts in formulas.
|
||||
spot::ltl::atomic_prop::dump_instances(std::cerr);
|
||||
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);
|
||||
assert(spot::ltl::fnode::instances_check());
|
||||
exit(exit_code);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ namespace
|
|||
}
|
||||
|
||||
int
|
||||
process_formula(const spot::ltl::formula*, const char*, int)
|
||||
process_formula(spot::ltl::formula, const char*, int)
|
||||
{
|
||||
SPOT_UNREACHABLE();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ automaton_printer::automaton_printer(stat_style input)
|
|||
|
||||
void
|
||||
automaton_printer::print(const spot::twa_graph_ptr& aut,
|
||||
const spot::ltl::formula* f,
|
||||
spot::ltl::formula f,
|
||||
// Input location for errors and statistics.
|
||||
const char* filename,
|
||||
int loc,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public:
|
|||
std::ostream&
|
||||
print(const spot::const_parsed_aut_ptr& haut,
|
||||
const spot::const_twa_graph_ptr& aut,
|
||||
const spot::ltl::formula* f,
|
||||
spot::ltl::formula f,
|
||||
const char* filename, int loc, double run_time)
|
||||
{
|
||||
filename_ = filename ? filename : "";
|
||||
|
|
@ -225,7 +225,7 @@ public:
|
|||
|
||||
void
|
||||
print(const spot::twa_graph_ptr& aut,
|
||||
const spot::ltl::formula* f = nullptr,
|
||||
spot::ltl::formula f = nullptr,
|
||||
// Input location for errors and statistics.
|
||||
const char* filename = nullptr,
|
||||
int loc = -1,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ parse_opt_finput(int key, char* arg, struct argp_state*)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const spot::ltl::formula*
|
||||
spot::ltl::formula
|
||||
parse_formula(const std::string& s, spot::ltl::parse_error_list& pel)
|
||||
{
|
||||
if (lbt_input)
|
||||
|
|
@ -108,15 +108,13 @@ job_processor::process_string(const std::string& input,
|
|||
int linenum)
|
||||
{
|
||||
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 (filename)
|
||||
error_at_line(0, 0, filename, linenum, "parse error:");
|
||||
spot::ltl::format_parse_errors(std::cerr, input, pel);
|
||||
if (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
return process_formula(f, filename, linenum);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Développement
|
||||
// de l'Epita (LRDE).
|
||||
// Copyright (C) 2012, 2013, 2015 Laboratoire de Recherche et
|
||||
// Développement de l'Epita (LRDE).
|
||||
//
|
||||
// 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);
|
||||
|
||||
const spot::ltl::formula*
|
||||
spot::ltl::formula
|
||||
parse_formula(const std::string& s, spot::ltl::parse_error_list& error_list);
|
||||
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ public:
|
|||
virtual ~job_processor();
|
||||
|
||||
virtual int
|
||||
process_formula(const spot::ltl::formula* f,
|
||||
process_formula(spot::ltl::formula f,
|
||||
const char* filename = 0, int linenum = 0) = 0;
|
||||
|
||||
virtual int
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ const struct argp output_argp = { options, parse_opt_output, 0, 0, 0, 0, 0 };
|
|||
|
||||
static
|
||||
void
|
||||
report_not_ltl(const spot::ltl::formula* f,
|
||||
report_not_ltl(spot::ltl::formula f,
|
||||
const char* filename, int linenum, const char* syn)
|
||||
{
|
||||
std::string s = spot::ltl::str_psl(f);
|
||||
|
|
@ -82,12 +82,12 @@ report_not_ltl(const spot::ltl::formula* f,
|
|||
|
||||
std::ostream&
|
||||
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)
|
||||
{
|
||||
case lbt_output:
|
||||
if (f->is_ltl_formula())
|
||||
if (f.is_ltl_formula())
|
||||
spot::ltl::print_lbt_ltl(out, f);
|
||||
else
|
||||
report_not_ltl(f, filename, linenum, "LBT");
|
||||
|
|
@ -96,13 +96,13 @@ stream_formula(std::ostream& out,
|
|||
spot::ltl::print_psl(out, f, full_parenth);
|
||||
break;
|
||||
case spin_output:
|
||||
if (f->is_ltl_formula())
|
||||
if (f.is_ltl_formula())
|
||||
spot::ltl::print_spin_ltl(out, f, full_parenth);
|
||||
else
|
||||
report_not_ltl(f, filename, linenum, "Spin");
|
||||
break;
|
||||
case wring_output:
|
||||
if (f->is_ltl_formula())
|
||||
if (f.is_ltl_formula())
|
||||
spot::ltl::print_wring_ltl(out, f);
|
||||
else
|
||||
report_not_ltl(f, filename, linenum, "Wring");
|
||||
|
|
@ -122,7 +122,7 @@ stream_formula(std::ostream& out,
|
|||
|
||||
static void
|
||||
stream_escapable_formula(std::ostream& os,
|
||||
const spot::ltl::formula* f,
|
||||
spot::ltl::formula f,
|
||||
const char* filename, int linenum)
|
||||
{
|
||||
if (escape_csv)
|
||||
|
|
@ -144,7 +144,7 @@ namespace
|
|||
{
|
||||
struct formula_with_location
|
||||
{
|
||||
const spot::ltl::formula* f;
|
||||
spot::ltl::formula f;
|
||||
const char* filename;
|
||||
int line;
|
||||
const char* prefix;
|
||||
|
|
@ -258,7 +258,7 @@ parse_opt_output(int key, char* arg, struct argp_state*)
|
|||
|
||||
static void
|
||||
output_formula(std::ostream& out,
|
||||
const spot::ltl::formula* f,
|
||||
spot::ltl::formula f,
|
||||
const char* filename = nullptr, int linenum = 0,
|
||||
const char* prefix = nullptr, const char* suffix = nullptr)
|
||||
{
|
||||
|
|
@ -284,7 +284,7 @@ void
|
|||
}
|
||||
|
||||
void
|
||||
output_formula_checked(const spot::ltl::formula* f,
|
||||
output_formula_checked(spot::ltl::formula f,
|
||||
const char* filename, int linenum,
|
||||
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
|
||||
std::ostream&
|
||||
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* prefix = 0, const char* suffix = 0);
|
||||
|
||||
|
||||
class printable_formula:
|
||||
public spot::printable_value<const spot::ltl::formula*>
|
||||
public spot::printable_value<spot::ltl::formula>
|
||||
{
|
||||
public:
|
||||
printable_formula&
|
||||
operator=(const spot::ltl::formula* new_val)
|
||||
operator=(spot::ltl::formula new_val)
|
||||
{
|
||||
val_ = new_val;
|
||||
return *this;
|
||||
|
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
std::ostream&
|
||||
print(const spot::const_twa_graph_ptr& aut,
|
||||
const spot::ltl::formula* f = 0,
|
||||
spot::ltl::formula f = 0,
|
||||
double run_time = -1.)
|
||||
{
|
||||
formula_ = f;
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ translator_runner::formula() const
|
|||
}
|
||||
|
||||
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'))
|
||||
string_ltl_spot = spot::ltl::str_psl(f, true);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public:
|
|||
bool no_output_allowed = false);
|
||||
void string_to_tmp(std::string& str, unsigned n, std::string& tmpname);
|
||||
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
|
||||
process_formula(const spot::ltl::formula*, const char*, int)
|
||||
process_formula(spot::ltl::formula, const char*, int)
|
||||
{
|
||||
SPOT_UNREACHABLE();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,8 +86,7 @@
|
|||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlenv/defaultenv.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
#include "ltlvisit/relabel.hh"
|
||||
|
||||
using namespace spot;
|
||||
|
|
@ -270,37 +269,31 @@ parse_opt(int key, char* arg, struct argp_state*)
|
|||
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 F_(x) spot::ltl::unop::instance(spot::ltl::unop::F, (x))
|
||||
#define X_(x) spot::ltl::unop::instance(spot::ltl::unop::X, (x))
|
||||
#define Not_(x) spot::ltl::unop::instance(spot::ltl::unop::Not, (x))
|
||||
#define Implies_(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))
|
||||
#define Implies_(x, y) formula::Implies((x), (y))
|
||||
#define Equiv_(x, y) formula::Equiv((x), (y))
|
||||
#define And_(x, y) formula::And({(x), (y)})
|
||||
#define Or_(x, y) formula::Or({(x), (y)})
|
||||
#define U_(x, y) formula::U((x), (y))
|
||||
|
||||
// F(p_1 & F(p_2 & F(p_3 & ... F(p_n))))
|
||||
static const formula*
|
||||
static formula
|
||||
E_n(std::string name, int n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return constant::true_instance();
|
||||
return formula::tt();
|
||||
|
||||
const formula* result = 0;
|
||||
formula result = nullptr;
|
||||
|
||||
for (; n > 0; --n)
|
||||
{
|
||||
std::ostringstream p;
|
||||
p << name << n;
|
||||
const formula* f = env.require(p.str());
|
||||
formula f = formula::ap(p.str());
|
||||
if (result)
|
||||
result = And_(f, result);
|
||||
else
|
||||
|
|
@ -311,43 +304,43 @@ E_n(std::string name, int n)
|
|||
}
|
||||
|
||||
// p & X(p & X(p & ... X(p)))
|
||||
static const formula*
|
||||
static formula
|
||||
phi_n(std::string name, int n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return constant::true_instance();
|
||||
return formula::tt();
|
||||
|
||||
const formula* result = 0;
|
||||
const formula* p = env.require(name);
|
||||
formula result = nullptr;
|
||||
formula p = formula::ap(name);
|
||||
for (; n > 0; --n)
|
||||
{
|
||||
if (result)
|
||||
result = And_(p->clone(), X_(result));
|
||||
result = And_(p, X_(result));
|
||||
else
|
||||
result = p;
|
||||
}
|
||||
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)
|
||||
static const formula*
|
||||
static formula
|
||||
phi_prime_n(std::string name, int n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return constant::true_instance();
|
||||
return formula::tt();
|
||||
|
||||
const formula* result = 0;
|
||||
const formula* p = env.require(name);
|
||||
formula result = nullptr;
|
||||
formula p = formula::ap(name);
|
||||
for (; n > 0; --n)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
p = X_(p->clone());
|
||||
p = X_(p);
|
||||
result = And_(result, p);
|
||||
}
|
||||
else
|
||||
|
|
@ -358,7 +351,7 @@ phi_prime_n(std::string name, int n)
|
|||
return result;
|
||||
}
|
||||
|
||||
static const formula*
|
||||
static formula
|
||||
N_prime_n(std::string name, int 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 == false
|
||||
static const formula*
|
||||
static formula
|
||||
GF_n(std::string name, int n, bool conj = true)
|
||||
{
|
||||
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)
|
||||
{
|
||||
std::ostringstream p;
|
||||
p << name << i;
|
||||
const formula* f = G_(F_(env.require(p.str())));
|
||||
formula f = G_(F_(formula::ap(p.str())));
|
||||
|
||||
if (result)
|
||||
result = multop::instance(op, f, result);
|
||||
result = formula::multop(o, {f, result});
|
||||
else
|
||||
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 == true
|
||||
static const formula*
|
||||
static formula
|
||||
FG_n(std::string name, int n, bool conj = false)
|
||||
{
|
||||
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)
|
||||
{
|
||||
std::ostringstream p;
|
||||
p << name << i;
|
||||
const formula* f = F_(G_(env.require(p.str())));
|
||||
formula f = F_(G_(formula::ap(p.str())));
|
||||
|
||||
if (result)
|
||||
result = multop::instance(op, f, result);
|
||||
result = formula::multop(o, {f, result});
|
||||
else
|
||||
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 == true
|
||||
static const formula*
|
||||
bin_n(std::string name, int n,
|
||||
binop::type op, bool right_assoc = false)
|
||||
static formula
|
||||
bin_n(std::string name, int n, op o, bool right_assoc = false)
|
||||
{
|
||||
if (n <= 0)
|
||||
n = 1;
|
||||
|
||||
const formula* result = 0;
|
||||
formula result = nullptr;
|
||||
|
||||
for (int i = 1; i <= n; ++i)
|
||||
{
|
||||
std::ostringstream p;
|
||||
p << name << (right_assoc ? (n + 1 - i) : i);
|
||||
const formula* f = env.require(p.str());
|
||||
formula f = formula::ap(p.str());
|
||||
if (!result)
|
||||
result = f;
|
||||
else if (right_assoc)
|
||||
result = binop::instance(op, f, result);
|
||||
result = formula::binop(o, f, result);
|
||||
else
|
||||
result = binop::instance(op, result, f);
|
||||
result = formula::binop(o, result, f);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// (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)
|
||||
{
|
||||
if (n <= 0)
|
||||
return constant::true_instance();
|
||||
return formula::tt();
|
||||
|
||||
const formula* pi;
|
||||
formula pi;
|
||||
|
||||
{
|
||||
std::ostringstream p;
|
||||
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)
|
||||
{
|
||||
const formula* gf = G_(F_(pi));
|
||||
formula gf = G_(F_(pi));
|
||||
std::ostringstream p;
|
||||
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)
|
||||
result = And_(f, result);
|
||||
else
|
||||
result = f;
|
||||
}
|
||||
pi->destroy();
|
||||
return result;
|
||||
}
|
||||
|
||||
// (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)
|
||||
{
|
||||
if (n <= 0)
|
||||
return constant::true_instance();
|
||||
return formula::tt();
|
||||
|
||||
const formula* pi;
|
||||
formula pi;
|
||||
|
||||
{
|
||||
std::ostringstream p;
|
||||
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)
|
||||
{
|
||||
const formula* f = F_(pi);
|
||||
formula f = F_(pi);
|
||||
|
||||
std::ostringstream p;
|
||||
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);
|
||||
|
||||
|
|
@ -514,31 +505,29 @@ Q_n(std::string name, int n)
|
|||
else
|
||||
result = f;
|
||||
}
|
||||
pi->destroy();
|
||||
return result;
|
||||
}
|
||||
|
||||
// OP(p1) | OP(p2) | ... | OP(Pn) if conj == false
|
||||
// OP(p1) & OP(p2) & ... & OP(Pn) if conj == true
|
||||
static const formula*
|
||||
combunop_n(std::string name, int n,
|
||||
unop::type op, bool conj = false)
|
||||
static formula
|
||||
combunop_n(std::string name, int n, op o, bool conj = false)
|
||||
{
|
||||
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)
|
||||
{
|
||||
std::ostringstream p;
|
||||
p << name << i;
|
||||
const formula* f = unop::instance(op, env.require(p.str()));
|
||||
formula f = formula::unop(o, formula::ap(p.str()));
|
||||
|
||||
if (result)
|
||||
result = multop::instance(cop, f, result);
|
||||
result = formula::multop(cop, {f, result});
|
||||
else
|
||||
result = f;
|
||||
}
|
||||
|
|
@ -547,21 +536,21 @@ combunop_n(std::string name, int n,
|
|||
|
||||
// !((GF(p1)&GF(p2)&...&GF(pn))->G(q -> F(r)))
|
||||
// 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)
|
||||
{
|
||||
const formula* fair = GF_n(p, n);
|
||||
const formula* resp = G_(Implies_(env.require(q), F_(env.require(r))));
|
||||
formula fair = GF_n(p, n);
|
||||
formula resp = G_(Implies_(formula::ap(q), F_(formula::ap(r))));
|
||||
return Not_(Implies_(fair, resp));
|
||||
}
|
||||
|
||||
|
||||
// Builds X(X(...X(p))) with n occurrences of X.
|
||||
static const formula*
|
||||
X_n(const formula* p, int n)
|
||||
static formula
|
||||
X_n(formula p, int n)
|
||||
{
|
||||
assert(n >= 0);
|
||||
const formula* res = p;
|
||||
formula res = p;
|
||||
while (n--)
|
||||
res = X_(res);
|
||||
return res;
|
||||
|
|
@ -569,214 +558,174 @@ X_n(const formula* p, int n)
|
|||
|
||||
// Based on LTLcounter.pl from Kristin Rozier.
|
||||
// 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)
|
||||
{
|
||||
const formula* b = env.require(bit);
|
||||
const formula* neg_b = Not_(b);
|
||||
const formula* m = env.require(marker);
|
||||
const formula* neg_m = Not_(m); // to destroy
|
||||
formula b = formula::ap(bit);
|
||||
formula neg_b = Not_(b);
|
||||
formula m = formula::ap(marker);
|
||||
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,
|
||||
// n-1 "0", etc.
|
||||
if (!linear)
|
||||
{
|
||||
// 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)
|
||||
(*v)[i] = X_n(neg_m->clone(), i + 1);
|
||||
(*v)[n - 1] = X_n(m->clone(), n);
|
||||
(*res)[0] = And_(m->clone(),
|
||||
G_(Implies_(m->clone(),
|
||||
multop::instance(multop::And, v))));
|
||||
v[i] = X_n(neg_m, i + 1);
|
||||
v[n - 1] = X_n(m, n);
|
||||
res[0] = And_(m, G_(Implies_(m, formula::And(std::move(v)))));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
p = And_(neg_m->clone(), X_(p));
|
||||
(*res)[0] = And_(m->clone(),
|
||||
G_(Implies_(m->clone(), X_(p))));
|
||||
p = And_(neg_m, X_(p));
|
||||
res[0] = And_(m, G_(Implies_(m, X_(p))));
|
||||
}
|
||||
|
||||
// All bits are initially zero.
|
||||
if (!linear)
|
||||
{
|
||||
// !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)
|
||||
(*v2)[i] = X_n(neg_b->clone(), i);
|
||||
(*res)[1] = multop::instance(multop::And, v2);
|
||||
v2[i] = X_n(neg_b, i);
|
||||
res[1] = formula::And(std::move(v2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// !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)
|
||||
p = And_(neg_b->clone(), X_(p));
|
||||
(*res)[1] = p;
|
||||
p = And_(neg_b, X_(p));
|
||||
res[1] = p;
|
||||
}
|
||||
|
||||
#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,
|
||||
// and other bits stay the same.
|
||||
const formula* Xnm1_b = X_n(b->clone(), n - 1);
|
||||
const formula* Xn_b = X_(Xnm1_b); // to destroy
|
||||
(*res)[2] =
|
||||
G_(Implies_(And_(m->clone(), neg_b->clone()),
|
||||
AndX_(Xnm1_b->clone(), U_(And_(Not_(m->clone()),
|
||||
Equiv_(b->clone(),
|
||||
Xn_b->clone())),
|
||||
m->clone()))));
|
||||
formula Xnm1_b = X_n(b, n - 1);
|
||||
formula Xn_b = X_(Xnm1_b);
|
||||
res[2] = G_(Implies_(And_(m, neg_b),
|
||||
AndX_(Xnm1_b, U_(And_(Not_(m), Equiv_(b, Xn_b)), m))));
|
||||
|
||||
// From the least significant bit to the first 0, all the bits
|
||||
// are flipped on the next value. Remaining bits are identical.
|
||||
const formula* Xnm1_negb = X_n(neg_b, n - 1);
|
||||
const formula* Xn_negb = X_(Xnm1_negb); // to destroy
|
||||
(*res)[3] =
|
||||
G_(Implies_(And_(m->clone(), b->clone()),
|
||||
AndX_(Xnm1_negb->clone(),
|
||||
U_(And_(And_(b->clone(), neg_m->clone()),
|
||||
Xn_negb->clone()),
|
||||
Or_(m->clone(),
|
||||
And_(And_(neg_m->clone(),
|
||||
neg_b->clone()),
|
||||
AndX_(Xnm1_b->clone(),
|
||||
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);
|
||||
formula Xnm1_negb = X_n(neg_b, n - 1);
|
||||
formula Xn_negb = X_(Xnm1_negb);
|
||||
res[3] = G_(Implies_(And_(m, b),
|
||||
AndX_(Xnm1_negb,
|
||||
U_(And_(And_(b, neg_m), Xn_negb),
|
||||
Or_(m, And_(And_(neg_m, neg_b),
|
||||
AndX_(Xnm1_b,
|
||||
U_(And_(neg_m,
|
||||
Equiv_(b, Xn_b)),
|
||||
m))))))));
|
||||
return formula::And(std::move(res));
|
||||
}
|
||||
|
||||
static const formula*
|
||||
static formula
|
||||
ltl_counter_carry(std::string bit, std::string marker,
|
||||
std::string carry, int n, bool linear)
|
||||
{
|
||||
const formula* b = env.require(bit);
|
||||
const formula* neg_b = Not_(b);
|
||||
const formula* m = env.require(marker);
|
||||
const formula* neg_m = Not_(m); // to destroy
|
||||
const formula* c = env.require(carry);
|
||||
const formula* neg_c = Not_(c); // to destroy
|
||||
formula b = formula::ap(bit);
|
||||
formula neg_b = Not_(b);
|
||||
formula m = formula::ap(marker);
|
||||
formula neg_m = Not_(m);
|
||||
formula c = formula::ap(carry);
|
||||
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,
|
||||
// n-1 "0", etc.
|
||||
if (!linear)
|
||||
{
|
||||
// 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)
|
||||
(*v)[i] = X_n(neg_m->clone(), i + 1);
|
||||
(*v)[n - 1] = X_n(m->clone(), n);
|
||||
(*res)[0] = And_(m->clone(),
|
||||
G_(Implies_(m->clone(),
|
||||
multop::instance(multop::And, v))));
|
||||
v[i] = X_n(neg_m, i + 1);
|
||||
v[n - 1] = X_n(m, n);
|
||||
res[0] = And_(m, G_(Implies_(m, formula::And(std::move(v)))));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
p = And_(neg_m->clone(), X_(p));
|
||||
(*res)[0] = And_(m->clone(),
|
||||
G_(Implies_(m->clone(), X_(p))));
|
||||
p = And_(neg_m, X_(p));
|
||||
res[0] = And_(m, G_(Implies_(m, X_(p))));
|
||||
}
|
||||
|
||||
// All bits are initially zero.
|
||||
if (!linear)
|
||||
{
|
||||
// !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)
|
||||
(*v2)[i] = X_n(neg_b->clone(), i);
|
||||
(*res)[1] = multop::instance(multop::And, v2);
|
||||
v2[i] = X_n(neg_b, i);
|
||||
res[1] = formula::And(std::move(v2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// !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)
|
||||
p = And_(neg_b->clone(), X_(p));
|
||||
(*res)[1] = p;
|
||||
p = And_(neg_b, X_(p));
|
||||
res[1] = p;
|
||||
}
|
||||
|
||||
const formula* Xn_b = X_n(b->clone(), n); // to destroy
|
||||
const formula* Xn_negb = X_n(neg_b, n); // to destroy
|
||||
formula Xn_b = X_n(b, n);
|
||||
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.
|
||||
(*res)[2] = G_(Implies_(And_(m->clone(), neg_b->clone()),
|
||||
And_(neg_c->clone(), Xn_b->clone())));
|
||||
res[2] = G_(Implies_(And_(m, neg_b), And_(neg_c, Xn_b)));
|
||||
|
||||
// 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()),
|
||||
And_(c->clone(), Xn_negb->clone())));
|
||||
res[3] = G_(Implies_(And_(m, b), And_(c, Xn_negb)));
|
||||
|
||||
if (!linear)
|
||||
{
|
||||
// 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())),
|
||||
And_(X_(Not_(c->clone())),
|
||||
Equiv_(X_(b->clone()),
|
||||
X_(Xn_b->clone())))));
|
||||
res[4] = G_(Implies_(And_(neg_c, X_(neg_m)),
|
||||
And_(X_(Not_(c)), Equiv_(X_(b), X_(Xn_b)))));
|
||||
|
||||
// If there's a carry, then add one: flip the bits of b and
|
||||
// adjust the carry.
|
||||
(*res)[5] = G_(Implies_(c->clone(),
|
||||
And_(Implies_(X_(neg_b->clone()),
|
||||
And_(X_(neg_c->clone()),
|
||||
X_(Xn_b->clone()))),
|
||||
Implies_(X_(b->clone()),
|
||||
And_(X_(c->clone()),
|
||||
X_(Xn_negb->clone()))))));
|
||||
res[5] = G_(Implies_(c, And_(Implies_(X_(neg_b),
|
||||
And_(X_(neg_c), X_(Xn_b))),
|
||||
Implies_(X_(b),
|
||||
And_(X_(c), X_(Xn_negb))))));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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())),
|
||||
X_(And_(Not_(c->clone()),
|
||||
Equiv_(b->clone(),
|
||||
Xn_b->clone())))));
|
||||
|
||||
res[4] = G_(Implies_(And_(neg_c, X_(neg_m)),
|
||||
X_(And_(Not_(c), Equiv_(b, Xn_b)))));
|
||||
// If there's a carry, then add one: flip the bits of b and
|
||||
// adjust the carry.
|
||||
(*res)[5] = G_(Implies_(c->clone(),
|
||||
X_(And_(Implies_(neg_b->clone(),
|
||||
And_(neg_c->clone(),
|
||||
Xn_b->clone())),
|
||||
Implies_(b->clone(),
|
||||
And_(c->clone(),
|
||||
Xn_negb->clone()))))));
|
||||
res[5] = G_(Implies_(c, X_(And_(Implies_(neg_b, And_(neg_c, Xn_b)),
|
||||
Implies_(b, And_(c, Xn_negb))))));
|
||||
}
|
||||
|
||||
neg_m->destroy();
|
||||
neg_c->destroy();
|
||||
Xn_b->destroy();
|
||||
Xn_negb->destroy();
|
||||
|
||||
return multop::instance(multop::And, res);
|
||||
return formula::And(std::move(res));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
output_pattern(int pattern, int n)
|
||||
{
|
||||
const formula* f = 0;
|
||||
formula f = nullptr;
|
||||
switch (pattern)
|
||||
{
|
||||
// Keep this alphabetically-ordered!
|
||||
case OPT_AND_F:
|
||||
f = combunop_n("p", n, unop::F, true);
|
||||
f = combunop_n("p", n, op::F, true);
|
||||
break;
|
||||
case OPT_AND_FG:
|
||||
f = FG_n("p", n, true);
|
||||
|
|
@ -785,13 +734,13 @@ output_pattern(int pattern, int n)
|
|||
f = GF_n("p", n, true);
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
case OPT_GH_Q:
|
||||
f = Q_n("p", n);
|
||||
|
|
@ -806,16 +755,16 @@ output_pattern(int pattern, int n)
|
|||
f = FG_n("p", n, false);
|
||||
break;
|
||||
case OPT_OR_G:
|
||||
f = combunop_n("p", n, unop::G, false);
|
||||
f = combunop_n("p", n, op::G, false);
|
||||
break;
|
||||
case OPT_OR_GF:
|
||||
f = GF_n("p", n, false);
|
||||
break;
|
||||
case OPT_R_LEFT:
|
||||
f = bin_n("p", n, binop::R, false);
|
||||
f = bin_n("p", n, op::R, false);
|
||||
break;
|
||||
case OPT_R_RIGHT:
|
||||
f = bin_n("p", n, binop::R, true);
|
||||
f = bin_n("p", n, op::R, true);
|
||||
break;
|
||||
case OPT_RV_COUNTER_CARRY:
|
||||
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);
|
||||
break;
|
||||
case OPT_U_LEFT:
|
||||
f = bin_n("p", n, binop::U, false);
|
||||
f = bin_n("p", n, op::U, false);
|
||||
break;
|
||||
case OPT_U_RIGHT:
|
||||
f = bin_n("p", n, binop::U, true);
|
||||
f = bin_n("p", n, op::U, true);
|
||||
break;
|
||||
default:
|
||||
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
|
||||
// in lbt's output.
|
||||
if (output_format == lbt_output && !f->has_lbt_atomic_props())
|
||||
{
|
||||
const spot::ltl::formula* r = spot::ltl::relabel(f, spot::ltl::Pnn);
|
||||
f->destroy();
|
||||
f = r;
|
||||
}
|
||||
if (output_format == lbt_output && !f.has_lbt_atomic_props())
|
||||
f = relabel(f, Pnn);
|
||||
|
||||
output_formula_checked(f, class_name[pattern - 1], n);
|
||||
f->destroy();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -138,14 +138,14 @@ namespace
|
|||
}
|
||||
|
||||
int
|
||||
process_formula(const spot::ltl::formula* f,
|
||||
process_formula(spot::ltl::formula f,
|
||||
const char* filename = 0, int linenum = 0)
|
||||
{
|
||||
// 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
|
||||
// future-proof.
|
||||
if (!f->is_psl_formula())
|
||||
if (!f.is_psl_formula())
|
||||
{
|
||||
std::string s = spot::ltl::str_psl(f);
|
||||
error_at_line(2, 0, filename, linenum,
|
||||
|
|
@ -159,7 +159,6 @@ namespace
|
|||
const double translation_time = sw.stop();
|
||||
|
||||
printer.print(aut, f, filename, linenum, translation_time, nullptr);
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -170,16 +170,16 @@ namespace
|
|||
}
|
||||
|
||||
int
|
||||
process_formula(const spot::ltl::formula* f,
|
||||
process_formula(spot::ltl::formula f,
|
||||
const char* filename = 0, int linenum = 0)
|
||||
{
|
||||
auto aut = trans.run(&f);
|
||||
|
||||
// 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
|
||||
// future-proof.
|
||||
if (!f->is_psl_formula())
|
||||
if (!f.is_psl_formula())
|
||||
{
|
||||
std::string s = spot::ltl::str_psl(f);
|
||||
error_at_line(2, 0, filename, linenum,
|
||||
|
|
@ -207,7 +207,6 @@ namespace
|
|||
tgta = spot::minimize_tgta(tgta);
|
||||
spot::print_dot(std::cout, tgta->get_ta());
|
||||
}
|
||||
f->destroy();
|
||||
flush_cout();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
#include "common_file.hh"
|
||||
#include "common_finput.hh"
|
||||
#include "parseaut/public.hh"
|
||||
#include "ltlast/unop.hh"
|
||||
#include "ltlvisit/print.hh"
|
||||
#include "ltlvisit/apcollect.hh"
|
||||
#include "ltlvisit/mutation.hh"
|
||||
|
|
@ -819,8 +818,7 @@ namespace
|
|||
}
|
||||
|
||||
typedef
|
||||
std::unordered_set<const spot::ltl::formula*,
|
||||
const spot::ptr_hash<const spot::ltl::formula> > fset_t;
|
||||
std::unordered_set<spot::ltl::formula> fset_t;
|
||||
|
||||
|
||||
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
|
||||
process_string(const std::string& input,
|
||||
const char* filename,
|
||||
int linenum)
|
||||
{
|
||||
spot::ltl::parse_error_list pel;
|
||||
const spot::ltl::formula* f = parse_formula(input, pel);
|
||||
spot::ltl::formula f = parse_formula(input, pel);
|
||||
|
||||
if (!f || !pel.empty())
|
||||
{
|
||||
if (filename)
|
||||
error_at_line(0, 0, filename, linenum, "parse error:");
|
||||
spot::ltl::format_parse_errors(std::cerr, input, pel);
|
||||
if (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
|
||||
f->clone();
|
||||
int res = process_formula(f, filename, linenum);
|
||||
|
||||
if (res && bogus_output)
|
||||
|
|
@ -867,7 +855,7 @@ namespace
|
|||
if (res && grind_output)
|
||||
{
|
||||
std::string bogus = input;
|
||||
std::vector<const spot::ltl::formula*> mutations;
|
||||
std::vector<spot::ltl::formula> mutations;
|
||||
unsigned mutation_count;
|
||||
unsigned mutation_max;
|
||||
while (res)
|
||||
|
|
@ -888,15 +876,12 @@ namespace
|
|||
{
|
||||
std::cerr << "Mutation " << mutation_count << '/'
|
||||
<< mutation_max << ": ";
|
||||
f->destroy();
|
||||
f = g->clone();
|
||||
res = process_formula(g->clone());
|
||||
f = g;
|
||||
res = process_formula(g);
|
||||
if (res)
|
||||
break;
|
||||
++mutation_count;
|
||||
}
|
||||
for (auto g: mutations)
|
||||
g->destroy();
|
||||
if (res)
|
||||
{
|
||||
if (lbt_input)
|
||||
|
|
@ -922,8 +907,6 @@ namespace
|
|||
std::cerr << ".\n\n";
|
||||
grind_output->ostream() << bogus << std::endl;
|
||||
}
|
||||
f->destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -954,20 +937,16 @@ namespace
|
|||
}
|
||||
|
||||
int
|
||||
process_formula(const spot::ltl::formula* f,
|
||||
process_formula(spot::ltl::formula f,
|
||||
const char* filename = 0, int linenum = 0)
|
||||
{
|
||||
static unsigned round = 0;
|
||||
|
||||
// If we need LBT atomic proposition in any of the input or
|
||||
// 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')))
|
||||
{
|
||||
const spot::ltl::formula* g = spot::ltl::relabel(f, spot::ltl::Pnn);
|
||||
f->destroy();
|
||||
f = g;
|
||||
}
|
||||
f = spot::ltl::relabel(f, spot::ltl::Pnn);
|
||||
|
||||
// ---------- Positive Formula ----------
|
||||
|
||||
|
|
@ -991,18 +970,13 @@ namespace
|
|||
// Make sure we do not translate the same formula twice.
|
||||
if (!allow_dups)
|
||||
{
|
||||
if (unique_set.insert(f).second)
|
||||
{
|
||||
f->clone();
|
||||
}
|
||||
else
|
||||
if (!unique_set.insert(f).second)
|
||||
{
|
||||
std::cerr
|
||||
<< ("warning: This formula or its negation has already"
|
||||
" been checked.\n Use --allow-dups if it "
|
||||
"should not be ignored.\n")
|
||||
<< std::endl;
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1053,12 +1027,11 @@ namespace
|
|||
nstats = &vstats[n + 1];
|
||||
nstats->resize(m);
|
||||
|
||||
const spot::ltl::formula* nf =
|
||||
spot::ltl::unop::instance(spot::ltl::unop::Not, f->clone());
|
||||
spot::ltl::formula nf = spot::ltl::formula::Not(f);
|
||||
|
||||
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
|
||||
// translated, otherwise that would mean that f had been
|
||||
// translated too and we would have caught it before.
|
||||
|
|
@ -1084,7 +1057,6 @@ namespace
|
|||
|| (!want_stats && is_deterministic(neg[n]))))
|
||||
comp_neg[n] = dtgba_complement(neg[n]);
|
||||
}
|
||||
nf->destroy();
|
||||
}
|
||||
|
||||
spot::cleanup_tmpfiles();
|
||||
|
|
@ -1171,7 +1143,6 @@ namespace
|
|||
}
|
||||
|
||||
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f);
|
||||
f->destroy();
|
||||
|
||||
if (want_stats)
|
||||
for (size_t i = 0; i < m; ++i)
|
||||
|
|
|
|||
|
|
@ -238,15 +238,13 @@ namespace
|
|||
int linenum)
|
||||
{
|
||||
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 (filename)
|
||||
error_at_line(0, 0, filename, linenum, "parse error:");
|
||||
spot::ltl::format_parse_errors(std::cerr, input, pel);
|
||||
if (f)
|
||||
f->destroy();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -257,22 +255,20 @@ namespace
|
|||
|
||||
|
||||
int
|
||||
process_formula(const spot::ltl::formula* f,
|
||||
process_formula(spot::ltl::formula f,
|
||||
const char* filename = 0, int linenum = 0)
|
||||
{
|
||||
std::unique_ptr<spot::ltl::relabeling_map> relmap;
|
||||
|
||||
// If atomic propositions are incompatible with one of the
|
||||
// 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')))
|
||||
|| (!f->has_spin_atomic_props() &&
|
||||
|| (!f.has_spin_atomic_props() &&
|
||||
(runner.has('s') || runner.has('S'))))
|
||||
{
|
||||
relmap.reset(new spot::ltl::relabeling_map);
|
||||
auto g = spot::ltl::relabel(f, spot::ltl::Pnn, relmap.get());
|
||||
f->destroy();
|
||||
f = g;
|
||||
f = spot::ltl::relabel(f, spot::ltl::Pnn, relmap.get());
|
||||
}
|
||||
|
||||
static unsigned round = 1;
|
||||
|
|
@ -297,7 +293,6 @@ namespace
|
|||
nullptr);
|
||||
};
|
||||
}
|
||||
f->destroy();
|
||||
spot::cleanup_tmpfiles();
|
||||
++round;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@
|
|||
#include "ltlvisit/apcollect.hh"
|
||||
#include "ltlvisit/exclusive.hh"
|
||||
#include "ltlvisit/print.hh"
|
||||
#include "ltlast/unop.hh"
|
||||
#include "ltlast/multop.hh"
|
||||
#include "twaalgos/ltl2tgba_fm.hh"
|
||||
#include "twaalgos/minimize.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::string unabbreviate;
|
||||
|
||||
static const spot::ltl::formula* implied_by = 0;
|
||||
static const spot::ltl::formula* imply = 0;
|
||||
static const spot::ltl::formula* equivalent_to = 0;
|
||||
static spot::ltl::formula implied_by = nullptr;
|
||||
static spot::ltl::formula imply = nullptr;
|
||||
static spot::ltl::formula equivalent_to = nullptr;
|
||||
|
||||
static const spot::ltl::formula*
|
||||
static spot::ltl::formula
|
||||
parse_formula_arg(const std::string& input)
|
||||
{
|
||||
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))
|
||||
error(2, 0, "parse error when parsing an argument");
|
||||
return f;
|
||||
|
|
@ -342,18 +340,16 @@ parse_opt(int key, char* arg, struct argp_state*)
|
|||
break;
|
||||
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
|
||||
implied_by =
|
||||
spot::ltl::multop::instance(spot::ltl::multop::Or, implied_by, i);
|
||||
implied_by = spot::ltl::formula::Or({implied_by, i});
|
||||
break;
|
||||
}
|
||||
case OPT_IMPLY:
|
||||
{
|
||||
// a→b∧a→c ≡ a→(b∧c)
|
||||
const spot::ltl::formula* i = parse_formula_arg(arg);
|
||||
imply =
|
||||
spot::ltl::multop::instance(spot::ltl::multop::And, imply, i);
|
||||
spot::ltl::formula i = parse_formula_arg(arg);
|
||||
imply = spot::ltl::formula::And({imply, i});
|
||||
break;
|
||||
}
|
||||
case OPT_LTL:
|
||||
|
|
@ -439,8 +435,7 @@ parse_opt(int key, char* arg, struct argp_state*)
|
|||
}
|
||||
|
||||
typedef
|
||||
std::unordered_set<const spot::ltl::formula*,
|
||||
const spot::ptr_hash<const spot::ltl::formula>> fset_t;
|
||||
std::unordered_set<spot::ltl::formula> fset_t;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -451,20 +446,6 @@ namespace
|
|||
fset_t unique_set;
|
||||
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)
|
||||
: simpl(simpl)
|
||||
{
|
||||
|
|
@ -475,7 +456,7 @@ namespace
|
|||
const char* filename = 0, int linenum = 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
@ -486,9 +467,6 @@ namespace
|
|||
spot::ltl::format_parse_errors(std::cerr, input, pel);
|
||||
}
|
||||
|
||||
if (f)
|
||||
f->destroy();
|
||||
|
||||
if (error_style == skip_errors)
|
||||
std::cout << input << std::endl;
|
||||
else
|
||||
|
|
@ -508,64 +486,44 @@ namespace
|
|||
}
|
||||
|
||||
int
|
||||
process_formula(const spot::ltl::formula* f,
|
||||
process_formula(spot::ltl::formula f,
|
||||
const char* filename = 0, int linenum = 0)
|
||||
{
|
||||
if (opt_max_count >= 0 && match_count >= opt_max_count)
|
||||
{
|
||||
abort_run = true;
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (negate)
|
||||
f = spot::ltl::unop::instance(spot::ltl::unop::Not, f);
|
||||
f = spot::ltl::formula::Not(f);
|
||||
|
||||
if (remove_x)
|
||||
{
|
||||
// If simplification are enabled, we do them before and after.
|
||||
if (simplification_level)
|
||||
{
|
||||
const spot::ltl::formula* res = simpl.simplify(f);
|
||||
f->destroy();
|
||||
f = res;
|
||||
}
|
||||
|
||||
const spot::ltl::formula* res = spot::ltl::remove_x(f);
|
||||
f->destroy();
|
||||
f = res;
|
||||
f = simpl.simplify(f);
|
||||
f = spot::ltl::remove_x(f);
|
||||
}
|
||||
|
||||
if (simplification_level || boolean_to_isop)
|
||||
{
|
||||
const spot::ltl::formula* res = simpl.simplify(f);
|
||||
f->destroy();
|
||||
f = res;
|
||||
}
|
||||
f = simpl.simplify(f);
|
||||
|
||||
if (nnf)
|
||||
{
|
||||
const spot::ltl::formula* res = simpl.negative_normal_form(f);
|
||||
f->destroy();
|
||||
f = res;
|
||||
}
|
||||
f = simpl.negative_normal_form(f);
|
||||
|
||||
switch (relabeling)
|
||||
{
|
||||
case ApRelabeling:
|
||||
{
|
||||
relmap.clear();
|
||||
auto res = spot::ltl::relabel(f, style, &relmap);
|
||||
f->destroy();
|
||||
f = res;
|
||||
f = spot::ltl::relabel(f, style, &relmap);
|
||||
break;
|
||||
}
|
||||
case BseRelabeling:
|
||||
{
|
||||
relmap.clear();
|
||||
auto res = spot::ltl::relabel_bse(f, style, &relmap);
|
||||
f->destroy();
|
||||
f = res;
|
||||
f = spot::ltl::relabel_bse(f, style, &relmap);
|
||||
break;
|
||||
}
|
||||
case NoRelabeling:
|
||||
|
|
@ -573,32 +531,24 @@ namespace
|
|||
}
|
||||
|
||||
if (!unabbreviate.empty())
|
||||
{
|
||||
auto res = spot::ltl::unabbreviate(f, unabbreviate.c_str());
|
||||
f->destroy();
|
||||
f = res;
|
||||
}
|
||||
f = spot::ltl::unabbreviate(f, unabbreviate.c_str());
|
||||
|
||||
if (!excl_ap.empty())
|
||||
{
|
||||
auto res = excl_ap.constrain(f);
|
||||
f->destroy();
|
||||
f = res;
|
||||
}
|
||||
f = excl_ap.constrain(f);
|
||||
|
||||
bool matched = true;
|
||||
|
||||
matched &= !ltl || f->is_ltl_formula();
|
||||
matched &= !psl || f->is_psl_formula();
|
||||
matched &= !boolean || f->is_boolean();
|
||||
matched &= !universal || f->is_universal();
|
||||
matched &= !eventual || f->is_eventual();
|
||||
matched &= !syntactic_safety || f->is_syntactic_safety();
|
||||
matched &= !syntactic_guarantee || f->is_syntactic_guarantee();
|
||||
matched &= !syntactic_obligation || f->is_syntactic_obligation();
|
||||
matched &= !syntactic_recurrence || f->is_syntactic_recurrence();
|
||||
matched &= !syntactic_persistence || f->is_syntactic_persistence();
|
||||
matched &= !syntactic_si || f->is_syntactic_stutter_invariant();
|
||||
matched &= !ltl || f.is_ltl_formula();
|
||||
matched &= !psl || f.is_psl_formula();
|
||||
matched &= !boolean || f.is_boolean();
|
||||
matched &= !universal || f.is_universal();
|
||||
matched &= !eventual || f.is_eventual();
|
||||
matched &= !syntactic_safety || f.is_syntactic_safety();
|
||||
matched &= !syntactic_guarantee || f.is_syntactic_guarantee();
|
||||
matched &= !syntactic_obligation || f.is_syntactic_obligation();
|
||||
matched &= !syntactic_recurrence || f.is_syntactic_recurrence();
|
||||
matched &= !syntactic_persistence || f.is_syntactic_persistence();
|
||||
matched &= !syntactic_si || f.is_syntactic_stutter_invariant();
|
||||
matched &= !ap || atomic_prop_collect(f)->size() == ap_n;
|
||||
|
||||
if (matched && (size_min > 0 || size_max >= 0))
|
||||
|
|
@ -643,13 +593,8 @@ namespace
|
|||
|
||||
matched ^= invert;
|
||||
|
||||
if (unique)
|
||||
{
|
||||
if (unique_set.insert(f).second)
|
||||
f->clone();
|
||||
else
|
||||
if (unique && !unique_set.insert(f).second)
|
||||
matched = false;
|
||||
}
|
||||
|
||||
if (matched)
|
||||
{
|
||||
|
|
@ -658,7 +603,7 @@ namespace
|
|||
&& output_format != quiet_output)
|
||||
{
|
||||
// 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)
|
||||
m.emplace(str_psl(p.first), p.second);
|
||||
for (auto& p: m)
|
||||
|
|
@ -670,7 +615,6 @@ namespace
|
|||
output_formula_checked(f, filename, linenum, prefix, suffix);
|
||||
++match_count;
|
||||
}
|
||||
f->destroy();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,10 +27,6 @@
|
|||
#include "common_output.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"
|
||||
|
||||
enum {
|
||||
|
|
@ -100,17 +96,13 @@ namespace
|
|||
{
|
||||
public:
|
||||
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)
|
||||
{
|
||||
auto mutations =
|
||||
spot::ltl::mutate(f, mut_opts, max_output, mutation_nb, opt_sort);
|
||||
f->destroy();
|
||||
for (auto g: mutations)
|
||||
{
|
||||
output_formula_checked(g, filename, linenum);
|
||||
g->destroy();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
#include "common_aoutput.hh"
|
||||
#include "common_conv.hh"
|
||||
|
||||
#include "ltlenv/defaultenv.hh"
|
||||
#include "misc/timer.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);
|
||||
break;
|
||||
}
|
||||
aprops.insert(spot::ltl::default_environment::instance().require(arg));
|
||||
aprops.insert(spot::ltl::formula::ap(arg));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -328,7 +327,6 @@ main(int argc, char** argv)
|
|||
if (ap_count_given.max > 0
|
||||
&& 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);
|
||||
aprops = spot::ltl::create_atomic_prop_set(c);
|
||||
}
|
||||
|
|
@ -391,5 +389,4 @@ main(int argc, char** argv)
|
|||
{
|
||||
error(2, 0, "%s", e.what());
|
||||
}
|
||||
spot::ltl::destroy_atomic_prop_set(aprops);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,14 +33,9 @@
|
|||
#include "common_conv.hh"
|
||||
|
||||
#include <sstream>
|
||||
#include "ltlast/multop.hh"
|
||||
#include "ltlast/unop.hh"
|
||||
#include "ltlvisit/randomltl.hh"
|
||||
#include "ltlvisit/length.hh"
|
||||
#include "ltlvisit/simplify.hh"
|
||||
#include "ltlenv/defaultenv.hh"
|
||||
#include "misc/random.hh"
|
||||
#include "misc/hash.hh"
|
||||
#include "misc/optionmap.hh"
|
||||
|
||||
const char argp_program_doc[] ="\
|
||||
|
|
@ -253,8 +248,8 @@ main(int argc, char** argv)
|
|||
opts.set("output", output);
|
||||
opts.set("tree_size_min", opt_tree_size.min);
|
||||
opts.set("tree_size_max", opt_tree_size.max);
|
||||
opts.set("opt_wf", opt_wf);
|
||||
opts.set("opt_seed", opt_seed);
|
||||
opts.set("wf", opt_wf);
|
||||
opts.set("seed", opt_seed);
|
||||
opts.set("simplification_level", simplification_level);
|
||||
return opts;
|
||||
}(), opt_pL, opt_pS, opt_pB);
|
||||
|
|
@ -291,14 +286,13 @@ main(int argc, char** argv)
|
|||
default:
|
||||
error(2, 0, "internal error: unknown type of output");
|
||||
}
|
||||
destroy_atomic_prop_set(aprops);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
while (opt_formulas < 0 || opt_formulas--)
|
||||
{
|
||||
static int count = 0;
|
||||
const spot::ltl::formula* f = rg.next();
|
||||
spot::ltl::formula f = rg.next();
|
||||
if (!f)
|
||||
{
|
||||
error(2, 0, "failed to generate a new unique formula after %d " \
|
||||
|
|
@ -307,21 +301,17 @@ main(int argc, char** argv)
|
|||
else
|
||||
{
|
||||
output_formula_checked(f, 0, ++count);
|
||||
f->destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (const std::runtime_error& e)
|
||||
{
|
||||
destroy_atomic_prop_set(aprops);
|
||||
error(2, 0, "%s", e.what());
|
||||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
destroy_atomic_prop_set(aprops);
|
||||
error(2, 0, "%s", e.what());
|
||||
}
|
||||
|
||||
destroy_atomic_prop_set(aprops);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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)
|
||||
//
|
||||
// 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,
|
||||
std::string on_me)
|
||||
void kripke_explicit::add_condition(ltl::formula f, std::string on_me)
|
||||
{
|
||||
add_conditions(formula_to_bdd(f, get_dict(), this), on_me);
|
||||
f->destroy();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
|
||||
// Développement de l'Epita (LRDE)
|
||||
// Copyright (C) 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.
|
||||
//
|
||||
|
|
@ -151,8 +151,7 @@ namespace spot
|
|||
///
|
||||
/// \param f the formula to add.
|
||||
/// \param on_me the state where to add.
|
||||
void add_condition(const ltl::formula* f,
|
||||
std::string on_me);
|
||||
void add_condition(ltl::formula f, std::string on_me);
|
||||
|
||||
/// \brief Return map between states and their names.
|
||||
const std::map<const state_kripke*, std::string>&
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ typedef std::map<std::string, bdd> formula_cache;
|
|||
{
|
||||
int token;
|
||||
std::string* str;
|
||||
const spot::ltl::formula* f;
|
||||
std::list<std::string*>* list;
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +109,7 @@ strident "," condition "," follow_list ";"
|
|||
if (i == fcache.end())
|
||||
{
|
||||
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);
|
||||
for (parse_error_list::iterator i = pel.begin();
|
||||
i != pel.end(); ++i)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
## Copyright (C) 2009, 2010, 2011, 2013, 2014 Laboratoire de Recherche
|
||||
## et Développement de l'Epita (LRDE).
|
||||
## Copyright (C) 2009, 2010, 2011, 2013, 2014, 2015 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.
|
||||
|
|
@ -26,24 +26,7 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS)
|
|||
|
||||
ltlastdir = $(pkgincludedir)/ltlast
|
||||
|
||||
ltlast_HEADERS = \
|
||||
allnodes.hh \
|
||||
atomic_prop.hh \
|
||||
binop.hh \
|
||||
bunop.hh \
|
||||
constant.hh \
|
||||
formula.hh \
|
||||
multop.hh \
|
||||
predecl.hh \
|
||||
unop.hh \
|
||||
visitor.hh
|
||||
ltlast_HEADERS = formula.hh
|
||||
|
||||
noinst_LTLIBRARIES = libltlast.la
|
||||
libltlast_la_SOURCES = \
|
||||
atomic_prop.cc \
|
||||
binop.cc \
|
||||
bunop.cc \
|
||||
constant.cc \
|
||||
formula.cc \
|
||||
multop.cc \
|
||||
unop.cc
|
||||
libltlast_la_SOURCES = formula.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 -*-
|
||||
// Copyright (C) 2009, 2012, 2014 Laboratoire de Recherche et Développement
|
||||
// de l'Epita (LRDE).
|
||||
// Copyright (C) 2009, 2012, 2014, 2015 Laboratoire de Recherche et
|
||||
// Développement de l'Epita (LRDE).
|
||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||
// 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
|
||||
declarative_environment::declare(const std::string& prop_str)
|
||||
{
|
||||
if (props_.find(prop_str) != props_.end())
|
||||
return false;
|
||||
props_[prop_str] = ltl::atomic_prop::instance(prop_str, *this);
|
||||
props_[prop_str] = formula::ap(prop_str);
|
||||
return true;
|
||||
}
|
||||
|
||||
const formula*
|
||||
formula
|
||||
declarative_environment::require(const std::string& prop_str)
|
||||
{
|
||||
prop_map::iterator i = props_.find(prop_str);
|
||||
if (i == props_.end())
|
||||
return 0;
|
||||
return i->second->clone();
|
||||
return nullptr;
|
||||
return i->second;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2009, 2012, 2013, 2014 Laboratoire de Recherche et
|
||||
// Développement de l'Epita (LRDE).
|
||||
// Copyright (C) 2009, 2012, 2013, 2014, 2015 Laboratoire de Recherche
|
||||
// et Développement de l'Epita (LRDE).
|
||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||
// et Marie Curie.
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#include "environment.hh"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "ltlast/atomic_prop.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -41,18 +41,18 @@ namespace spot
|
|||
{
|
||||
public:
|
||||
declarative_environment();
|
||||
~declarative_environment();
|
||||
~declarative_environment() = default;
|
||||
|
||||
/// Declare an atomic proposition. Return false iff the
|
||||
/// proposition was already declared.
|
||||
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.
|
||||
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.
|
||||
const prop_map& get_prop_map() const;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2012, 2014 Laboratoire de Recherche et Développement
|
||||
// de l'Epita (LRDE).
|
||||
// Copyright (C) 2012, 2014, 2015 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.
|
||||
|
|
@ -31,10 +31,10 @@ namespace spot
|
|||
{
|
||||
}
|
||||
|
||||
const atomic_prop*
|
||||
formula
|
||||
default_environment::require(const std::string& s)
|
||||
{
|
||||
return atomic_prop::instance(s, *this);
|
||||
return formula::ap(s);
|
||||
}
|
||||
|
||||
const std::string&
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2012, 2013, 2014, 2015 Laboratoire de Recherche et
|
||||
// Développement
|
||||
// de l'Epita (LRDE).
|
||||
// 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.
|
||||
|
|
@ -24,7 +23,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "environment.hh"
|
||||
#include "ltlast/atomic_prop.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -42,7 +41,7 @@ namespace spot
|
|||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
/// Get the sole instance of spot::ltl::default_environment.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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).
|
||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris
|
||||
// 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,
|
||||
/// 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
|
||||
/// "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,
|
||||
/// 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.
|
||||
virtual const std::string& name() const = 0;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
#include "public.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
#include "ltlvisit/print.hh"
|
||||
|
||||
struct minmax_t { unsigned min, max; };
|
||||
|
|
@ -43,11 +43,11 @@
|
|||
|
||||
%parse-param {spot::ltl::parse_error_list &error_list}
|
||||
%parse-param {spot::ltl::environment &parse_environment}
|
||||
%parse-param {const spot::ltl::formula* &result}
|
||||
%parse-param {spot::ltl::formula &result}
|
||||
%union
|
||||
{
|
||||
std::string* str;
|
||||
const spot::ltl::formula* ltl;
|
||||
const spot::ltl::fnode* ltl;
|
||||
unsigned num;
|
||||
minmax_t minmax;
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ using namespace spot::ltl;
|
|||
do \
|
||||
{ \
|
||||
missing_right_op_msg(op, str); \
|
||||
res = constant::false_instance(); \
|
||||
res = fnode::ff(); \
|
||||
} \
|
||||
while (0);
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ using namespace spot::ltl;
|
|||
|
||||
enum parser_type { parser_ltl, parser_bool, parser_sere };
|
||||
|
||||
static const formula*
|
||||
static formula
|
||||
try_recursive_parse(const std::string& str,
|
||||
const spot::location& location,
|
||||
spot::ltl::environment& env,
|
||||
|
|
@ -117,11 +117,11 @@ using namespace spot::ltl;
|
|||
if (str.empty())
|
||||
{
|
||||
error_list.emplace_back(location, "unexpected empty block");
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
spot::ltl::parse_error_list suberror;
|
||||
const spot::ltl::formula* f = 0;
|
||||
formula f;
|
||||
switch (type)
|
||||
{
|
||||
case parser_sere:
|
||||
|
|
@ -138,9 +138,6 @@ using namespace spot::ltl;
|
|||
if (suberror.empty())
|
||||
return f;
|
||||
|
||||
if (f)
|
||||
f->destroy();
|
||||
|
||||
f = env.require(str);
|
||||
if (!f)
|
||||
{
|
||||
|
|
@ -240,72 +237,76 @@ using namespace spot::ltl;
|
|||
%destructor { $$->destroy(); } <ltl>
|
||||
|
||||
%printer { debug_stream() << *$$; } <str>
|
||||
%printer { spot::ltl::print_psl(debug_stream(), $$); } <ltl>
|
||||
%printer { spot::ltl::print_sere(debug_stream(), $$); } sere bracedsere
|
||||
%printer { spot::ltl::print_psl(debug_stream(), formula($$)); } <ltl>
|
||||
%printer { spot::ltl::print_sere(debug_stream(), formula($$)); } sere bracedsere
|
||||
%printer { debug_stream() << $$; } <num>
|
||||
%printer { debug_stream() << $$.min << ".." << $$.max; } <minmax>
|
||||
|
||||
%%
|
||||
result: START_LTL subformula END_OF_INPUT
|
||||
{ result = $2;
|
||||
{
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_LTL enderror
|
||||
{
|
||||
result = 0;
|
||||
result = nullptr;
|
||||
YYABORT;
|
||||
}
|
||||
| START_LTL subformula enderror
|
||||
{
|
||||
result = $2;
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_LTL emptyinput
|
||||
{ YYABORT; }
|
||||
| START_BOOL boolformula END_OF_INPUT
|
||||
{ result = $2;
|
||||
{
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_BOOL enderror
|
||||
{
|
||||
result = 0;
|
||||
result = nullptr;
|
||||
YYABORT;
|
||||
}
|
||||
| START_BOOL boolformula enderror
|
||||
{
|
||||
result = $2;
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_BOOL emptyinput
|
||||
{ YYABORT; }
|
||||
| START_SERE sere END_OF_INPUT
|
||||
{ result = $2;
|
||||
{
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_SERE enderror
|
||||
{
|
||||
result = 0;
|
||||
result = nullptr;
|
||||
YYABORT;
|
||||
}
|
||||
| START_SERE sere enderror
|
||||
{
|
||||
result = $2;
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_SERE emptyinput
|
||||
{ YYABORT; }
|
||||
| START_LBT lbtformula END_OF_INPUT
|
||||
{ result = $2;
|
||||
{
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_LBT enderror
|
||||
{
|
||||
result = 0;
|
||||
result = nullptr;
|
||||
YYABORT;
|
||||
}
|
||||
| START_LBT lbtformula enderror
|
||||
{
|
||||
result = $2;
|
||||
result = formula($2);
|
||||
YYACCEPT;
|
||||
}
|
||||
| START_LBT emptyinput
|
||||
|
|
@ -314,7 +315,7 @@ result: START_LTL subformula END_OF_INPUT
|
|||
emptyinput: END_OF_INPUT
|
||||
{
|
||||
error_list.emplace_back(@$, "empty input");
|
||||
result = 0;
|
||||
result = nullptr;
|
||||
}
|
||||
|
||||
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
|
||||
{ $$.min = $1; $$.max = $3; }
|
||||
| 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
|
||||
{ $$.min = 0U; $$.max = $2; }
|
||||
| OP_SQBKT_SEP_opt OP_SQBKT_CLOSE
|
||||
{ $$.min = 0U; $$.max = bunop::unbounded; }
|
||||
{ $$.min = 0U; $$.max = fnode::unbounded(); }
|
||||
| OP_SQBKT_NUM OP_SQBKT_CLOSE
|
||||
{ $$.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
|
||||
{ $$.min = $2; $$.max = $4; }
|
||||
| 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
|
||||
{ $$.min = 1U; $$.max = $3; }
|
||||
| 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
|
||||
{ $$.min = $$.max = 1U; }
|
||||
| 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
|
||||
|
||||
starargs: kleen_star
|
||||
{ $$.min = 0U; $$.max = bunop::unbounded; }
|
||||
{ $$.min = 0U; $$.max = fnode::unbounded(); }
|
||||
| OP_PLUS
|
||||
{ $$.min = 1U; $$.max = bunop::unbounded; }
|
||||
{ $$.min = 1U; $$.max = fnode::unbounded(); }
|
||||
| OP_STAR_OPEN sqbracketargs
|
||||
{ $$ = $2; }
|
||||
| OP_STAR_OPEN error OP_SQBKT_CLOSE
|
||||
{ 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
|
||||
{ error_list.emplace_back(@$, "missing closing bracket for star");
|
||||
$$.min = $$.max = 0U; }
|
||||
|
||||
fstarargs: OP_BFSTAR
|
||||
{ $$.min = 0U; $$.max = bunop::unbounded; }
|
||||
{ $$.min = 0U; $$.max = fnode::unbounded(); }
|
||||
| OP_FPLUS
|
||||
{ $$.min = 1U; $$.max = bunop::unbounded; }
|
||||
{ $$.min = 1U; $$.max = fnode::unbounded(); }
|
||||
| OP_FSTAR_OPEN sqbracketargs
|
||||
{ $$ = $2; }
|
||||
| OP_FSTAR_OPEN error OP_SQBKT_CLOSE
|
||||
{ error_list.emplace_back
|
||||
(@$, "treating this fusion-star block as [:*]");
|
||||
$$.min = 0U; $$.max = bunop::unbounded; }
|
||||
$$.min = 0U; $$.max = fnode::unbounded(); }
|
||||
| OP_FSTAR_OPEN error_opt END_OF_INPUT
|
||||
{ error_list.emplace_back
|
||||
(@$, "missing closing bracket for fusion-star");
|
||||
|
|
@ -394,19 +395,16 @@ equalargs: OP_EQUAL_OPEN sqbracketargs
|
|||
{ $$ = $2; }
|
||||
| OP_EQUAL_OPEN error OP_SQBKT_CLOSE
|
||||
{ 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
|
||||
{ error_list.
|
||||
emplace_back(@$, "missing closing bracket for equal operator");
|
||||
$$.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
|
||||
{
|
||||
$$ = parse_environment.require(*$1);
|
||||
$$ = parse_environment.require(*$1).to_node_();
|
||||
if (! $$)
|
||||
{
|
||||
std::string s = "unknown atomic proposition `";
|
||||
|
|
@ -423,7 +421,7 @@ booleanatom: ATOMIC_PROP
|
|||
}
|
||||
| ATOMIC_PROP OP_POST_POS
|
||||
{
|
||||
$$ = parse_environment.require(*$1);
|
||||
$$ = parse_environment.require(*$1).to_node_();
|
||||
if (! $$)
|
||||
{
|
||||
std::string s = "unknown atomic proposition `";
|
||||
|
|
@ -440,7 +438,7 @@ booleanatom: ATOMIC_PROP
|
|||
}
|
||||
| ATOMIC_PROP OP_POST_NEG
|
||||
{
|
||||
$$ = parse_environment.require(*$1);
|
||||
$$ = parse_environment.require(*$1).to_node_();
|
||||
if (! $$)
|
||||
{
|
||||
std::string s = "unknown atomic proposition `";
|
||||
|
|
@ -454,19 +452,19 @@ booleanatom: ATOMIC_PROP
|
|||
}
|
||||
else
|
||||
delete $1;
|
||||
$$ = unop::instance(unop::Not, $$);
|
||||
$$ = fnode::unop(op::Not, $$);
|
||||
}
|
||||
| CONST_TRUE
|
||||
{ $$ = constant::true_instance(); }
|
||||
{ $$ = fnode::tt(); }
|
||||
| CONST_FALSE
|
||||
{ $$ = constant::false_instance(); }
|
||||
{ $$ = fnode::ff(); }
|
||||
|
||||
sere: booleanatom
|
||||
| OP_NOT sere
|
||||
{
|
||||
if ($2->is_boolean())
|
||||
{
|
||||
$$ = unop::instance(unop::Not, $2);
|
||||
$$ = fnode::unop(op::Not, $2);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -475,14 +473,16 @@ sere: booleanatom
|
|||
"be applied to a Boolean expression");
|
||||
error_list.emplace_back(@$, "treating this block as false");
|
||||
$2->destroy();
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
}
|
||||
| bracedsere
|
||||
| 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;
|
||||
if (!$$)
|
||||
YYERROR;
|
||||
|
|
@ -493,7 +493,7 @@ sere: booleanatom
|
|||
{ error_list.
|
||||
emplace_back(@$,
|
||||
"treating this parenthetical block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
| PAR_OPEN sere END_OF_INPUT
|
||||
{ error_list.emplace_back(@1 + @2, "missing closing parenthesis");
|
||||
|
|
@ -503,28 +503,28 @@ sere: booleanatom
|
|||
{ error_list.emplace_back(@$,
|
||||
"missing closing parenthesis, "
|
||||
"treating this parenthetical block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
| sere OP_AND sere
|
||||
{ $$ = multop::instance(multop::AndRat, $1, $3); }
|
||||
{ $$ = fnode::multop(op::AndRat, {$1, $3}); }
|
||||
| sere OP_AND error
|
||||
{ missing_right_binop($$, $1, @2,
|
||||
"length-matching and operator"); }
|
||||
| sere OP_SHORT_AND sere
|
||||
{ $$ = multop::instance(multop::AndNLM, $1, $3); }
|
||||
{ $$ = fnode::multop(op::AndNLM, {$1, $3}); }
|
||||
| sere OP_SHORT_AND error
|
||||
{ missing_right_binop($$, $1, @2,
|
||||
"non-length-matching and operator"); }
|
||||
| sere OP_OR sere
|
||||
{ $$ = multop::instance(multop::OrRat, $1, $3); }
|
||||
{ $$ = fnode::multop(op::OrRat, {$1, $3}); }
|
||||
| sere OP_OR error
|
||||
{ missing_right_binop($$, $1, @2, "or operator"); }
|
||||
| sere OP_CONCAT sere
|
||||
{ $$ = multop::instance(multop::Concat, $1, $3); }
|
||||
{ $$ = fnode::multop(op::Concat, {$1, $3}); }
|
||||
| sere OP_CONCAT error
|
||||
{ missing_right_binop($$, $1, @2, "concat operator"); }
|
||||
| sere OP_FUSION sere
|
||||
{ $$ = multop::instance(multop::Fusion, $1, $3); }
|
||||
{ $$ = fnode::multop(op::Fusion, {$1, $3}); }
|
||||
| sere OP_FUSION error
|
||||
{ missing_right_binop($$, $1, @2, "fusion operator"); }
|
||||
| starargs
|
||||
|
|
@ -534,8 +534,7 @@ sere: booleanatom
|
|||
error_list.emplace_back(@1, "reversed range");
|
||||
std::swap($1.max, $1.min);
|
||||
}
|
||||
$$ = bunop::instance(bunop::Star, constant::true_instance(),
|
||||
$1.min, $1.max);
|
||||
$$ = fnode::bunop(op::Star, fnode::tt(), $1.min, $1.max);
|
||||
}
|
||||
| sere starargs
|
||||
{
|
||||
|
|
@ -544,7 +543,7 @@ sere: booleanatom
|
|||
error_list.emplace_back(@2, "reversed range");
|
||||
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
|
||||
{
|
||||
|
|
@ -553,7 +552,7 @@ sere: booleanatom
|
|||
error_list.emplace_back(@2, "reversed range");
|
||||
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
|
||||
{
|
||||
|
|
@ -564,7 +563,8 @@ sere: booleanatom
|
|||
}
|
||||
if ($1->is_boolean())
|
||||
{
|
||||
$$ = bunop::sugar_equal($1, $2.min, $2.max);
|
||||
$$ = formula::sugar_equal(formula($1),
|
||||
$2.min, $2.max).to_node_();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -574,7 +574,7 @@ sere: booleanatom
|
|||
error_list.emplace_back(@$,
|
||||
"treating this block as false");
|
||||
$1->destroy();
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
}
|
||||
| sere gotoargs
|
||||
|
|
@ -586,7 +586,8 @@ sere: booleanatom
|
|||
}
|
||||
if ($1->is_boolean())
|
||||
{
|
||||
$$ = bunop::sugar_goto($1, $2.min, $2.max);
|
||||
$$ = formula::sugar_goto(formula($1),
|
||||
$2.min, $2.max).to_node_();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -596,14 +597,14 @@ sere: booleanatom
|
|||
error_list.emplace_back(@$,
|
||||
"treating this block as false");
|
||||
$1->destroy();
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
}
|
||||
| sere OP_XOR sere
|
||||
{
|
||||
if ($1->is_boolean() && $3->is_boolean())
|
||||
{
|
||||
$$ = binop::instance(binop::Xor, $1, $3);
|
||||
$$ = fnode::binop(op::Xor, $1, $3);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -622,7 +623,7 @@ sere: booleanatom
|
|||
error_list.emplace_back(@$, "treating this block as false");
|
||||
$1->destroy();
|
||||
$3->destroy();
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
}
|
||||
| sere OP_XOR error
|
||||
|
|
@ -631,7 +632,7 @@ sere: booleanatom
|
|||
{
|
||||
if ($1->is_boolean())
|
||||
{
|
||||
$$ = binop::instance(binop::Implies, $1, $3);
|
||||
$$ = fnode::binop(op::Implies, $1, $3);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -644,7 +645,7 @@ sere: booleanatom
|
|||
error_list.emplace_back(@$, "treating this block as false");
|
||||
$1->destroy();
|
||||
$3->destroy();
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
}
|
||||
| sere OP_IMPLIES error
|
||||
|
|
@ -653,7 +654,7 @@ sere: booleanatom
|
|||
{
|
||||
if ($1->is_boolean() && $3->is_boolean())
|
||||
{
|
||||
$$ = binop::instance(binop::Equiv, $1, $3);
|
||||
$$ = fnode::binop(op::Equiv, $1, $3);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -672,7 +673,7 @@ sere: booleanatom
|
|||
error_list.emplace_back(@$, "treating this block as false");
|
||||
$1->destroy();
|
||||
$3->destroy();
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
}
|
||||
| sere OP_EQUIV error
|
||||
|
|
@ -687,7 +688,7 @@ bracedsere: BRACE_OPEN sere BRACE_CLOSE
|
|||
| BRACE_OPEN error BRACE_CLOSE
|
||||
{ error_list.emplace_back(@$,
|
||||
"treating this brace block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
| BRACE_OPEN sere END_OF_INPUT
|
||||
{ error_list.emplace_back(@1 + @2,
|
||||
|
|
@ -703,13 +704,13 @@ bracedsere: BRACE_OPEN sere BRACE_CLOSE
|
|||
{ error_list.emplace_back(@$,
|
||||
"missing closing brace, "
|
||||
"treating this brace block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
| BRA_BLOCK
|
||||
{
|
||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||
debug_level(),
|
||||
parser_sere, error_list);
|
||||
parser_sere, error_list).to_node_();
|
||||
delete $1;
|
||||
if (!$$)
|
||||
YYERROR;
|
||||
|
|
@ -718,7 +719,8 @@ bracedsere: BRACE_OPEN sere BRACE_CLOSE
|
|||
parenthesedsubformula: PAR_BLOCK
|
||||
{
|
||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||
debug_level(), parser_ltl, error_list);
|
||||
debug_level(), parser_ltl, error_list)
|
||||
.to_node_();
|
||||
delete $1;
|
||||
if (!$$)
|
||||
YYERROR;
|
||||
|
|
@ -732,7 +734,7 @@ parenthesedsubformula: PAR_BLOCK
|
|||
| PAR_OPEN error PAR_CLOSE
|
||||
{ error_list.emplace_back(@$,
|
||||
"treating this parenthetical block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
| PAR_OPEN subformula END_OF_INPUT
|
||||
{ error_list.emplace_back(@1 + @2, "missing closing parenthesis");
|
||||
|
|
@ -747,7 +749,7 @@ parenthesedsubformula: PAR_BLOCK
|
|||
{ error_list.emplace_back(@$,
|
||||
"missing closing parenthesis, "
|
||||
"treating this parenthetical block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -755,7 +757,8 @@ boolformula: booleanatom
|
|||
| PAR_BLOCK
|
||||
{
|
||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||
debug_level(), parser_bool, error_list);
|
||||
debug_level(), parser_bool, error_list)
|
||||
.to_node_();
|
||||
delete $1;
|
||||
if (!$$)
|
||||
YYERROR;
|
||||
|
|
@ -769,7 +772,7 @@ boolformula: booleanatom
|
|||
| PAR_OPEN error PAR_CLOSE
|
||||
{ error_list.emplace_back(@$,
|
||||
"treating this parenthetical block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
| PAR_OPEN boolformula END_OF_INPUT
|
||||
{ error_list.emplace_back(@1 + @2,
|
||||
|
|
@ -785,156 +788,153 @@ boolformula: booleanatom
|
|||
{ error_list.emplace_back(@$,
|
||||
"missing closing parenthesis, "
|
||||
"treating this parenthetical block as false");
|
||||
$$ = constant::false_instance();
|
||||
$$ = fnode::ff();
|
||||
}
|
||||
| boolformula OP_AND boolformula
|
||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
||||
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||
| boolformula OP_AND error
|
||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||
| boolformula OP_SHORT_AND boolformula
|
||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
||||
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||
| boolformula OP_SHORT_AND error
|
||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||
| boolformula OP_STAR boolformula
|
||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
||||
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||
| boolformula OP_STAR error
|
||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||
| boolformula OP_OR boolformula
|
||||
{ $$ = multop::instance(multop::Or, $1, $3); }
|
||||
{ $$ = fnode::multop(op::Or, {$1, $3}); }
|
||||
| boolformula OP_OR error
|
||||
{ missing_right_binop($$, $1, @2, "or operator"); }
|
||||
| boolformula OP_XOR boolformula
|
||||
{ $$ = binop::instance(binop::Xor, $1, $3); }
|
||||
{ $$ = fnode::binop(op::Xor, $1, $3); }
|
||||
| boolformula OP_XOR error
|
||||
{ missing_right_binop($$, $1, @2, "xor operator"); }
|
||||
| boolformula OP_IMPLIES boolformula
|
||||
{ $$ = binop::instance(binop::Implies, $1, $3); }
|
||||
{ $$ = fnode::binop(op::Implies, $1, $3); }
|
||||
| boolformula OP_IMPLIES error
|
||||
{ missing_right_binop($$, $1, @2, "implication operator"); }
|
||||
| boolformula OP_EQUIV boolformula
|
||||
{ $$ = binop::instance(binop::Equiv, $1, $3); }
|
||||
{ $$ = fnode::binop(op::Equiv, $1, $3); }
|
||||
| boolformula OP_EQUIV error
|
||||
{ missing_right_binop($$, $1, @2, "equivalent operator"); }
|
||||
| OP_NOT boolformula
|
||||
{ $$ = unop::instance(unop::Not, $2); }
|
||||
{ $$ = fnode::unop(op::Not, $2); }
|
||||
| OP_NOT error
|
||||
{ missing_right_op($$, @1, "not operator"); }
|
||||
|
||||
subformula: booleanatom
|
||||
| parenthesedsubformula
|
||||
| subformula OP_AND subformula
|
||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
||||
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||
| subformula OP_AND error
|
||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||
| subformula OP_SHORT_AND subformula
|
||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
||||
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||
| subformula OP_SHORT_AND error
|
||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||
| subformula OP_STAR subformula
|
||||
{ $$ = multop::instance(multop::And, $1, $3); }
|
||||
{ $$ = fnode::multop(op::And, {$1, $3}); }
|
||||
| subformula OP_STAR error
|
||||
{ missing_right_binop($$, $1, @2, "and operator"); }
|
||||
| subformula OP_OR subformula
|
||||
{ $$ = multop::instance(multop::Or, $1, $3); }
|
||||
{ $$ = fnode::multop(op::Or, {$1, $3}); }
|
||||
| subformula OP_OR error
|
||||
{ missing_right_binop($$, $1, @2, "or operator"); }
|
||||
| subformula OP_XOR subformula
|
||||
{ $$ = binop::instance(binop::Xor, $1, $3); }
|
||||
{ $$ = fnode::binop(op::Xor, $1, $3); }
|
||||
| subformula OP_XOR error
|
||||
{ missing_right_binop($$, $1, @2, "xor operator"); }
|
||||
| subformula OP_IMPLIES subformula
|
||||
{ $$ = binop::instance(binop::Implies, $1, $3); }
|
||||
{ $$ = fnode::binop(op::Implies, $1, $3); }
|
||||
| subformula OP_IMPLIES error
|
||||
{ missing_right_binop($$, $1, @2, "implication operator"); }
|
||||
| subformula OP_EQUIV subformula
|
||||
{ $$ = binop::instance(binop::Equiv, $1, $3); }
|
||||
{ $$ = fnode::binop(op::Equiv, $1, $3); }
|
||||
| subformula OP_EQUIV error
|
||||
{ missing_right_binop($$, $1, @2, "equivalent operator"); }
|
||||
| subformula OP_U subformula
|
||||
{ $$ = binop::instance(binop::U, $1, $3); }
|
||||
{ $$ = fnode::binop(op::U, $1, $3); }
|
||||
| subformula OP_U error
|
||||
{ missing_right_binop($$, $1, @2, "until operator"); }
|
||||
| subformula OP_R subformula
|
||||
{ $$ = binop::instance(binop::R, $1, $3); }
|
||||
{ $$ = fnode::binop(op::R, $1, $3); }
|
||||
| subformula OP_R error
|
||||
{ missing_right_binop($$, $1, @2, "release operator"); }
|
||||
| subformula OP_W subformula
|
||||
{ $$ = binop::instance(binop::W, $1, $3); }
|
||||
{ $$ = fnode::binop(op::W, $1, $3); }
|
||||
| subformula OP_W error
|
||||
{ missing_right_binop($$, $1, @2, "weak until operator"); }
|
||||
| subformula OP_M subformula
|
||||
{ $$ = binop::instance(binop::M, $1, $3); }
|
||||
{ $$ = fnode::binop(op::M, $1, $3); }
|
||||
| subformula OP_M error
|
||||
{ missing_right_binop($$, $1, @2, "strong release operator"); }
|
||||
| OP_F subformula
|
||||
{ $$ = unop::instance(unop::F, $2); }
|
||||
{ $$ = fnode::unop(op::F, $2); }
|
||||
| OP_F error
|
||||
{ missing_right_op($$, @1, "sometimes operator"); }
|
||||
| OP_G subformula
|
||||
{ $$ = unop::instance(unop::G, $2); }
|
||||
{ $$ = fnode::unop(op::G, $2); }
|
||||
| OP_G error
|
||||
{ missing_right_op($$, @1, "always operator"); }
|
||||
| OP_X subformula
|
||||
{ $$ = unop::instance(unop::X, $2); }
|
||||
{ $$ = fnode::unop(op::X, $2); }
|
||||
| OP_X error
|
||||
{ missing_right_op($$, @1, "next operator"); }
|
||||
| OP_NOT subformula
|
||||
{ $$ = unop::instance(unop::Not, $2); }
|
||||
{ $$ = fnode::unop(op::Not, $2); }
|
||||
| OP_NOT error
|
||||
{ missing_right_op($$, @1, "not operator"); }
|
||||
| bracedsere
|
||||
{ $$ = unop::instance(unop::Closure, $1); }
|
||||
{ $$ = fnode::unop(op::Closure, $1); }
|
||||
| bracedsere OP_UCONCAT subformula
|
||||
{ $$ = binop::instance(binop::UConcat, $1, $3); }
|
||||
{ $$ = fnode::binop(op::UConcat, $1, $3); }
|
||||
| bracedsere parenthesedsubformula
|
||||
{ $$ = binop::instance(binop::UConcat, $1, $2); }
|
||||
{ $$ = fnode::binop(op::UConcat, $1, $2); }
|
||||
| bracedsere OP_UCONCAT error
|
||||
{ missing_right_binop_hard($$, $1, @2,
|
||||
"universal overlapping concat operator"); }
|
||||
| bracedsere OP_ECONCAT subformula
|
||||
{ $$ = binop::instance(binop::EConcat, $1, $3); }
|
||||
{ $$ = fnode::binop(op::EConcat, $1, $3); }
|
||||
| bracedsere OP_ECONCAT error
|
||||
{ missing_right_binop_hard($$, $1, @2,
|
||||
"existential overlapping concat operator");
|
||||
}
|
||||
| bracedsere OP_UCONCAT_NONO subformula
|
||||
/* {SERE}[]=>EXP = {SERE;1}[]->EXP */
|
||||
{ $$ = binop::instance(binop::UConcat,
|
||||
multop::instance(multop::Concat, $1,
|
||||
constant::true_instance()), $3);
|
||||
}
|
||||
{ $$ = fnode::binop(op::UConcat,
|
||||
fnode::multop(op::Concat, {$1, fnode::tt()}),
|
||||
$3); }
|
||||
| bracedsere OP_UCONCAT_NONO error
|
||||
{ missing_right_binop_hard($$, $1, @2,
|
||||
"universal non-overlapping concat operator");
|
||||
}
|
||||
| bracedsere OP_ECONCAT_NONO subformula
|
||||
/* {SERE}<>=>EXP = {SERE;1}<>->EXP */
|
||||
{ $$ = binop::instance(binop::EConcat,
|
||||
multop::instance(multop::Concat, $1,
|
||||
constant::true_instance()), $3);
|
||||
}
|
||||
{ $$ = fnode::binop(op::EConcat,
|
||||
fnode::multop(op::Concat, {$1, fnode::tt()}),
|
||||
$3); }
|
||||
| bracedsere OP_ECONCAT_NONO error
|
||||
{ missing_right_binop_hard($$, $1, @2,
|
||||
"existential non-overlapping concat operator");
|
||||
}
|
||||
| BRACE_OPEN sere BRACE_BANG_CLOSE
|
||||
/* {SERE}! = {SERE} <>-> 1 */
|
||||
{ $$ = binop::instance(binop::EConcat, $2,
|
||||
constant::true_instance()); }
|
||||
{ $$ = fnode::binop(op::EConcat, $2, fnode::tt()); }
|
||||
| BRA_BANG_BLOCK
|
||||
{
|
||||
$$ = try_recursive_parse(*$1, @1, parse_environment,
|
||||
debug_level(), parser_sere, error_list);
|
||||
debug_level(), parser_sere, error_list)
|
||||
.to_node_();
|
||||
delete $1;
|
||||
if (!$$)
|
||||
YYERROR;
|
||||
$$ = binop::instance(binop::EConcat, $$,
|
||||
constant::true_instance());
|
||||
$$ = fnode::binop(op::EConcat, $$, fnode::tt());
|
||||
}
|
||||
|
||||
lbtformula: ATOMIC_PROP
|
||||
{
|
||||
$$ = parse_environment.require(*$1);
|
||||
$$ = parse_environment.require(*$1).to_node_();
|
||||
if (! $$)
|
||||
{
|
||||
std::string s = "atomic proposition `";
|
||||
|
|
@ -950,37 +950,37 @@ lbtformula: ATOMIC_PROP
|
|||
delete $1;
|
||||
}
|
||||
| '!' lbtformula
|
||||
{ $$ = unop::instance(unop::Not, $2); }
|
||||
{ $$ = fnode::unop(op::Not, $2); }
|
||||
| '&' lbtformula lbtformula
|
||||
{ $$ = multop::instance(multop::And, $2, $3); }
|
||||
{ $$ = fnode::multop(op::And, {$2, $3}); }
|
||||
| '|' lbtformula lbtformula
|
||||
{ $$ = multop::instance(multop::Or, $2, $3); }
|
||||
{ $$ = fnode::multop(op::Or, {$2, $3}); }
|
||||
| '^' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::Xor, $2, $3); }
|
||||
{ $$ = fnode::binop(op::Xor, $2, $3); }
|
||||
| 'i' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::Implies, $2, $3); }
|
||||
{ $$ = fnode::binop(op::Implies, $2, $3); }
|
||||
| 'e' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::Equiv, $2, $3); }
|
||||
{ $$ = fnode::binop(op::Equiv, $2, $3); }
|
||||
| 'X' lbtformula
|
||||
{ $$ = unop::instance(unop::X, $2); }
|
||||
{ $$ = fnode::unop(op::X, $2); }
|
||||
| 'F' lbtformula
|
||||
{ $$ = unop::instance(unop::F, $2); }
|
||||
{ $$ = fnode::unop(op::F, $2); }
|
||||
| 'G' lbtformula
|
||||
{ $$ = unop::instance(unop::G, $2); }
|
||||
{ $$ = fnode::unop(op::G, $2); }
|
||||
| 'U' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::U, $2, $3); }
|
||||
{ $$ = fnode::binop(op::U, $2, $3); }
|
||||
| 'V' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::R, $2, $3); }
|
||||
{ $$ = fnode::binop(op::R, $2, $3); }
|
||||
| 'R' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::R, $2, $3); }
|
||||
{ $$ = fnode::binop(op::R, $2, $3); }
|
||||
| 'W' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::W, $2, $3); }
|
||||
{ $$ = fnode::binop(op::W, $2, $3); }
|
||||
| 'M' lbtformula lbtformula
|
||||
{ $$ = binop::instance(binop::M, $2, $3); }
|
||||
{ $$ = fnode::binop(op::M, $2, $3); }
|
||||
| 't'
|
||||
{ $$ = constant::true_instance(); }
|
||||
{ $$ = fnode::tt(); }
|
||||
| 'f'
|
||||
{ $$ = constant::false_instance(); }
|
||||
{ $$ = fnode::ff(); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
@ -995,13 +995,13 @@ namespace spot
|
|||
{
|
||||
namespace ltl
|
||||
{
|
||||
const formula*
|
||||
formula
|
||||
parse_infix_psl(const std::string& ltl_string,
|
||||
parse_error_list& error_list,
|
||||
environment& env,
|
||||
bool debug, bool lenient)
|
||||
{
|
||||
const formula* result = 0;
|
||||
formula result = nullptr;
|
||||
flex_set_buffer(ltl_string,
|
||||
ltlyy::parser::token::START_LTL,
|
||||
lenient);
|
||||
|
|
@ -1012,13 +1012,13 @@ namespace spot
|
|||
return result;
|
||||
}
|
||||
|
||||
const formula*
|
||||
formula
|
||||
parse_infix_boolean(const std::string& ltl_string,
|
||||
parse_error_list& error_list,
|
||||
environment& env,
|
||||
bool debug, bool lenient)
|
||||
{
|
||||
const formula* result = 0;
|
||||
formula result = nullptr;
|
||||
flex_set_buffer(ltl_string,
|
||||
ltlyy::parser::token::START_BOOL,
|
||||
lenient);
|
||||
|
|
@ -1029,13 +1029,13 @@ namespace spot
|
|||
return result;
|
||||
}
|
||||
|
||||
const formula*
|
||||
formula
|
||||
parse_prefix_ltl(const std::string& ltl_string,
|
||||
parse_error_list& error_list,
|
||||
environment& env,
|
||||
bool debug)
|
||||
{
|
||||
const formula* result = 0;
|
||||
formula result = nullptr;
|
||||
flex_set_buffer(ltl_string,
|
||||
ltlyy::parser::token::START_LBT,
|
||||
false);
|
||||
|
|
@ -1046,14 +1046,14 @@ namespace spot
|
|||
return result;
|
||||
}
|
||||
|
||||
const formula*
|
||||
formula
|
||||
parse_infix_sere(const std::string& sere_string,
|
||||
parse_error_list& error_list,
|
||||
environment& env,
|
||||
bool debug,
|
||||
bool lenient)
|
||||
{
|
||||
const formula* result = 0;
|
||||
formula result = nullptr;
|
||||
flex_set_buffer(sere_string,
|
||||
ltlyy::parser::token::START_SERE,
|
||||
lenient);
|
||||
|
|
@ -1064,16 +1064,16 @@ namespace spot
|
|||
return result;
|
||||
}
|
||||
|
||||
const formula*
|
||||
formula
|
||||
parse_formula(const std::string& ltl_string, environment& env)
|
||||
{
|
||||
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;
|
||||
if (format_parse_errors(s, ltl_string, pel))
|
||||
{
|
||||
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())
|
||||
return g;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ namespace spot
|
|||
/// \param lenient When true, parenthesized blocks that cannot be
|
||||
/// parsed as subformulas will be considered as
|
||||
/// atomic propositions.
|
||||
/// \return A pointer to the formula built from \a ltl_string, or
|
||||
/// 0 if the input was unparsable.
|
||||
/// \return A formula built from \a ltl_string, or
|
||||
/// formula(nullptr) if the input was unparsable.
|
||||
///
|
||||
/// Note that the parser usually tries to recover from errors. It can
|
||||
/// return a non zero value even if it encountered error during the
|
||||
|
|
@ -66,7 +66,7 @@ namespace spot
|
|||
///
|
||||
/// \warning This function is not reentrant.
|
||||
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,
|
||||
environment& env =
|
||||
default_environment::instance(),
|
||||
|
|
@ -82,8 +82,8 @@ namespace spot
|
|||
/// \param lenient When true, parenthesized blocks that cannot be
|
||||
/// parsed as subformulas will be considered as
|
||||
/// atomic propositions.
|
||||
/// \return A pointer to the formula built from \a ltl_string, or
|
||||
/// 0 if the input was unparsable.
|
||||
/// \return A formula built from \a ltl_string, or
|
||||
/// formula(nullptr) if the input was unparsable.
|
||||
///
|
||||
/// Note that the parser usually tries to recover from errors. It can
|
||||
/// return a non zero value even if it encountered error during the
|
||||
|
|
@ -92,7 +92,7 @@ namespace spot
|
|||
///
|
||||
/// \warning This function is not reentrant.
|
||||
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,
|
||||
environment& env =
|
||||
default_environment::instance(),
|
||||
|
|
@ -105,8 +105,8 @@ namespace spot
|
|||
/// parse errors that occured during parsing.
|
||||
/// \param env The environment into which parsing should take place.
|
||||
/// \param debug When true, causes the parser to trace its execution.
|
||||
/// \return A pointer to the formula built from \a ltl_string, or
|
||||
/// 0 if the input was unparsable.
|
||||
/// \return A formula built from \a ltl_string, or
|
||||
/// formula(nullptr) if the input was unparsable.
|
||||
///
|
||||
/// Note that the parser usually tries to recover from errors. It can
|
||||
/// return an non zero value even if it encountered error during the
|
||||
|
|
@ -119,7 +119,7 @@ namespace spot
|
|||
///
|
||||
/// \warning This function is not reentrant.
|
||||
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,
|
||||
environment& env =
|
||||
default_environment::instance(),
|
||||
|
|
@ -131,7 +131,7 @@ namespace spot
|
|||
/// parse_infix_psl(); if this fails it tries parse_prefix_ltl();
|
||||
/// and if both fails it returns the errors of the first call to
|
||||
/// parse_infix_psl() as a parse_error exception.
|
||||
SPOT_API const formula*
|
||||
SPOT_API formula
|
||||
parse_formula(const std::string& ltl_string,
|
||||
environment& env = default_environment::instance());
|
||||
|
||||
|
|
@ -144,8 +144,8 @@ namespace spot
|
|||
/// \param lenient When true, parenthesized blocks that cannot be
|
||||
/// parsed as subformulas will be considered as
|
||||
/// atomic propositions.
|
||||
/// \return A pointer to the formula built from \a sere_string, or
|
||||
/// 0 if the input was unparsable.
|
||||
/// \return A formula built from \a sere_string, or
|
||||
/// formula(0) if the input was unparsable.
|
||||
///
|
||||
/// Note that the parser usually tries to recover from errors. It can
|
||||
/// return an non zero value even if it encountered error during the
|
||||
|
|
@ -154,7 +154,7 @@ namespace spot
|
|||
///
|
||||
/// \warning This function is not reentrant.
|
||||
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,
|
||||
environment& env =
|
||||
default_environment::instance(),
|
||||
|
|
@ -181,11 +181,10 @@ namespace spot
|
|||
|
||||
/// \brief Fix location of diagnostics assuming the input is utf8.
|
||||
///
|
||||
/// The spot::ltl::parse() and spot::ltl::parse_sere() function
|
||||
/// return a parse_error_list that contain locations specified at
|
||||
/// the byte level. Although these parser recognize some
|
||||
/// utf8 characters they only work byte by byte and will report
|
||||
/// positions by counting byte.
|
||||
/// The different parser functions return a parse_error_list that
|
||||
/// contain locations specified at the byte level. Although these
|
||||
/// parser recognize some utf8 characters they only work byte by
|
||||
/// byte and will report positions by counting byte.
|
||||
///
|
||||
/// This function fixes the positions returned by the parser to
|
||||
/// look correct when the string is interpreted as a utf8-encoded
|
||||
|
|
|
|||
|
|
@ -28,15 +28,12 @@ ltlvisitdir = $(pkgincludedir)/ltlvisit
|
|||
ltlvisit_HEADERS = \
|
||||
apcollect.hh \
|
||||
contain.hh \
|
||||
clone.hh \
|
||||
dot.hh \
|
||||
dump.hh \
|
||||
exclusive.hh \
|
||||
length.hh \
|
||||
mutation.hh \
|
||||
nenoform.hh \
|
||||
print.hh \
|
||||
postfix.hh \
|
||||
randomltl.hh \
|
||||
relabel.hh \
|
||||
remove_x.hh \
|
||||
|
|
@ -49,9 +46,7 @@ noinst_LTLIBRARIES = libltlvisit.la
|
|||
libltlvisit_la_SOURCES = \
|
||||
apcollect.cc \
|
||||
contain.cc \
|
||||
clone.cc \
|
||||
dot.cc \
|
||||
dump.cc \
|
||||
exclusive.cc \
|
||||
length.cc \
|
||||
mark.cc \
|
||||
|
|
@ -59,7 +54,6 @@ libltlvisit_la_SOURCES = \
|
|||
mutation.cc \
|
||||
nenoform.cc \
|
||||
print.cc \
|
||||
postfix.cc \
|
||||
randomltl.cc \
|
||||
relabel.cc \
|
||||
remove_x.cc \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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).
|
||||
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// 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/>.
|
||||
|
||||
#include "apcollect.hh"
|
||||
#include "ltlvisit/postfix.hh"
|
||||
#include "twa/twa.hh"
|
||||
#include "twa/bdddict.hh"
|
||||
|
||||
|
|
@ -29,70 +28,40 @@ namespace spot
|
|||
{
|
||||
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 res;
|
||||
auto& e = spot::ltl::default_environment::instance();
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
{
|
||||
std::ostringstream p;
|
||||
p << 'p' << i;
|
||||
res.insert(e.require(p.str()));
|
||||
res.insert(formula::ap(p.str()));
|
||||
}
|
||||
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_collect(const formula* f, atomic_prop_set* s)
|
||||
atomic_prop_collect(formula f, atomic_prop_set* s)
|
||||
{
|
||||
if (!s)
|
||||
s = new atomic_prop_set;
|
||||
atomic_prop_collector v(s);
|
||||
f->accept(v);
|
||||
f.traverse([&](const formula& f)
|
||||
{
|
||||
if (f.is(op::AP))
|
||||
s->insert(f);
|
||||
return false;
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
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;
|
||||
atomic_prop_collect(f, &aps);
|
||||
bdd res = bddtrue;
|
||||
for (atomic_prop_set::const_iterator i = aps.begin();
|
||||
i != aps.end(); ++i)
|
||||
res &= bdd_ithvar(a->register_ap(*i));
|
||||
for (auto f: aps)
|
||||
res &= bdd_ithvar(a->register_ap(f));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ltlast/atomic_prop.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
#include <set>
|
||||
#include <bddx.h>
|
||||
#include "twa/fwd.hh"
|
||||
|
|
@ -35,18 +35,12 @@ namespace spot
|
|||
/// @{
|
||||
|
||||
/// Set of atomic propositions.
|
||||
typedef std::set<const atomic_prop*,
|
||||
formula_ptr_less_than> atomic_prop_set;
|
||||
typedef std::set<formula> atomic_prop_set;
|
||||
|
||||
/// \brief construct an atomic_prop_set with n propositions
|
||||
SPOT_API
|
||||
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.
|
||||
///
|
||||
/// \param f the formula to inspect
|
||||
|
|
@ -55,10 +49,8 @@ namespace spot
|
|||
/// \return A pointer to the supplied set, \c s, augmented with
|
||||
/// atomic propositions occurring in \c f; or a newly allocated
|
||||
/// 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*
|
||||
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
|
||||
/// formula, as a BDD.
|
||||
|
|
@ -67,8 +59,7 @@ namespace spot
|
|||
/// \param a that automaton that should register the BDD variables used.
|
||||
/// \return A conjunction the atomic propositions.
|
||||
SPOT_API bdd
|
||||
atomic_prop_collect_as_bdd(const formula* f,
|
||||
const twa_ptr& a);
|
||||
atomic_prop_collect_as_bdd(formula f, 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 "simplify.hh"
|
||||
#include "ltlast/unop.hh"
|
||||
#include "ltlast/binop.hh"
|
||||
#include "ltlast/multop.hh"
|
||||
#include "ltlast/constant.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
#include "twaalgos/product.hh"
|
||||
|
||||
namespace spot
|
||||
|
|
@ -50,13 +47,7 @@ namespace spot
|
|||
void
|
||||
language_containment_checker::clear()
|
||||
{
|
||||
while (!translated_.empty())
|
||||
{
|
||||
trans_map::iterator i = translated_.begin();
|
||||
const formula* f = i->first;
|
||||
translated_.erase(i);
|
||||
f->destroy();
|
||||
}
|
||||
translated_.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -75,31 +66,26 @@ namespace spot
|
|||
|
||||
// Check whether L(l) is a subset of L(g).
|
||||
bool
|
||||
language_containment_checker::contained(const formula* l,
|
||||
const formula* g)
|
||||
language_containment_checker::contained(formula l,
|
||||
formula g)
|
||||
{
|
||||
if (l == g)
|
||||
return true;
|
||||
record_* rl = register_formula_(l);
|
||||
const formula* ng = unop::instance(unop::Not, g->clone());
|
||||
record_* rng = register_formula_(ng);
|
||||
ng->destroy();
|
||||
record_* rng = register_formula_(formula::Not(g));
|
||||
return incompatible_(rl, rng);
|
||||
}
|
||||
|
||||
// Check whether L(!l) is a subset of L(g).
|
||||
bool
|
||||
language_containment_checker::neg_contained(const formula* l,
|
||||
const formula* g)
|
||||
language_containment_checker::neg_contained(formula l,
|
||||
formula g)
|
||||
{
|
||||
if (l == g)
|
||||
return false;
|
||||
const formula* nl = unop::instance(unop::Not, l->clone());
|
||||
formula nl = formula::Not(l);
|
||||
record_* rnl = register_formula_(nl);
|
||||
const formula* ng = unop::instance(unop::Not, g->clone());
|
||||
record_* rng = register_formula_(ng);
|
||||
nl->destroy();
|
||||
ng->destroy();
|
||||
record_* rng = register_formula_(formula::Not(g));
|
||||
if (nl == g)
|
||||
return true;
|
||||
return incompatible_(rnl, rng);
|
||||
|
|
@ -107,8 +93,8 @@ namespace spot
|
|||
|
||||
// Check whether L(l) is a subset of L(!g).
|
||||
bool
|
||||
language_containment_checker::contained_neg(const formula* l,
|
||||
const formula* g)
|
||||
language_containment_checker::contained_neg(formula l,
|
||||
formula g)
|
||||
{
|
||||
if (l == g)
|
||||
return false;
|
||||
|
|
@ -119,13 +105,13 @@ namespace spot
|
|||
|
||||
// Check whether L(l) = L(g).
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (i != translated_.end())
|
||||
|
|
@ -133,17 +119,17 @@ namespace spot
|
|||
|
||||
auto e = ltl_to_tgba_fm(f, dict_, exprop_, symb_merge_,
|
||||
branching_postponement_, fair_loop_approx_);
|
||||
record_& r = translated_[f->clone()];
|
||||
record_& r = translated_[f];
|
||||
r.translation = e;
|
||||
return &r;
|
||||
}
|
||||
|
||||
|
||||
const formula*
|
||||
reduce_tau03(const formula* f, bool stronger)
|
||||
formula
|
||||
reduce_tau03(formula f, bool stronger)
|
||||
{
|
||||
if (!f->is_psl_formula())
|
||||
return f->clone();
|
||||
if (!f.is_psl_formula())
|
||||
return f;
|
||||
|
||||
ltl_simplifier_options opt(false, false, false,
|
||||
true, stronger);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace spot
|
|||
typedef std::map<const record_*, bool> incomp_map;
|
||||
incomp_map incompatible;
|
||||
};
|
||||
typedef std::unordered_map<const formula*, record_> trans_map;
|
||||
typedef std::unordered_map<formula, record_> trans_map;
|
||||
public:
|
||||
/// This class uses spot::ltl_to_tgba_fm to translate LTL
|
||||
/// formulae. See that function for the meaning of these options.
|
||||
|
|
@ -55,19 +55,19 @@ namespace spot
|
|||
void clear();
|
||||
|
||||
/// 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).
|
||||
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).
|
||||
bool contained_neg(const formula* l, const formula* g);
|
||||
bool contained_neg(formula l, formula g);
|
||||
|
||||
/// Check whether L(l) = L(g).
|
||||
bool equal(const formula* l, const formula* g);
|
||||
bool equal(formula l, formula g);
|
||||
|
||||
protected:
|
||||
bool incompatible_(record_* l, record_* g);
|
||||
|
||||
record_* register_formula_(const formula* f);
|
||||
record_* register_formula_(formula f);
|
||||
|
||||
/* Translation options */
|
||||
bdd_dict_ptr dict_;
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@
|
|||
// 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 "misc/hash.hh"
|
||||
#include "dot.hh"
|
||||
#include "ltlast/visitor.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
#include <unordered_map>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
|
|
@ -33,160 +32,106 @@ namespace spot
|
|||
{
|
||||
namespace
|
||||
{
|
||||
class dotty_visitor: public visitor
|
||||
struct dot_printer final
|
||||
{
|
||||
public:
|
||||
typedef std::unordered_map<const formula*, int, ptr_hash<formula>> map;
|
||||
dotty_visitor(std::ostream& os, map& m)
|
||||
: os_(os), father_(-1), node_(m), sinks_(new std::ostringstream)
|
||||
std::ostream& os_;
|
||||
std::unordered_map<formula, int> node_;
|
||||
std::ostringstream* sinks_;
|
||||
|
||||
dot_printer(std::ostream& os, formula f)
|
||||
: os_(os), sinks_(new std::ostringstream)
|
||||
{
|
||||
os_ << "digraph G {\n";
|
||||
rec(f);
|
||||
os_ << " subgraph atoms {\n rank=sink;\n"
|
||||
<< sinks_->str() << " }\n}\n";
|
||||
}
|
||||
|
||||
virtual
|
||||
~dotty_visitor()
|
||||
~dot_printer()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
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_;
|
||||
}
|
||||
|
||||
int childnum;
|
||||
|
||||
private:
|
||||
std::ostream& os_;
|
||||
int father_;
|
||||
map& node_;
|
||||
std::ostringstream* sinks_;
|
||||
|
||||
bool
|
||||
draw_node_(const formula* f, const std::string& str, bool sink = false)
|
||||
int rec(formula f)
|
||||
{
|
||||
map::iterator i = node_.find(f);
|
||||
int node;
|
||||
bool node_exists = false;
|
||||
if (i != node_.end())
|
||||
{
|
||||
node = i->second;
|
||||
node_exists = true;
|
||||
}
|
||||
auto i = node_.emplace(f, node_.size());
|
||||
int src = i.first->second;
|
||||
if (!i.second)
|
||||
return src;
|
||||
|
||||
op o = f.kind();
|
||||
std::string str = (o == op::AP) ? f.ap_name() : f.kindstr();
|
||||
|
||||
if (o == op::AP || f.is_constant())
|
||||
*sinks_ << " " << src << " [label=\""
|
||||
<< str << "\", shape=box];\n";
|
||||
else
|
||||
os_ << " " << src << " [label=\"" << str << "\"];\n";
|
||||
|
||||
int childnum = 0;
|
||||
switch (o)
|
||||
{
|
||||
node = node_.size();
|
||||
node_[f] = node;
|
||||
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::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)
|
||||
os_ << " [taillabel=\"" << childnum << "\"]";
|
||||
if (childnum == -1)
|
||||
if (childnum == -2)
|
||||
os_ << " [taillabel=\"L\"]";
|
||||
else if (childnum == -2)
|
||||
else if (childnum == -1)
|
||||
os_ << " [taillabel=\"R\"]";
|
||||
os_ << ";\n";
|
||||
++childnum;
|
||||
}
|
||||
father_ = node;
|
||||
|
||||
// the node
|
||||
if (node_exists)
|
||||
return false;
|
||||
|
||||
if (!sink)
|
||||
{
|
||||
os_ << " " << node << " [label=\"" << str << "\"];";
|
||||
}
|
||||
else
|
||||
{
|
||||
*sinks_ << " " << node
|
||||
<< " [label=\"" << str << "\", shape=box];\n";
|
||||
}
|
||||
return true;
|
||||
return src;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
print_dot_psl(std::ostream& os, const formula* f)
|
||||
print_dot_psl(std::ostream& os, formula f)
|
||||
{
|
||||
dotty_visitor::map m;
|
||||
dotty_visitor v(os, m);
|
||||
os << "digraph G {\n";
|
||||
f->accept(v);
|
||||
v.finish();
|
||||
os << '}' << std::endl;
|
||||
dot_printer p(os, f);
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <ltlast/formula.hh>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -37,6 +36,6 @@ namespace spot
|
|||
/// \c dot is part of the GraphViz package
|
||||
/// http://www.graphviz.org/
|
||||
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/>.
|
||||
|
||||
#include "exclusive.hh"
|
||||
#include "ltlenv/defaultenv.hh"
|
||||
#include "ltlast/multop.hh"
|
||||
#include "ltlast/unop.hh"
|
||||
#include "ltlast/constant.hh"
|
||||
#include "twaalgos/mask.hh"
|
||||
#include "misc/casts.hh"
|
||||
#include "misc/minato.hh"
|
||||
|
|
@ -29,20 +25,12 @@
|
|||
|
||||
namespace spot
|
||||
{
|
||||
exclusive_ap::~exclusive_ap()
|
||||
{
|
||||
for (auto& g: groups)
|
||||
for (auto ap: g)
|
||||
ap->destroy();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static const std::vector<const spot::ltl::atomic_prop*>
|
||||
static const std::vector<ltl::formula>
|
||||
split_aps(const char* arg)
|
||||
{
|
||||
auto& env = spot::ltl::default_environment::instance();
|
||||
std::vector<const spot::ltl::atomic_prop*> group;
|
||||
std::vector<ltl::formula> group;
|
||||
auto start = arg;
|
||||
while (*start)
|
||||
{
|
||||
|
|
@ -73,8 +61,7 @@ namespace spot
|
|||
throw std::invalid_argument(s);
|
||||
}
|
||||
std::string ap(start, end - start);
|
||||
auto* t = env.require(ap);
|
||||
group.push_back(down_cast<const spot::ltl::atomic_prop*>(t));
|
||||
group.emplace_back(ltl::formula::ap(ap));
|
||||
do
|
||||
++end;
|
||||
while (*end == ' ' || *end == '\t');
|
||||
|
|
@ -99,8 +86,7 @@ namespace spot
|
|||
while (rend > start && (rend[-1] == ' ' || rend[-1] == '\t'))
|
||||
--rend;
|
||||
std::string ap(start, rend - start);
|
||||
auto* t = env.require(ap);
|
||||
group.push_back(down_cast<const spot::ltl::atomic_prop*>(t));
|
||||
group.emplace_back(ltl::formula::ap(ap));
|
||||
if (*end == ',')
|
||||
start = end + 1;
|
||||
else
|
||||
|
|
@ -116,29 +102,27 @@ namespace spot
|
|||
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);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const ltl::formula*
|
||||
nand(const ltl::formula* lhs, const ltl::formula* rhs)
|
||||
ltl::formula
|
||||
nand(ltl::formula lhs, ltl::formula rhs)
|
||||
{
|
||||
auto f = ltl::multop::instance(ltl::multop::And,
|
||||
lhs->clone(), rhs->clone());
|
||||
return ltl::unop::instance(ltl::unop::Not, f);
|
||||
return ltl::formula::Not(ltl::formula::And({lhs, rhs}));
|
||||
}
|
||||
}
|
||||
|
||||
const ltl::formula*
|
||||
exclusive_ap::constrain(const ltl::formula* f) const
|
||||
ltl::formula
|
||||
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;
|
||||
ltl::multop::vec* v = new ltl::multop::vec;
|
||||
std::vector<ltl::formula> group;
|
||||
std::vector<ltl::formula> v;
|
||||
|
||||
for (auto& g: groups)
|
||||
{
|
||||
|
|
@ -151,14 +135,11 @@ namespace spot
|
|||
unsigned s = group.size();
|
||||
for (unsigned j = 0; j < s; ++j)
|
||||
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;
|
||||
|
||||
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);
|
||||
return ltl::formula::And({f, ltl::formula::G(ltl::formula::And(v))});
|
||||
}
|
||||
|
||||
twa_graph_ptr exclusive_ap::constrain(const_twa_graph_ptr aut,
|
||||
|
|
|
|||
|
|
@ -20,19 +20,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "ltlast/atomic_prop.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
#include "twa/twagraph.hh"
|
||||
|
||||
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:
|
||||
~exclusive_ap();
|
||||
#ifndef SWIG
|
||||
void add_group(std::vector<const ltl::atomic_prop*> ap);
|
||||
void add_group(std::vector<ltl::formula> ap);
|
||||
#endif
|
||||
void add_group(const char* ap_csv);
|
||||
|
||||
|
|
@ -41,7 +39,7 @@ namespace spot
|
|||
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,
|
||||
bool simplify_guards = false) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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).
|
||||
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// 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/>.
|
||||
|
||||
#include "length.hh"
|
||||
#include "ltlvisit/postfix.hh"
|
||||
#include "ltlast/multop.hh"
|
||||
#include "ltlast/unop.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace ltl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
class length_visitor: public postfix_visitor
|
||||
{
|
||||
public:
|
||||
length_visitor()
|
||||
: result_(0)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
result() const
|
||||
length(formula f)
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
virtual void
|
||||
visit(const multop* mo)
|
||||
int len = 0;
|
||||
f.traverse([&len](const formula& x)
|
||||
{
|
||||
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;
|
||||
auto s = x.size();
|
||||
if (s > 1)
|
||||
len += s - 1;
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
++len;
|
||||
return false;
|
||||
});
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
length(const formula* f)
|
||||
length_boolone(formula f)
|
||||
{
|
||||
length_visitor v;
|
||||
f->accept(v);
|
||||
return v.result();
|
||||
int len = 0;
|
||||
f.traverse([&len](const formula& x)
|
||||
{
|
||||
if (x.is_boolean())
|
||||
{
|
||||
++len;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
length_boolone(const formula* f)
|
||||
auto s = x.size();
|
||||
if (s > 2)
|
||||
{
|
||||
length_boolone_visitor v;
|
||||
f->accept(v);
|
||||
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 -*-
|
||||
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Developement de
|
||||
// l'Epita (LRDE).
|
||||
// Copyright (C) 2012, 2013, 2015 Laboratoire de Recherche et
|
||||
// Développement de l'Epita (LRDE).
|
||||
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||
// et Marie Curie.
|
||||
|
|
@ -33,15 +33,14 @@ namespace spot
|
|||
///
|
||||
/// The length of a formula is the number of atomic propositions,
|
||||
/// constants, and operators (logical and temporal) occurring in
|
||||
/// the formula. spot::ltl::multop instances with n arguments
|
||||
/// count for n-1; for instance <code>a | b | c</code> has length
|
||||
/// 5, even if there is only as single <code>|</code> node
|
||||
/// internally.
|
||||
/// the formula. n-ary operators count for n-1; for instance
|
||||
/// <code>a | b | c</code> has length 5, even if there is only as
|
||||
/// single <code>|</code> node internally.
|
||||
///
|
||||
/// If squash_boolean is set, all Boolean formulae are assumed
|
||||
/// to have length one.
|
||||
SPOT_API
|
||||
int length(const formula* f);
|
||||
int length(formula f);
|
||||
|
||||
/// \ingroup ltl_misc
|
||||
/// \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
|
||||
/// formulae are assumed to have length one.
|
||||
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/>.
|
||||
|
||||
#include "mark.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "misc/casts.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace ltl
|
||||
{
|
||||
namespace
|
||||
formula
|
||||
mark_tools::mark_concat_ops(formula f)
|
||||
{
|
||||
class simplify_mark_visitor : public visitor
|
||||
{
|
||||
const formula* result_;
|
||||
mark_tools* tools_;
|
||||
f2f_map::iterator i = markops_.find(f);
|
||||
if (i != markops_.end())
|
||||
return i->second;
|
||||
|
||||
public:
|
||||
simplify_mark_visitor(mark_tools* t)
|
||||
: tools_(t)
|
||||
ltl::formula res;
|
||||
switch (f.kind())
|
||||
{
|
||||
}
|
||||
|
||||
~simplify_mark_visitor()
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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:
|
||||
return this->mark_concat_ops(f);
|
||||
});
|
||||
break;
|
||||
case op::Xor:
|
||||
case op::Implies:
|
||||
case op::Equiv:
|
||||
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;
|
||||
markops_[f] = res;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (const unop* uo = is_unop(f))
|
||||
|
||||
formula
|
||||
mark_tools::simplify_mark(formula f)
|
||||
{
|
||||
switch (uo->op())
|
||||
if (!f.is_marked())
|
||||
return f;
|
||||
|
||||
f2f_map::iterator i = simpmark_.find(f);
|
||||
if (i != simpmark_.end())
|
||||
return i->second;
|
||||
|
||||
auto recurse = [this](formula f)
|
||||
{
|
||||
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));
|
||||
return this->simplify_mark(f);
|
||||
};
|
||||
|
||||
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::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 unop::NegClosure:
|
||||
nlist.push_back(uo);
|
||||
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
|
||||
{
|
||||
res->push_back(recurse(f));
|
||||
v.push_back(c);
|
||||
}
|
||||
}
|
||||
// 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()))
|
||||
for (auto e: elist)
|
||||
if (empairs.find(std::make_pair(e.nth(0), e.nth(1)))
|
||||
== empairs.end())
|
||||
res->push_back((*i)->clone());
|
||||
v.push_back(e);
|
||||
// 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());
|
||||
for (auto n: nlist)
|
||||
if (nmset.find(n.nth(0)) == nmset.end())
|
||||
v.push_back(n);
|
||||
res = ltl::formula::And(v);
|
||||
}
|
||||
}
|
||||
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:
|
||||
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();
|
||||
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);
|
||||
if (i != markops_.end())
|
||||
return i->second->clone();
|
||||
|
||||
f->accept(*markvisitor_);
|
||||
|
||||
const formula* r = down_cast<mark_visitor*>(markvisitor_)->result();
|
||||
markops_[f->clone()] = r->clone();
|
||||
return r;
|
||||
}
|
||||
|
||||
const formula*
|
||||
mark_tools::simplify_mark(const formula* f)
|
||||
{
|
||||
if (!f->is_marked())
|
||||
return f->clone();
|
||||
|
||||
f2f_map::iterator i = simpmark_.find(f);
|
||||
if (i != simpmark_.end())
|
||||
return i->second->clone();
|
||||
|
||||
f->accept(*simpvisitor_);
|
||||
|
||||
const formula* r =
|
||||
down_cast<simplify_mark_visitor*>(simpvisitor_)->result();
|
||||
simpmark_[f->clone()] = r->clone();
|
||||
return r;
|
||||
simpmark_[f] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2010, 2011, 2012, 2013 Laboratoire de Recherche et
|
||||
// Développement de l'Epita (LRDE).
|
||||
// Copyright (C) 2010, 2011, 2012, 2013, 2015 Laboratoire de Recherche
|
||||
// et Développement de l'Epita (LRDE).
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
//
|
||||
|
|
@ -20,34 +20,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "ltlast/formula.hh"
|
||||
#include "ltlast/visitor.hh"
|
||||
#include "misc/hash.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace ltl
|
||||
{
|
||||
class mark_tools
|
||||
class mark_tools final
|
||||
{
|
||||
public:
|
||||
/// \ingroup ltl_rewriting
|
||||
/// \brief Mark operators NegClosure and EConcat.
|
||||
///
|
||||
/// \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);
|
||||
|
||||
mark_tools();
|
||||
~mark_tools();
|
||||
formula simplify_mark(formula f);
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<const formula*, const formula*,
|
||||
ptr_hash<formula>> f2f_map;
|
||||
typedef std::unordered_map<formula, formula> f2f_map;
|
||||
f2f_map simpmark_;
|
||||
f2f_map markops_;
|
||||
visitor* simpvisitor_;
|
||||
visitor* markvisitor_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,28 +17,18 @@
|
|||
// 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 <unordered_set>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlvisit/apcollect.hh"
|
||||
#include "ltlvisit/clone.hh"
|
||||
#include "ltlvisit/mutation.hh"
|
||||
#include "ltlvisit/length.hh"
|
||||
#include "misc/hash.hh"
|
||||
|
||||
#define Implies_(x, y) \
|
||||
spot::ltl::binop::instance(spot::ltl::binop::Implies, (x), (y))
|
||||
#define And_(x, y) \
|
||||
spot::ltl::multop::instance(spot::ltl::multop::And, (x), (y))
|
||||
#define AndRat_(x, y) \
|
||||
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))
|
||||
#define And_(x, y) formula::And({(x), (y)})
|
||||
#define AndRat_(x, y) formula::AndRat({(x), (y)})
|
||||
#define AndNLM_(x) formula::AndNLM(x)
|
||||
#define Concat_(x, y) formula::Concat({(x), (y)})
|
||||
#define Not_(x) formula::Not(x)
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -46,233 +36,91 @@ namespace spot
|
|||
{
|
||||
namespace
|
||||
{
|
||||
class replace_visitor final : public clone_visitor
|
||||
formula substitute_ap(formula f, formula ap_src, formula ap_dst)
|
||||
{
|
||||
public:
|
||||
void visit(const atomic_prop* ap)
|
||||
return f.map([&](formula f)
|
||||
{
|
||||
if (ap == ap1_)
|
||||
result_ = ap2_->clone();
|
||||
if (f == ap_src)
|
||||
return ap_dst;
|
||||
else
|
||||
result_ = ap->clone();
|
||||
return substitute_ap(f, ap_src, ap_dst);
|
||||
});
|
||||
}
|
||||
|
||||
const formula*
|
||||
replace(const formula* f,
|
||||
const atomic_prop* ap1,
|
||||
const atomic_prop* ap2)
|
||||
typedef std::vector<formula> vec;
|
||||
class mutator final
|
||||
{
|
||||
int mutation_counter_ = 0;
|
||||
formula f_;
|
||||
unsigned opts_;
|
||||
public:
|
||||
mutator(formula f, unsigned opts) : f_(f), opts_(opts)
|
||||
{
|
||||
ap1_ = ap1;
|
||||
ap2_ = ap2;
|
||||
return recurse(f);
|
||||
}
|
||||
|
||||
private:
|
||||
const atomic_prop* ap1_;
|
||||
const atomic_prop* ap2_;
|
||||
formula mutate(formula f)
|
||||
{
|
||||
auto recurse = [this](formula f)
|
||||
{
|
||||
return this->mutate(f);
|
||||
};
|
||||
|
||||
typedef std::vector<const formula*> vec;
|
||||
class mutation_visitor final : public clone_visitor
|
||||
switch (f.kind())
|
||||
{
|
||||
public:
|
||||
mutation_visitor(const formula* f, unsigned opts) : f_(f), opts_(opts)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(const atomic_prop* ap)
|
||||
{
|
||||
result_ = 0;
|
||||
case op::False:
|
||||
case op::True:
|
||||
case op::EmptyWord:
|
||||
return f;
|
||||
case op::AP:
|
||||
if (opts_ & Mut_Ap2Const)
|
||||
{
|
||||
if (mutation_counter_-- == 0)
|
||||
result_ = constant::true_instance();
|
||||
return formula::tt();
|
||||
if (mutation_counter_-- == 0)
|
||||
result_ = constant::false_instance();
|
||||
return formula::ff();
|
||||
}
|
||||
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)
|
||||
return f;
|
||||
case op::Not:
|
||||
case op::X:
|
||||
case op::F:
|
||||
case op::G:
|
||||
if ((opts_ & Mut_Remove_Ops)
|
||||
&& mutation_counter_-- == 0)
|
||||
result_ = uo->child()->clone();
|
||||
}
|
||||
if (!result_)
|
||||
{
|
||||
return f.nth(0);
|
||||
// fall through
|
||||
case op::Closure:
|
||||
case op::NegClosure:
|
||||
case op::NegClosureMarked:
|
||||
if (mutation_counter_ < 0)
|
||||
result_ = uo->clone();
|
||||
return f;
|
||||
else
|
||||
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:
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
const formula* c = bu->child()->clone();
|
||||
result_ = nullptr;
|
||||
auto op = bu->op();
|
||||
|
||||
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
|
||||
result_ = c;
|
||||
if (opts_ & Mut_Simplify_Bounds)
|
||||
{
|
||||
auto min = bu->min();
|
||||
auto max = bu->max();
|
||||
if (min > 0)
|
||||
{
|
||||
if (mutation_counter_-- == 0)
|
||||
result_ = bunop::instance(op, c, min - 1, max);
|
||||
if (mutation_counter_-- == 0)
|
||||
result_ = bunop::instance(op, c, 0, max);
|
||||
}
|
||||
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;
|
||||
|
||||
int mos = f.size();
|
||||
if (opts_ & Mut_Remove_Multop_Operands)
|
||||
{
|
||||
for (i = 0; i < mos; ++i)
|
||||
for (int i = 0; i < mos; ++i)
|
||||
if (mutation_counter_-- == 0)
|
||||
result_ = mo->all_but(i);
|
||||
return f.all_but(i);
|
||||
}
|
||||
|
||||
if (opts_ & Mut_Split_Ops && mo->op() == multop::AndNLM)
|
||||
if (opts_ & Mut_Split_Ops && f.is(op::AndNLM))
|
||||
{
|
||||
if (mutation_counter_ >= 0 && mutation_counter_ < 2 * (mos - 1))
|
||||
if (mutation_counter_ >= 0
|
||||
&& mutation_counter_ < 2 * (mos - 1))
|
||||
{
|
||||
vec* v1 = new vec();
|
||||
vec* v2 = new vec();
|
||||
v1->push_back(mo->nth(0)->clone());
|
||||
vec v1;
|
||||
vec v2;
|
||||
v1.push_back(f.nth(0));
|
||||
bool reverse = false;
|
||||
i = 1;
|
||||
int i = 1;
|
||||
while (i < mos)
|
||||
{
|
||||
if (mutation_counter_-- == 0)
|
||||
|
|
@ -282,119 +130,213 @@ namespace spot
|
|||
reverse = true;
|
||||
break;
|
||||
}
|
||||
v1->push_back(mo->nth(i++)->clone());
|
||||
v1.push_back(f.nth(i++));
|
||||
}
|
||||
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);
|
||||
v2.push_back(f.nth(i));
|
||||
formula first = AndNLM_(v1);
|
||||
formula second = AndNLM_(v2);
|
||||
formula ost = formula::one_star();
|
||||
if (!reverse)
|
||||
result_ = AndRat_(Concat_(first, tstar), second);
|
||||
return AndRat_(Concat_(first, ost), second);
|
||||
else
|
||||
result_ = AndRat_(Concat_(second, tstar), first);
|
||||
return AndRat_(Concat_(second, ost), first);
|
||||
}
|
||||
else
|
||||
{
|
||||
mutation_counter_ -= 2 * (mos - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result_)
|
||||
{
|
||||
if (mutation_counter_ < 0)
|
||||
result_ = mo->clone();
|
||||
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:
|
||||
{
|
||||
vec* v = new vec();
|
||||
for (i = 0; i < mos; ++i)
|
||||
v->push_back(recurse(mo->nth(i)));
|
||||
result_ = multop::instance(mo->op(), v);
|
||||
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*
|
||||
recurse(const formula* f)
|
||||
{
|
||||
f->accept(*this);
|
||||
return result_;
|
||||
}
|
||||
|
||||
const formula*
|
||||
formula
|
||||
get_mutation(int n)
|
||||
{
|
||||
mutation_counter_ = n;
|
||||
const formula* mut = recurse(f_);
|
||||
formula mut = mutate(f_);
|
||||
if (mut == f_)
|
||||
{
|
||||
mut->destroy();
|
||||
return 0;
|
||||
}
|
||||
return nullptr;
|
||||
return mut;
|
||||
}
|
||||
|
||||
private:
|
||||
const formula* f_;
|
||||
int mutation_counter_ = 0;
|
||||
unsigned opts_;
|
||||
};
|
||||
|
||||
bool
|
||||
formula_length_less_than(const formula* left, const formula* right)
|
||||
formula_length_less_than(formula left, formula right)
|
||||
{
|
||||
assert(left);
|
||||
assert(right);
|
||||
assert(left != nullptr);
|
||||
assert(right != nullptr);
|
||||
if (left == right)
|
||||
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
|
||||
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)
|
||||
{
|
||||
if (m == 0)
|
||||
{
|
||||
if (mutations.insert(f).second)
|
||||
{
|
||||
f->clone();
|
||||
--n;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const formula* mut(nullptr);
|
||||
formula mut;
|
||||
int i = 0;
|
||||
mutation_visitor mv(f, opts);
|
||||
while (n > 0 && (mut = mv.get_mutation(i++)))
|
||||
{
|
||||
mutator mv(f, opts);
|
||||
while (n > 0 && ((mut = mv.get_mutation(i++)) != nullptr))
|
||||
single_mutation_rec(mut, mutations, opts, n, m - 1);
|
||||
mut->destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (m == 0)
|
||||
{
|
||||
if (mutations.insert(f).second)
|
||||
{
|
||||
f->clone();
|
||||
--n;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!n)
|
||||
return;
|
||||
replace_visitor rv;
|
||||
auto aps =
|
||||
std::unique_ptr<atomic_prop_set>(atomic_prop_collect(f));
|
||||
for (auto ap1: *aps)
|
||||
|
|
@ -402,9 +344,8 @@ namespace spot
|
|||
{
|
||||
if (ap1 == ap2)
|
||||
continue;
|
||||
auto mut = rv.replace(f, ap1, ap2);
|
||||
auto mut = substitute_ap(f, ap1, ap2);
|
||||
replace_ap_rec(mut, mutations, opts, n, m - 1);
|
||||
mut->destroy();
|
||||
if (!n)
|
||||
return;
|
||||
}
|
||||
|
|
@ -412,8 +353,8 @@ namespace spot
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<const formula*>
|
||||
mutate(const formula* f, unsigned opts, unsigned max_output,
|
||||
std::vector<formula>
|
||||
mutate(formula f, unsigned opts, unsigned max_output,
|
||||
unsigned mutation_count, bool sort)
|
||||
{
|
||||
fset_t mutations;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2014 Laboratoire de Recherche et Développement de
|
||||
// l'Epita (LRDE).
|
||||
// Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement
|
||||
// de l'Epita (LRDE).
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
//
|
||||
|
|
@ -20,7 +20,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "ltlast/formula.hh"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace spot
|
||||
|
|
@ -40,7 +39,7 @@ namespace spot
|
|||
};
|
||||
|
||||
SPOT_API
|
||||
std::vector<const formula*> mutate(const formula* f,
|
||||
std::vector<formula> mutate(formula f,
|
||||
unsigned opts = Mut_All,
|
||||
unsigned max_output = -1U,
|
||||
unsigned mutation_count = 1,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013 Laboratoire de Recherche
|
||||
// et Développement de l'Epita (LRDE).
|
||||
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 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.
|
||||
|
|
@ -27,11 +27,11 @@ namespace spot
|
|||
{
|
||||
namespace ltl
|
||||
{
|
||||
const formula*
|
||||
negative_normal_form(const formula* f, bool negated)
|
||||
formula
|
||||
negative_normal_form(formula f, bool negated)
|
||||
{
|
||||
if (!negated && f->is_in_nenoform())
|
||||
return f->clone();
|
||||
if (!negated && f.is_in_nenoform())
|
||||
return f;
|
||||
|
||||
ltl_simplifier s;
|
||||
return s.negative_normal_form(f, negated);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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).
|
||||
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||
|
|
@ -39,11 +39,11 @@ namespace spot
|
|||
/// \c !f
|
||||
///
|
||||
/// Note that this will not remove abbreviated operators. If you
|
||||
/// want to remove abbreviations, call spot::ltl::unabbreviate_logic
|
||||
/// or spot::ltl::unabbreviate_ltl first. (Calling these functions
|
||||
/// after spot::ltl::negative_normal_form would likely produce a
|
||||
/// formula which is not in negative normal form.)
|
||||
SPOT_API const formula*
|
||||
negative_normal_form(const formula* f, bool negated = false);
|
||||
/// want to remove abbreviations, call spot::ltl::unabbreviate
|
||||
/// first. (Calling this function after
|
||||
/// spot::ltl::negative_normal_form would likely produce a formula
|
||||
/// which is not in negative normal form.)
|
||||
SPOT_API formula
|
||||
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
|
||||
/// parenthesized.
|
||||
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
|
||||
/// \param f The formula to translate.
|
||||
/// \param full_parent Whether or not the string should by fully
|
||||
/// parenthesized.
|
||||
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.
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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);
|
||||
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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.
|
||||
/// \param f The formula to translate.
|
||||
|
|
@ -69,14 +69,14 @@ namespace spot
|
|||
/// \param full_parent Whether or not the string should by fully
|
||||
/// parenthesized.
|
||||
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
|
||||
/// \param f The formula to translate.
|
||||
/// \param full_parent Whether or not the string should by fully
|
||||
/// parenthesized.
|
||||
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.
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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);
|
||||
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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.
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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);
|
||||
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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.
|
||||
/// \param os The stream where it should be output.
|
||||
/// \param f The formula to translate.
|
||||
SPOT_API std::ostream&
|
||||
print_wring_ltl(std::ostream& os, const formula* f);
|
||||
print_wring_ltl(std::ostream& os, formula f);
|
||||
|
||||
/// \brief Convert a formula into a string parsable by Wring
|
||||
/// \param f The formula to translate.
|
||||
SPOT_API std::string
|
||||
str_wring_ltl(const formula* f);
|
||||
str_wring_ltl(formula f);
|
||||
|
||||
/// \brief Output a PSL formula as a LaTeX string.
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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);
|
||||
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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.
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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);
|
||||
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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.
|
||||
///
|
||||
|
|
@ -163,7 +163,7 @@ namespace spot
|
|||
/// \param full_parent Whether or not the string should by fully
|
||||
/// parenthesized.
|
||||
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);
|
||||
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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.
|
||||
///
|
||||
|
|
@ -183,7 +183,7 @@ namespace spot
|
|||
/// \param full_parent Whether or not the string should by fully
|
||||
/// parenthesized.
|
||||
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);
|
||||
|
||||
/// \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
|
||||
/// parenthesized.
|
||||
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.
|
||||
///
|
||||
|
|
@ -206,7 +206,7 @@ namespace spot
|
|||
/// \param f The formula to translate.
|
||||
/// \param os The stream where it should be output.
|
||||
SPOT_API std::ostream&
|
||||
print_lbt_ltl(std::ostream& os, const formula* f);
|
||||
print_lbt_ltl(std::ostream& os, formula f);
|
||||
|
||||
/// \brief Output an LTL formula as a string in LBT's format.
|
||||
///
|
||||
|
|
@ -218,7 +218,7 @@ namespace spot
|
|||
///
|
||||
/// \param f The formula to translate.
|
||||
SPOT_API std::string
|
||||
str_lbt_ltl(const formula* f);
|
||||
str_lbt_ltl(formula f);
|
||||
/// @}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include "randomltl.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "misc/random.hh"
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
|
@ -37,25 +36,41 @@ namespace spot
|
|||
{
|
||||
namespace
|
||||
{
|
||||
static const formula*
|
||||
static formula
|
||||
ap_builder(const random_formula* rl, int n)
|
||||
{
|
||||
assert(n == 1);
|
||||
(void) n;
|
||||
atomic_prop_set::const_iterator i = rl->ap()->begin();
|
||||
std::advance(i, mrand(rl->ap()->size()));
|
||||
return (*i)->clone();
|
||||
return *i;
|
||||
}
|
||||
|
||||
static const formula*
|
||||
static formula
|
||||
true_builder(const random_formula*, int n)
|
||||
{
|
||||
assert(n == 1);
|
||||
(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)
|
||||
{
|
||||
assert(n >= 1);
|
||||
|
|
@ -63,40 +78,24 @@ namespace spot
|
|||
return rs->rb.generate(n);
|
||||
}
|
||||
|
||||
static const formula*
|
||||
false_builder(const random_formula*, int n)
|
||||
{
|
||||
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*
|
||||
template <op Op>
|
||||
static formula
|
||||
unop_builder(const random_formula* rl, int n)
|
||||
{
|
||||
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)
|
||||
{
|
||||
assert(n >= 2);
|
||||
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>
|
||||
static const formula*
|
||||
template <op Op>
|
||||
static formula
|
||||
binop_builder(const random_formula* rl, int n)
|
||||
{
|
||||
assert(n >= 3);
|
||||
|
|
@ -109,11 +108,11 @@ namespace spot
|
|||
// discovering that clang would perform the nested calls from
|
||||
// left to right.
|
||||
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>
|
||||
static const formula*
|
||||
template <op Op>
|
||||
static formula
|
||||
binop_SERELTL_builder(const random_formula* rl, int n)
|
||||
{
|
||||
assert(n >= 3);
|
||||
|
|
@ -122,41 +121,41 @@ namespace spot
|
|||
int l = rrand(1, n - 1);
|
||||
// See comment in binop_builder.
|
||||
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>
|
||||
static const formula*
|
||||
template <op Op>
|
||||
static formula
|
||||
bunop_unbounded_builder(const random_formula* rl, int n)
|
||||
{
|
||||
assert(n >= 2);
|
||||
return bunop::instance(Op, rl->generate(n - 1));
|
||||
return formula::bunop(Op, rl->generate(n - 1));
|
||||
}
|
||||
|
||||
template <bunop::type Op>
|
||||
static const formula*
|
||||
template <op Op>
|
||||
static formula
|
||||
bunop_bounded_builder(const random_formula* rl, int n)
|
||||
{
|
||||
assert(n >= 2);
|
||||
int min = rrand(0, 2);
|
||||
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>
|
||||
static const formula*
|
||||
template <op Op>
|
||||
static formula
|
||||
bunop_bool_bounded_builder(const random_formula* rl, int n)
|
||||
{
|
||||
assert(n >= 2);
|
||||
int min = rrand(0, 2);
|
||||
int max = rrand(min, 3);
|
||||
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>
|
||||
static const formula*
|
||||
template <op Op>
|
||||
static formula
|
||||
multop_builder(const random_formula* rl, int n)
|
||||
{
|
||||
assert(n >= 3);
|
||||
|
|
@ -164,7 +163,7 @@ namespace spot
|
|||
int l = rrand(1, n - 1);
|
||||
// See comment in binop_builder.
|
||||
auto right = rl->generate(n - l);
|
||||
return multop::instance(Op, rl->generate(l), right);
|
||||
return formula::multop(Op, {rl->generate(l), right});
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
|
@ -208,7 +207,7 @@ namespace spot
|
|||
assert(total_2_and_more_ >= total_2_);
|
||||
}
|
||||
|
||||
const formula*
|
||||
formula
|
||||
random_formula::generate(int n) const
|
||||
{
|
||||
assert(n > 0);
|
||||
|
|
@ -319,15 +318,15 @@ namespace spot
|
|||
proba_2_ = proba_ + 1;
|
||||
proba_2_or_more_ = proba_ + 1;
|
||||
proba_[1].setup("boolform", 1, boolform_builder);
|
||||
proba_[2].setup("star", 2, bunop_unbounded_builder<bunop::Star>);
|
||||
proba_[3].setup("star_b", 2, bunop_bounded_builder<bunop::Star>);
|
||||
proba_[4].setup("fstar", 2, bunop_unbounded_builder<bunop::FStar>);
|
||||
proba_[5].setup("fstar_b", 2, bunop_bounded_builder<bunop::FStar>);
|
||||
proba_[6].setup("and", 3, multop_builder<multop::AndRat>);
|
||||
proba_[7].setup("andNLM", 3, multop_builder<multop::AndNLM>);
|
||||
proba_[8].setup("or", 3, multop_builder<multop::OrRat>);
|
||||
proba_[9].setup("concat", 3, multop_builder<multop::Concat>);
|
||||
proba_[10].setup("fusion", 3, multop_builder<multop::Fusion>);
|
||||
proba_[2].setup("star", 2, bunop_unbounded_builder<op::Star>);
|
||||
proba_[3].setup("star_b", 2, bunop_bounded_builder<op::Star>);
|
||||
proba_[4].setup("fstar", 2, bunop_unbounded_builder<op::FStar>);
|
||||
proba_[5].setup("fstar_b", 2, bunop_bounded_builder<op::FStar>);
|
||||
proba_[6].setup("and", 3, multop_builder<op::AndRat>);
|
||||
proba_[7].setup("andNLM", 3, multop_builder<op::AndNLM>);
|
||||
proba_[8].setup("or", 3, multop_builder<op::OrRat>);
|
||||
proba_[9].setup("concat", 3, multop_builder<op::Concat>);
|
||||
proba_[10].setup("fusion", 3, multop_builder<op::Fusion>);
|
||||
|
||||
update_sums();
|
||||
}
|
||||
|
|
@ -341,12 +340,12 @@ namespace spot
|
|||
proba_[1].setup("false", 1, false_builder);
|
||||
proba_[2].setup("true", 1, true_builder);
|
||||
proba_2_or_more_ = proba_2_ = proba_ + 3;
|
||||
proba_[3].setup("not", 2, unop_builder<unop::Not>);
|
||||
proba_[4].setup("equiv", 3, binop_builder<binop::Equiv>);
|
||||
proba_[5].setup("implies", 3, binop_builder<binop::Implies>);
|
||||
proba_[6].setup("xor", 3, binop_builder<binop::Xor>);
|
||||
proba_[7].setup("and", 3, multop_builder<multop::And>);
|
||||
proba_[8].setup("or", 3, multop_builder<multop::Or>);
|
||||
proba_[3].setup("not", 2, unop_builder<op::Not>);
|
||||
proba_[4].setup("equiv", 3, binop_builder<op::Equiv>);
|
||||
proba_[5].setup("implies", 3, binop_builder<op::Implies>);
|
||||
proba_[6].setup("xor", 3, binop_builder<op::Xor>);
|
||||
proba_[7].setup("and", 3, multop_builder<op::And>);
|
||||
proba_[8].setup("or", 3, multop_builder<op::Or>);
|
||||
|
||||
update_sums();
|
||||
}
|
||||
|
|
@ -360,19 +359,19 @@ namespace spot
|
|||
proba_[1].setup("false", 1, false_builder);
|
||||
proba_[2].setup("true", 1, true_builder);
|
||||
proba_2_or_more_ = proba_2_ = proba_ + 3;
|
||||
proba_[3].setup("not", 2, unop_builder<unop::Not>);
|
||||
proba_[4].setup("F", 2, unop_builder<unop::F>);
|
||||
proba_[5].setup("G", 2, unop_builder<unop::G>);
|
||||
proba_[6].setup("X", 2, unop_builder<unop::X>);
|
||||
proba_[7].setup("equiv", 3, binop_builder<binop::Equiv>);
|
||||
proba_[8].setup("implies", 3, binop_builder<binop::Implies>);
|
||||
proba_[9].setup("xor", 3, binop_builder<binop::Xor>);
|
||||
proba_[10].setup("R", 3, binop_builder<binop::R>);
|
||||
proba_[11].setup("U", 3, binop_builder<binop::U>);
|
||||
proba_[12].setup("W", 3, binop_builder<binop::W>);
|
||||
proba_[13].setup("M", 3, binop_builder<binop::M>);
|
||||
proba_[14].setup("and", 3, multop_builder<multop::And>);
|
||||
proba_[15].setup("or", 3, multop_builder<multop::Or>);
|
||||
proba_[3].setup("not", 2, unop_builder<op::Not>);
|
||||
proba_[4].setup("F", 2, unop_builder<op::F>);
|
||||
proba_[5].setup("G", 2, unop_builder<op::G>);
|
||||
proba_[6].setup("X", 2, unop_builder<op::X>);
|
||||
proba_[7].setup("equiv", 3, binop_builder<op::Equiv>);
|
||||
proba_[8].setup("implies", 3, binop_builder<op::Implies>);
|
||||
proba_[9].setup("xor", 3, binop_builder<op::Xor>);
|
||||
proba_[10].setup("R", 3, binop_builder<op::R>);
|
||||
proba_[11].setup("U", 3, binop_builder<op::U>);
|
||||
proba_[12].setup("W", 3, binop_builder<op::W>);
|
||||
proba_[13].setup("M", 3, binop_builder<op::M>);
|
||||
proba_[14].setup("and", 3, multop_builder<op::And>);
|
||||
proba_[15].setup("or", 3, multop_builder<op::Or>);
|
||||
}
|
||||
|
||||
random_ltl::random_ltl(const atomic_prop_set* ap)
|
||||
|
|
@ -399,8 +398,8 @@ namespace spot
|
|||
((proba_ + 16) - (proba_ + 7)) * sizeof(*proba_));
|
||||
|
||||
proba_[7].setup("Closure", 2, closure_builder);
|
||||
proba_[17].setup("EConcat", 3, binop_SERELTL_builder<binop::EConcat>);
|
||||
proba_[18].setup("UConcat", 3, binop_SERELTL_builder<binop::UConcat>);
|
||||
proba_[17].setup("EConcat", 3, binop_SERELTL_builder<op::EConcat>);
|
||||
proba_[18].setup("UConcat", 3, binop_SERELTL_builder<op::UConcat>);
|
||||
update_sums();
|
||||
}
|
||||
|
||||
|
|
@ -490,16 +489,13 @@ namespace spot
|
|||
randltlgenerator::~randltlgenerator()
|
||||
{
|
||||
delete rf_;
|
||||
// Cleanup the unicity table.
|
||||
for (auto i: unique_set_)
|
||||
i->destroy();
|
||||
}
|
||||
|
||||
const formula* randltlgenerator::next()
|
||||
formula randltlgenerator::next()
|
||||
{
|
||||
unsigned trials = MAX_TRIALS;
|
||||
bool ignore;
|
||||
const formula* f = nullptr;
|
||||
formula f = nullptr;
|
||||
do
|
||||
{
|
||||
ignore = false;
|
||||
|
|
@ -512,29 +508,14 @@ namespace spot
|
|||
{
|
||||
atomic_prop_set s = aprops_;
|
||||
remove_some_props(s);
|
||||
f = multop::instance(multop::And,
|
||||
f, GF_n());
|
||||
f = formula::And({f, GF_n()});
|
||||
}
|
||||
|
||||
if (opt_simpl_level_)
|
||||
{
|
||||
const spot::ltl::formula* tmp = simpl_.simplify(f);
|
||||
f->destroy();
|
||||
f = tmp;
|
||||
}
|
||||
f = simpl_.simplify(f);
|
||||
|
||||
if (opt_unique_)
|
||||
{
|
||||
if (unique_set_.insert(f).second)
|
||||
{
|
||||
f->clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opt_unique_ && !unique_set_.insert(f).second)
|
||||
ignore = true;
|
||||
f->destroy();
|
||||
}
|
||||
}
|
||||
} while (ignore && --trials);
|
||||
if (trials <= 0)
|
||||
return nullptr;
|
||||
|
|
@ -557,17 +538,15 @@ namespace spot
|
|||
}
|
||||
|
||||
// GF(p_1) & GF(p_2) & ... & GF(p_n)
|
||||
const formula*
|
||||
formula
|
||||
randltlgenerator::GF_n()
|
||||
{
|
||||
const formula* res = 0;
|
||||
formula res = nullptr;
|
||||
for (auto v: aprops_)
|
||||
{
|
||||
const formula* f =
|
||||
unop::instance(unop::F, v->clone());
|
||||
f = unop::instance(unop::G, f);
|
||||
formula f = formula::G(formula::F(v));
|
||||
if (res)
|
||||
res = multop::instance(multop::And, f, res);
|
||||
res = formula::And({f, res});
|
||||
else
|
||||
res = f;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ namespace spot
|
|||
/// n, because some simple simplifications are performed by the
|
||||
/// AST. (For instance the formula <code>a | a</code> is
|
||||
/// automatically reduced to <code>a</code> by spot::ltl::multop.)
|
||||
const formula* generate(int n) const;
|
||||
formula generate(int n) const;
|
||||
|
||||
/// \brief Print the priorities of each operator, constants,
|
||||
/// and atomic propositions.
|
||||
|
|
@ -93,7 +93,7 @@ namespace spot
|
|||
const char* name;
|
||||
int min_n;
|
||||
double proba;
|
||||
typedef const formula* (*builder)(const random_formula* rl, int n);
|
||||
typedef formula (*builder)(const random_formula* rl, int n);
|
||||
builder build;
|
||||
void setup(const char* name, int min_n, builder build);
|
||||
};
|
||||
|
|
@ -304,9 +304,7 @@ namespace spot
|
|||
|
||||
class SPOT_API randltlgenerator
|
||||
{
|
||||
typedef
|
||||
std::unordered_set<const spot::ltl::formula*,
|
||||
const spot::ptr_hash<const spot::ltl::formula>> fset_t;
|
||||
typedef std::unordered_set<formula> fset_t;
|
||||
|
||||
|
||||
public:
|
||||
|
|
@ -322,7 +320,7 @@ namespace spot
|
|||
|
||||
~randltlgenerator();
|
||||
|
||||
const spot::ltl::formula* next();
|
||||
formula next();
|
||||
|
||||
void dump_ltl_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 remove_some_props(atomic_prop_set& s);
|
||||
|
||||
const formula* GF_n();
|
||||
formula GF_n();
|
||||
|
||||
private:
|
||||
fset_t unique_set_;
|
||||
|
|
|
|||
|
|
@ -19,10 +19,7 @@
|
|||
|
||||
#include "relabel.hh"
|
||||
#include <sstream>
|
||||
#include "clone.hh"
|
||||
#include "misc/hash.hh"
|
||||
#include "ltlenv/defaultenv.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
|
@ -41,7 +38,7 @@ namespace spot
|
|||
{
|
||||
struct ap_generator
|
||||
{
|
||||
virtual const formula* next() = 0;
|
||||
virtual formula next() = 0;
|
||||
virtual ~ap_generator() {}
|
||||
};
|
||||
|
||||
|
|
@ -53,11 +50,11 @@ namespace spot
|
|||
{
|
||||
}
|
||||
|
||||
const formula* next()
|
||||
formula next()
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << 'p' << nn++;
|
||||
return default_environment::instance().require(s.str());
|
||||
return formula::ap(s.str());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -71,7 +68,7 @@ namespace spot
|
|||
|
||||
unsigned nn;
|
||||
|
||||
const formula* next()
|
||||
formula next()
|
||||
{
|
||||
std::string s;
|
||||
unsigned n = nn++;
|
||||
|
|
@ -81,16 +78,15 @@ namespace spot
|
|||
n /= 26;
|
||||
}
|
||||
while (n);
|
||||
|
||||
return default_environment::instance().require(s);
|
||||
return formula::ap(s);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class relabeler: public clone_visitor
|
||||
class relabeler
|
||||
{
|
||||
public:
|
||||
typedef std::unordered_map<const formula*, const formula*> map;
|
||||
typedef std::unordered_map<formula, formula> map;
|
||||
map newname;
|
||||
ap_generator* gen;
|
||||
relabeling_map* oldnames;
|
||||
|
|
@ -105,29 +101,33 @@ namespace spot
|
|||
delete gen;
|
||||
}
|
||||
|
||||
const formula* rename(const formula* old)
|
||||
formula rename(formula old)
|
||||
{
|
||||
auto r = newname.emplace(old, nullptr);
|
||||
if (!r.second)
|
||||
{
|
||||
return r.first->second->clone();
|
||||
return r.first->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
const formula* res;
|
||||
r.first->second = res = gen->next();
|
||||
formula res = gen->next();
|
||||
r.first->second = res;
|
||||
if (oldnames)
|
||||
(*oldnames)[res] = old->clone();
|
||||
(*oldnames)[res] = old;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
using clone_visitor::visit;
|
||||
|
||||
void
|
||||
visit(const atomic_prop* ap)
|
||||
formula
|
||||
visit(formula f)
|
||||
{
|
||||
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*
|
||||
relabel(const formula* f, relabeling_style style,
|
||||
relabeling_map* m)
|
||||
formula
|
||||
relabel(formula f, relabeling_style style, relabeling_map* m)
|
||||
{
|
||||
ap_generator* gen = 0;
|
||||
switch (style)
|
||||
|
|
@ -149,8 +148,9 @@ namespace spot
|
|||
gen = new abc_generator;
|
||||
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).
|
||||
namespace
|
||||
{
|
||||
typedef std::vector<const formula*> succ_vec;
|
||||
typedef std::map<const formula*, succ_vec> fgraph;
|
||||
typedef std::vector<formula> succ_vec;
|
||||
typedef std::map<formula, succ_vec> fgraph;
|
||||
|
||||
// Convert the formula's syntax tree into an undirected graph
|
||||
// labeled by subformulas.
|
||||
class formula_to_fgraph: public visitor
|
||||
class formula_to_fgraph final
|
||||
{
|
||||
public:
|
||||
fgraph& g;
|
||||
std::stack<const formula*> s;
|
||||
std::stack<formula> s;
|
||||
|
||||
formula_to_fgraph(fgraph& g):
|
||||
g(g)
|
||||
|
|
@ -248,104 +248,63 @@ namespace spot
|
|||
}
|
||||
|
||||
void
|
||||
visit(const atomic_prop*)
|
||||
visit(formula f)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
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;
|
||||
const formula* b = mo->is_boolean() ? 0 : mo->boolean_operands(&i);
|
||||
if (b)
|
||||
{
|
||||
recurse(b);
|
||||
b->destroy();
|
||||
}
|
||||
for (; i < mos; ++i)
|
||||
recurse(mo->nth(i));
|
||||
// For Boolean nodes, connect all children in a loop. This
|
||||
// way the node can only be a cut-point if it separates all
|
||||
// children from the reset of the graph (not only one).
|
||||
if (mo->is_boolean())
|
||||
{
|
||||
const formula* pred = mo->nth(0);
|
||||
for (i = 1; i < mos; ++i)
|
||||
{
|
||||
const formula* next = mo->nth(i);
|
||||
// Note that we only add an edge in one direction,
|
||||
// because we are building a cycle between all
|
||||
// children anyway.
|
||||
g[pred].push_back(next);
|
||||
pred = next;
|
||||
}
|
||||
g[pred].push_back(mo->nth(0));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
recurse(const formula* f)
|
||||
{
|
||||
auto i = g.emplace(f, succ_vec());
|
||||
// Connect to parent
|
||||
auto in = g.emplace(f, succ_vec());
|
||||
if (!s.empty())
|
||||
{
|
||||
const formula* top = s.top();
|
||||
i.first->second.push_back(top);
|
||||
formula top = s.top();
|
||||
in.first->second.push_back(top);
|
||||
g[top].push_back(f);
|
||||
if (!i.second)
|
||||
if (!in.second)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(i.second);
|
||||
assert(in.second);
|
||||
}
|
||||
}
|
||||
f->clone();
|
||||
s.push(f);
|
||||
f->accept(*this);
|
||||
|
||||
unsigned sz = f.size();
|
||||
unsigned i = 0;
|
||||
if (sz > 2 && !f.is_boolean())
|
||||
{
|
||||
/// If we have a formula like (a & b & Xc), consider
|
||||
/// it as ((a & b) & Xc) in the graph to isolate the
|
||||
/// Boolean operands as a single node.
|
||||
formula b = f.boolean_operands(&i);
|
||||
if (b)
|
||||
visit(b);
|
||||
}
|
||||
for (; i < sz; ++i)
|
||||
visit(f.nth(i));
|
||||
if (sz > 1 && f.is_boolean())
|
||||
{
|
||||
// For Boolean nodes, connect all children in a
|
||||
// loop. This way the node can only be a cut-point
|
||||
// if it separates all children from the reset of
|
||||
// the graph (not only one).
|
||||
formula pred = f.nth(0);
|
||||
for (i = 1; i < sz; ++i)
|
||||
{
|
||||
formula next = f.nth(i);
|
||||
// Note that we only add an edge in one
|
||||
// direction, because we are building a cycle
|
||||
// between all children anyway.
|
||||
g[pred].push_back(next);
|
||||
pred = next;
|
||||
}
|
||||
g[pred].push_back(f.nth(0));
|
||||
}
|
||||
s.pop();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef std::set<const formula*> fset;
|
||||
typedef std::set<formula> fset;
|
||||
struct data_entry // for each node of the graph
|
||||
{
|
||||
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
|
||||
{
|
||||
const formula* grand_parent;
|
||||
const formula* parent; // current node
|
||||
formula grand_parent;
|
||||
formula parent; // current node
|
||||
succ_vec::const_iterator current_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
|
||||
// OK: if the top-most formula is Boolean we want to replace it
|
||||
// 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;
|
||||
|
||||
|
|
@ -397,7 +356,7 @@ namespace spot
|
|||
{
|
||||
// Skip the edge if it is just the reverse of the one
|
||||
// we took.
|
||||
const formula* child = *e.current_child;
|
||||
formula child = *e.current_child;
|
||||
if (child == e.grand_parent)
|
||||
{
|
||||
++e.current_child;
|
||||
|
|
@ -428,15 +387,15 @@ namespace spot
|
|||
}
|
||||
else
|
||||
{
|
||||
const formula* grand_parent = e.grand_parent;
|
||||
const formula* parent = e.parent;
|
||||
formula grand_parent = e.grand_parent;
|
||||
formula parent = e.parent;
|
||||
s.pop();
|
||||
if (!s.empty())
|
||||
{
|
||||
data_entry& dparent = data[parent];
|
||||
data_entry& dgrand_parent = data[grand_parent];
|
||||
if (dparent.low >= dgrand_parent.num // cut-point
|
||||
&& grand_parent->is_boolean())
|
||||
&& grand_parent.is_boolean())
|
||||
c.insert(grand_parent);
|
||||
if (dparent.low < dgrand_parent.low)
|
||||
dgrand_parent.low = dparent.low;
|
||||
|
|
@ -450,7 +409,6 @@ namespace spot
|
|||
{
|
||||
public:
|
||||
fset& c;
|
||||
|
||||
bse_relabeler(ap_generator* gen, fset& c,
|
||||
relabeling_map* m)
|
||||
: relabeler(gen, m), c(c)
|
||||
|
|
@ -459,57 +417,51 @@ namespace spot
|
|||
|
||||
using relabeler::visit;
|
||||
|
||||
void
|
||||
visit(const multop* mo)
|
||||
formula
|
||||
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
|
||||
/// it as ((a & b) & Xc) in the graph to isolate the
|
||||
/// Boolean operands as a single node.
|
||||
unsigned i = 0;
|
||||
const formula* b = mo->is_boolean() ? 0 : mo->boolean_operands(&i);
|
||||
multop::vec* res = new multop::vec;
|
||||
formula b = f.boolean_operands(&i);
|
||||
if (b)
|
||||
{
|
||||
res->reserve(mos - i + 1);
|
||||
res->push_back(recurse(b));
|
||||
b->destroy();
|
||||
res.reserve(sz - i + 1);
|
||||
res.push_back(visit(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
res->reserve(mos);
|
||||
res.reserve(sz);
|
||||
}
|
||||
for (; i < mos; ++i)
|
||||
res->push_back(recurse(mo->nth(i)));
|
||||
result_ = multop::instance(mo->op(), 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_;
|
||||
for (; i < sz; ++i)
|
||||
res.push_back(visit(f.nth(i)));
|
||||
return formula::multop(f.kind(), res);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
const formula*
|
||||
relabel_bse(const formula* f, relabeling_style style,
|
||||
relabeling_map* m)
|
||||
formula
|
||||
relabel_bse(formula f, relabeling_style style, relabeling_map* m)
|
||||
{
|
||||
fgraph g;
|
||||
|
||||
// Build the graph g from the formula f.
|
||||
{
|
||||
formula_to_fgraph conv(g);
|
||||
conv.recurse(f);
|
||||
conv.visit(f);
|
||||
}
|
||||
|
||||
// Compute its cut-points
|
||||
|
|
@ -529,18 +481,7 @@ namespace spot
|
|||
break;
|
||||
}
|
||||
bse_relabeler rel(gen, c, m);
|
||||
f = rel.recurse(f);
|
||||
|
||||
// Cleanup.
|
||||
fgraph::const_iterator i = g.begin();
|
||||
while (i != g.end())
|
||||
{
|
||||
const formula* f = i->first;
|
||||
++i;
|
||||
f->destroy();
|
||||
}
|
||||
|
||||
return f;
|
||||
return rel.visit(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,25 +29,7 @@ namespace spot
|
|||
{
|
||||
enum relabeling_style { Abc, Pnn };
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
typedef std::map<formula, formula> relabeling_map;
|
||||
|
||||
/// \ingroup ltl_rewriting
|
||||
/// \brief Relabel the atomic propositions in a formula.
|
||||
|
|
@ -55,7 +37,7 @@ namespace spot
|
|||
/// If \a m is non-null, it is filled with correspondence
|
||||
/// between the new names (keys) and the old names (values).
|
||||
SPOT_API
|
||||
const formula* relabel(const formula* f, relabeling_style style,
|
||||
formula relabel(formula f, relabeling_style style,
|
||||
relabeling_map* m = 0);
|
||||
|
||||
|
||||
|
|
@ -66,7 +48,7 @@ namespace spot
|
|||
/// If \a m is non-null, it is filled with correspondence
|
||||
/// between the new names (keys) and the old names (values).
|
||||
SPOT_API
|
||||
const formula* relabel_bse(const formula* f, relabeling_style style,
|
||||
formula relabel_bse(formula f, relabeling_style style,
|
||||
relabeling_map* m = 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
// 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 "ltlvisit/simplify.hh"
|
||||
#include "ltlvisit/clone.hh"
|
||||
#include "ltlvisit/apcollect.hh"
|
||||
#include "ltlvisit/remove_x.hh"
|
||||
|
||||
|
|
@ -29,104 +27,76 @@ namespace spot
|
|||
{
|
||||
namespace
|
||||
{
|
||||
static formula
|
||||
remove_x_rec(formula f, atomic_prop_set& aps)
|
||||
{
|
||||
if (f.is_syntactic_stutter_invariant())
|
||||
return f;
|
||||
|
||||
#define AND(x, y) multop::instance(multop::And, (x), (y))
|
||||
#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
|
||||
auto rec = [&aps](formula f)
|
||||
{
|
||||
typedef clone_visitor super;
|
||||
atomic_prop_set aps;
|
||||
|
||||
public:
|
||||
remove_x_visitor(const formula* f)
|
||||
{
|
||||
atomic_prop_collect(f, &aps);
|
||||
}
|
||||
|
||||
virtual
|
||||
~remove_x_visitor()
|
||||
{
|
||||
}
|
||||
|
||||
using super::visit;
|
||||
void visit(const unop* uo)
|
||||
{
|
||||
const formula* c = recurse(uo->child());
|
||||
|
||||
unop::type op = uo->op();
|
||||
if (op != unop::X)
|
||||
{
|
||||
result_ = unop::instance(op, c);
|
||||
return;
|
||||
}
|
||||
multop::vec* vo = new multop::vec;
|
||||
for (atomic_prop_set::const_iterator i = aps.begin();
|
||||
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();
|
||||
}
|
||||
return remove_x_rec(f, aps);
|
||||
};
|
||||
|
||||
if (!f.is(op::X))
|
||||
return f.map(rec);
|
||||
|
||||
formula c = rec(f.nth(0));
|
||||
|
||||
std::vector<formula> vo;
|
||||
for (auto i: aps)
|
||||
{
|
||||
// First line
|
||||
std::vector<formula> va1;
|
||||
formula npi = formula::Not(i);
|
||||
va1.push_back(i);
|
||||
va1.push_back(formula::U(i, formula::And({npi, c})));
|
||||
|
||||
for (auto j: aps)
|
||||
if (j != i)
|
||||
{
|
||||
// make sure the arguments of OR are created in a
|
||||
// deterministic order
|
||||
auto tmp = formula::U(formula::Not(j), npi);
|
||||
va1.push_back(formula::Or({formula::U(j, npi), tmp}));
|
||||
}
|
||||
vo.push_back(formula::And(va1));
|
||||
// Second line
|
||||
std::vector<formula> va2;
|
||||
va2.push_back(npi);
|
||||
va2.push_back(formula::U(npi, formula::And({i, c})));
|
||||
for (auto j: aps)
|
||||
if (j != i)
|
||||
{
|
||||
// make sure the arguments of OR are created in a
|
||||
// deterministic order
|
||||
auto tmp = formula::U(formula::Not(j), i);
|
||||
va2.push_back(formula::Or({formula::U(j, i), tmp}));
|
||||
}
|
||||
vo.push_back(formula::And(va2));
|
||||
}
|
||||
// Third line
|
||||
std::vector<formula> va3;
|
||||
for (auto i: aps)
|
||||
{
|
||||
// make sure the arguments of OR are created in a
|
||||
// deterministic order
|
||||
auto tmp = formula::G(formula::Not(i));
|
||||
va3.push_back(formula::Or({formula::G(i), tmp}));
|
||||
}
|
||||
va3.push_back(c);
|
||||
vo.push_back(formula::And(va3));
|
||||
return formula::Or(vo);
|
||||
}
|
||||
}
|
||||
|
||||
const formula* remove_x(const formula* f)
|
||||
formula remove_x(formula f)
|
||||
{
|
||||
remove_x_visitor v(f);
|
||||
return v.recurse(f);
|
||||
if (f.is_syntactic_stutter_invariant())
|
||||
return f;
|
||||
atomic_prop_set aps;
|
||||
atomic_prop_collect(f, &aps);
|
||||
return remove_x_rec(f, aps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2013 Laboratoire de Recherche et Developpement de
|
||||
// l'Epita (LRDE).
|
||||
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Developpement
|
||||
// de l'Epita (LRDE).
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
//
|
||||
|
|
@ -19,14 +19,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "misc/common.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace ltl
|
||||
{
|
||||
class formula;
|
||||
|
||||
/// \brief Rewrite a stutter-insensitive formula \a f without
|
||||
/// using the X operator.
|
||||
///
|
||||
|
|
@ -46,6 +44,6 @@ namespace spot
|
|||
}
|
||||
\endverbatim */
|
||||
SPOT_API
|
||||
const formula* remove_x(const formula* f);
|
||||
formula remove_x(formula f);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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).
|
||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// 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
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlvisit/clone.hh"
|
||||
#include "simpfg.hh"
|
||||
#include <cassert>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace ltl
|
||||
{
|
||||
|
||||
simplify_f_g_visitor::simplify_f_g_visitor()
|
||||
formula simplify_f_g(formula p)
|
||||
{
|
||||
// 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 -*-
|
||||
// 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).
|
||||
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||
|
|
@ -22,36 +22,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "clone.hh"
|
||||
#include "ltlast/formula.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
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
|
||||
/// \brief Replace <code>true U f</code> and <code>false R g</code> by
|
||||
/// <code>F f</code> and <code>G g</code>.
|
||||
|
|
@ -63,6 +39,6 @@ namespace spot
|
|||
/// - false R a = 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 -*-
|
||||
// Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
|
||||
// Developpement de l'Epita (LRDE).
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015 Laboratoire de Recherche
|
||||
// et Developpement de l'Epita (LRDE).
|
||||
//
|
||||
// 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
|
||||
/// constructor).
|
||||
const formula* simplify(const formula* f);
|
||||
formula simplify(formula f);
|
||||
|
||||
/// Build the negative normal form of formula \a f.
|
||||
/// All negations of the formula are pushed in front of the
|
||||
|
|
@ -116,8 +116,8 @@ namespace spot
|
|||
/// \param f The formula to normalize.
|
||||
/// \param negated If \c true, return the negative normal form of
|
||||
/// \c !f
|
||||
const formula*
|
||||
negative_normal_form(const formula* f, bool negated = false);
|
||||
formula
|
||||
negative_normal_form(formula f, bool negated = false);
|
||||
|
||||
/// \brief Syntactic implication.
|
||||
///
|
||||
|
|
@ -138,20 +138,20 @@ namespace spot
|
|||
}
|
||||
\endverbatim */
|
||||
///
|
||||
bool syntactic_implication(const formula* f, const formula* g);
|
||||
bool syntactic_implication(formula f, formula g);
|
||||
/// \brief Syntactic implication with one negated argument.
|
||||
///
|
||||
/// If \a right is true, this method returns whether
|
||||
/// \a f implies !\a g. If \a right is false, this returns
|
||||
/// 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);
|
||||
|
||||
/// \brief check whether two formulae are equivalent.
|
||||
///
|
||||
/// This costly check performs up to four translations,
|
||||
/// 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.
|
||||
|
|
@ -159,13 +159,13 @@ namespace spot
|
|||
/// This operation is costlier than syntactic_implication()
|
||||
/// because it requires two translation, one product and one
|
||||
/// emptiness check.
|
||||
bool implication(const formula* f, const formula* g);
|
||||
bool implication(formula f, formula g);
|
||||
|
||||
/// \brief Convert a Boolean formula as a BDD.
|
||||
///
|
||||
/// If you plan to use this method, be sure to pass a bdd_dict
|
||||
/// to the constructor.
|
||||
bdd as_bdd(const formula* f);
|
||||
bdd as_bdd(formula f);
|
||||
|
||||
/// \brief Clear the as_bdd() cache.
|
||||
///
|
||||
|
|
@ -182,14 +182,14 @@ namespace spot
|
|||
bdd_dict_ptr get_dict() const;
|
||||
|
||||
/// 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
|
||||
/// sum of product.
|
||||
///
|
||||
/// This uses a cache, so it is OK to call this with identical
|
||||
/// arguments.
|
||||
const formula* boolean_to_isop(const formula* f);
|
||||
formula boolean_to_isop(formula f);
|
||||
|
||||
/// Dump statistics about the caches.
|
||||
void print_stats(std::ostream& os) const;
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "snf.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlast/visitor.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -27,82 +25,51 @@ namespace spot
|
|||
{
|
||||
namespace
|
||||
{
|
||||
// E°
|
||||
class snf_visitor: public visitor
|
||||
// E° if bounded=false
|
||||
// E^□ if nounded=true
|
||||
template<bool bounded>
|
||||
class snf_visitor
|
||||
{
|
||||
protected:
|
||||
const formula* result_;
|
||||
formula result_;
|
||||
snf_cache* cache_;
|
||||
public:
|
||||
|
||||
snf_visitor(snf_cache* c): cache_(c)
|
||||
snf_visitor(snf_cache* c)
|
||||
: cache_(c)
|
||||
{
|
||||
}
|
||||
|
||||
const formula*
|
||||
result() const
|
||||
formula visit(formula f)
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
if (!f.accepts_eword())
|
||||
return f;
|
||||
|
||||
void
|
||||
visit(const atomic_prop*)
|
||||
{
|
||||
SPOT_UNIMPLEMENTED();
|
||||
}
|
||||
snf_cache::const_iterator i = cache_->find(f);
|
||||
if (i != cache_->end())
|
||||
return i->second;
|
||||
|
||||
void
|
||||
visit(const constant* c)
|
||||
formula out;
|
||||
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:
|
||||
assert(bo->accepts_eword());
|
||||
// Strip the star.
|
||||
result_ = recurse(bo->child());
|
||||
case op::EmptyWord:
|
||||
out = formula::ff();
|
||||
break;
|
||||
case bunop::FStar:
|
||||
// FIXME: Can we deal with FStar in a better way?
|
||||
result_ = bo->clone();
|
||||
case op::Star:
|
||||
if (!bounded)
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visit(const unop*)
|
||||
case op::Concat:
|
||||
if (bounded)
|
||||
{
|
||||
SPOT_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
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();
|
||||
out = f;
|
||||
break;
|
||||
case multop::Concat:
|
||||
case multop::AndNLM:
|
||||
}
|
||||
// Fall through
|
||||
case op::OrRat:
|
||||
case op::AndNLM:
|
||||
// Let F designate expressions that accept [*0],
|
||||
// and G designate expressions that do not.
|
||||
|
||||
|
|
@ -112,100 +79,70 @@ namespace spot
|
|||
//
|
||||
// AndNLM can be dealt with similarly.
|
||||
//
|
||||
// This case is already handled in recurse().
|
||||
// if we reach this switch, we only have to
|
||||
// deal with...
|
||||
// The above cases are already handled by the
|
||||
// accepts_eword() tests at the top of this method. So
|
||||
// we reach this switch, we only have to deal with...
|
||||
//
|
||||
// (F₁;F₂;F₃)° = (F₁°)|(F₂°)|(F₃°)
|
||||
// (F₁&F₂&F₃)° = (F₁°)|(F₂°)|(F₃°)
|
||||
// so we fall through to the OrRat case...
|
||||
case multop::OrRat:
|
||||
assert(mo->accepts_eword());
|
||||
// (F₁|G₂|F₃)° = (F₁°)|(G₂°)|(F₃°)
|
||||
{
|
||||
unsigned s = mo->size();
|
||||
multop::vec* v = new multop::vec;
|
||||
v->reserve(s);
|
||||
unsigned s = f.size();
|
||||
std::vector<formula> v;
|
||||
v.reserve(s);
|
||||
for (unsigned pos = 0; pos < s; ++pos)
|
||||
v->push_back(recurse(mo->nth(pos)));
|
||||
result_ = multop::instance(multop::OrRat, v);
|
||||
}
|
||||
break;
|
||||
case multop::AndRat:
|
||||
// FIXME: Can we deal with AndRat in a better way
|
||||
// when it accepts [*0]?
|
||||
result_ = mo->clone();
|
||||
v.emplace_back(visit(f.nth(pos)));
|
||||
out = formula::OrRat(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const formula*
|
||||
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();
|
||||
case op::False:
|
||||
case op::True:
|
||||
case op::AP:
|
||||
case op::Not:
|
||||
case op::X:
|
||||
case op::F:
|
||||
case op::G:
|
||||
case op::Closure:
|
||||
case op::NegClosure:
|
||||
case op::NegClosureMarked:
|
||||
case op::Xor:
|
||||
case op::Implies:
|
||||
case op::Equiv:
|
||||
case op::U:
|
||||
case op::R:
|
||||
case op::W:
|
||||
case op::M:
|
||||
case op::EConcat:
|
||||
case op::EConcatMarked:
|
||||
case op::UConcat:
|
||||
case op::Fusion:
|
||||
case op::Or:
|
||||
case op::And:
|
||||
SPOT_UNREACHABLE();
|
||||
case op::AndRat: // Can AndRat be handled better?
|
||||
case op::FStar: // Can FStar be handled better?
|
||||
out = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visit(const multop* mo)
|
||||
{
|
||||
if (mo->op() == multop::Concat)
|
||||
result_ = mo->clone();
|
||||
else
|
||||
this->snf_visitor::visit(mo);
|
||||
return (*cache_)[f] = out;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const formula*
|
||||
star_normal_form(const formula* sere, snf_cache* cache)
|
||||
formula
|
||||
star_normal_form(formula sere, snf_cache* cache)
|
||||
{
|
||||
snf_visitor v(cache);
|
||||
return v.recurse(sere);
|
||||
snf_visitor<false> v(cache);
|
||||
return v.visit(sere);
|
||||
}
|
||||
|
||||
const formula*
|
||||
star_normal_form_bounded(const formula* sere, snf_cache* cache)
|
||||
formula
|
||||
star_normal_form_bounded(formula sere, snf_cache* cache)
|
||||
{
|
||||
snf_visitor_bounded v(cache);
|
||||
return v.recurse(sere);
|
||||
snf_visitor<true> v(cache);
|
||||
return v.visit(sere);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- 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).
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
|
|
@ -20,15 +20,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "ltlast/formula.hh"
|
||||
#include "misc/hash.hh"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace ltl
|
||||
{
|
||||
|
||||
typedef std::unordered_map<const formula*, const formula*,
|
||||
ptr_hash<formula>> snf_cache;
|
||||
typedef std::unordered_map<formula, formula> snf_cache;
|
||||
|
||||
/// Helper to rewrite a sere in Star Normal Form.
|
||||
///
|
||||
|
|
@ -49,11 +48,11 @@ namespace spot
|
|||
///
|
||||
/// \param sere the SERE to rewrite
|
||||
/// \param cache an optional cache
|
||||
SPOT_API const formula*
|
||||
star_normal_form(const formula* sere, snf_cache* cache = 0);
|
||||
SPOT_API formula
|
||||
star_normal_form(formula sere, snf_cache* cache = 0);
|
||||
|
||||
/// A variant of star_normal_form() for r[*0..j] where j < ω.
|
||||
SPOT_API const formula*
|
||||
star_normal_form_bounded(const formula* sere, snf_cache* cache = 0);
|
||||
SPOT_API formula
|
||||
star_normal_form_bounded(formula sere, snf_cache* cache = 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
|
||||
#include "unabbrev.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include <cassert>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -70,242 +68,183 @@ namespace spot
|
|||
}
|
||||
}
|
||||
|
||||
unabbreviator::~unabbreviator()
|
||||
{
|
||||
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)
|
||||
formula unabbreviator::run(formula in)
|
||||
{
|
||||
auto entry = cache_.emplace(in, nullptr);
|
||||
if (!entry.second)
|
||||
return entry.first->second->clone();
|
||||
in->clone();
|
||||
return entry.first->second;
|
||||
|
||||
// Skip recursion whenever possible
|
||||
bool no_boolean_rewrite = !re_some_bool_ || in->is_sugar_free_boolean();
|
||||
bool no_f_g_rewrite = !re_some_f_g_ || in->is_sugar_free_ltl();
|
||||
bool no_boolean_rewrite = !re_some_bool_ || in.is_sugar_free_boolean();
|
||||
bool no_f_g_rewrite = !re_some_f_g_ || in.is_sugar_free_ltl();
|
||||
if (no_boolean_rewrite
|
||||
&& (in->is_boolean() || (no_f_g_rewrite && !re_some_other_)))
|
||||
{
|
||||
entry.first->second = in->clone();
|
||||
return in->clone();
|
||||
}
|
||||
&& (in.is_boolean() || (no_f_g_rewrite && !re_some_other_)))
|
||||
return entry.first->second = in;
|
||||
|
||||
const formula* out = nullptr;
|
||||
switch (in->kind())
|
||||
auto rec = [this](formula f)
|
||||
{
|
||||
case formula::AtomicProp:
|
||||
case formula::Constant:
|
||||
out = in->clone();
|
||||
return this->run(f);
|
||||
};
|
||||
|
||||
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 formula::UnOp:
|
||||
{
|
||||
const unop* uo = static_cast<const unop*>(in);
|
||||
auto c = run(uo->child());
|
||||
switch (auto op = uo->op())
|
||||
{
|
||||
case op::F:
|
||||
// F f = true U f
|
||||
case unop::F:
|
||||
if (!re_f_)
|
||||
goto unop_clone;
|
||||
out = binop::instance(binop::U, constant::true_instance(), c);
|
||||
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)
|
||||
case unop::G:
|
||||
if (!re_g_)
|
||||
goto unop_clone;
|
||||
break;
|
||||
if (!re_r_)
|
||||
{
|
||||
out = binop::instance(binop::R,
|
||||
constant::false_instance(), c);
|
||||
out = formula::R(formula::ff(), out.nth(0));
|
||||
break;
|
||||
}
|
||||
if (!re_w_)
|
||||
{
|
||||
out = binop::instance(binop::W,
|
||||
c, constant::false_instance());
|
||||
out = formula::W(out.nth(0), formula::ff());
|
||||
break;
|
||||
}
|
||||
{
|
||||
auto nc = unop::instance(unop::Not, c);
|
||||
auto nc = formula::Not(out.nth(0));
|
||||
if (!re_f_)
|
||||
{
|
||||
out = unop::instance(unop::Not,
|
||||
unop::instance(unop::F, nc));
|
||||
out = formula::Not(formula::F(nc));
|
||||
break;
|
||||
}
|
||||
auto u = binop::instance(binop::U,
|
||||
constant::true_instance(), nc);
|
||||
out = unop::instance(unop::Not, u);
|
||||
out = formula::Not(formula::U(formula::tt(), nc));
|
||||
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())
|
||||
{
|
||||
case op::Xor:
|
||||
// f1 ^ f2 == !(f1 <-> f2)
|
||||
// f1 ^ f2 == (f1 & !f2) | (f2 & !f1)
|
||||
case binop::Xor:
|
||||
{
|
||||
if (!re_xor_)
|
||||
goto binop_clone;
|
||||
break;
|
||||
{
|
||||
auto f1 = out.nth(0);
|
||||
auto f2 = out.nth(1);
|
||||
if (!re_e_)
|
||||
{
|
||||
out = unop::instance(unop::Not,
|
||||
binop::instance(binop::Equiv,
|
||||
f1, f2));
|
||||
out = formula::Not(formula::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);
|
||||
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
|
||||
case binop::Implies:
|
||||
if (!re_i_)
|
||||
goto binop_clone;
|
||||
out = multop::instance(multop::Or,
|
||||
unop::instance(unop::Not, f1), f2);
|
||||
break;
|
||||
out = formula::Or({formula::Not(out.nth(0)), out.nth(1)});
|
||||
break;
|
||||
case op::Equiv:
|
||||
// f1 <=> f2 == (f1 & f2) | (!f1 & !f2)
|
||||
case binop::Equiv:
|
||||
if (!re_e_)
|
||||
goto binop_clone;
|
||||
break;
|
||||
{
|
||||
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);
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
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))
|
||||
case binop::R:
|
||||
if (!re_r_)
|
||||
goto binop_clone;
|
||||
break;
|
||||
{
|
||||
auto f12 = multop::instance(multop::And, f1, f2->clone());
|
||||
auto f1 = out.nth(0);
|
||||
auto f2 = out.nth(1);
|
||||
auto f12 = formula::And({f1, f2});
|
||||
if (!re_w_)
|
||||
{
|
||||
out = binop::instance(binop::W, f2, f12);
|
||||
out = formula::W(f2, f12);
|
||||
break;
|
||||
}
|
||||
out = unop::instance(unop::G, f2->clone());
|
||||
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 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:
|
||||
auto f1 = out.nth(0);
|
||||
auto f2 = out.nth(1);
|
||||
if (!re_r_)
|
||||
{
|
||||
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);
|
||||
out = formula::R(f2, formula::Or({f2, f1}));
|
||||
break;
|
||||
}
|
||||
case formula::BUnOp:
|
||||
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;
|
||||
{
|
||||
const bunop* bo = static_cast<const bunop*>(in);
|
||||
out = bunop::instance(bo->op(), run(bo->child()),
|
||||
bo->min(), bo->max());
|
||||
auto f2 = out.nth(1);
|
||||
out = formula::U(f2, formula::And({f2, out.nth(0)}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return entry.first->second = out;
|
||||
}
|
||||
|
||||
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);
|
||||
return un.run(in);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ namespace spot
|
|||
bool re_some_f_g_ = false; // rewrite F or G
|
||||
bool re_some_other_ = false; // rewrite W, M, or R
|
||||
// Cache of rewritten subformulas
|
||||
std::unordered_map<const formula*, const formula*> cache_;
|
||||
std::unordered_map<formula, formula> cache_;
|
||||
public:
|
||||
/// \brief Constructor
|
||||
///
|
||||
|
|
@ -55,8 +55,7 @@ namespace spot
|
|||
/// which in which each letter denote an operator (using LBT's
|
||||
/// convention).
|
||||
unabbreviator(const char* opt = default_unabbrev_string);
|
||||
const formula* run(const formula* in);
|
||||
~unabbreviator();
|
||||
formula run(formula in);
|
||||
};
|
||||
|
||||
/// \ingroup ltl_rewriting
|
||||
|
|
@ -66,8 +65,8 @@ namespace spot
|
|||
/// The set of operators to remove should be passed as a string
|
||||
/// which in which each letter denote an operator (using LBT's
|
||||
/// convention).
|
||||
SPOT_API const formula*
|
||||
unabbreviate(const formula* in, const char* opt= default_unabbrev_string);
|
||||
SPOT_API formula
|
||||
unabbreviate(formula in, const char* opt= default_unabbrev_string);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include "ltlast/constant.hh"
|
||||
#include "twa/formula2bdd.hh"
|
||||
#include "public.hh"
|
||||
#include "priv/accmap.hh"
|
||||
|
|
@ -45,9 +44,10 @@
|
|||
typedef std::map<int, bdd> map_t;
|
||||
|
||||
/* Cache parsed formulae. Labels on arcs are frequently identical
|
||||
and it would be a waste of time to parse them to formula* over and
|
||||
over, and to register all their atomic_propositions in the
|
||||
bdd_dict. Keep the bdd result around so we can reuse it. */
|
||||
and it would be a waste of time to parse them to ltl::formula
|
||||
over and over, and to register all their atomic_propositions in
|
||||
the bdd_dict. Keep the bdd result around so we can reuse
|
||||
it. */
|
||||
typedef std::map<std::string, bdd> formula_cache;
|
||||
|
||||
typedef std::pair<int, std::string*> pair;
|
||||
|
|
@ -152,7 +152,6 @@
|
|||
%code
|
||||
{
|
||||
#include <sstream>
|
||||
#include "ltlast/constant.hh"
|
||||
#include "ltlparse/public.hh"
|
||||
|
||||
/* parseaut.hh and parsedecl.hh include each other recursively.
|
||||
|
|
@ -561,9 +560,7 @@ ap-name: STRING
|
|||
std::ostringstream out;
|
||||
out << "unknown atomic proposition \"" << *$1 << "\"";
|
||||
error(@1, out.str());
|
||||
f = spot::ltl::default_environment::instance()
|
||||
.require("$unknown$");
|
||||
b = res.h->aut->register_ap(f);
|
||||
b = res.h->aut->register_ap("$unknown$");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -575,7 +572,6 @@ ap-name: STRING
|
|||
error(@1, out.str());
|
||||
}
|
||||
}
|
||||
f->destroy();
|
||||
res.ap.push_back(b);
|
||||
}
|
||||
delete $1;
|
||||
|
|
@ -1422,11 +1418,7 @@ nc-formula: nc-formula-or-ident
|
|||
}
|
||||
bdd cond = bddfalse;
|
||||
if (f)
|
||||
{
|
||||
cond = spot::formula_to_bdd(f, res.h->aut->get_dict(),
|
||||
res.h->aut);
|
||||
f->destroy();
|
||||
}
|
||||
cond = spot::formula_to_bdd(f, res.h->aut->get_dict(), res.h->aut);
|
||||
$$ = (res.fcache[*$1] = cond).id();
|
||||
}
|
||||
else
|
||||
|
|
@ -1587,7 +1579,7 @@ lbtt-acc: { $$ = 0U; }
|
|||
lbtt-guard: STRING
|
||||
{
|
||||
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())
|
||||
{
|
||||
std::string s = "failed to parse guard: ";
|
||||
|
|
@ -1611,7 +1603,7 @@ lbtt-guard: STRING
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!f->is_boolean())
|
||||
if (!f.is_boolean())
|
||||
{
|
||||
error(@$,
|
||||
"non-Boolean transition label (replaced by true)");
|
||||
|
|
@ -1622,7 +1614,6 @@ lbtt-guard: STRING
|
|||
res.cur_label =
|
||||
formula_to_bdd(f, res.h->aut->get_dict(), res.h->aut);
|
||||
}
|
||||
f->destroy();
|
||||
}
|
||||
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"}
|
||||
s,/\*(.*?)\*/,f($1),sge;
|
||||
s,//.*?\n,//\n,g;
|
||||
s,"[^"\n]*","",g;
|
||||
s,"(\\.|[^"\\\n])*","",g;
|
||||
s,SPOT_API ,,g' -0777 <$file >$tmp
|
||||
|
||||
$GREP '[ ]$' $tmp &&
|
||||
|
|
@ -231,10 +231,14 @@ for dir in "${INCDIR-..}" "${INCDIR-..}"/../iface; do
|
|||
$GREP -v 'for (.*;;)' $tmp | $GREP ';[^ ")'"']" &&
|
||||
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.'
|
||||
|
||||
$GREP '{.*{' $tmp &&
|
||||
$GREP '^[^()]{[^()]*{[^()]$' $tmp &&
|
||||
diag 'No two { on the same line.'
|
||||
|
||||
$GREP 'delete[ ]*[(][^(]*[)];' $tmp &&
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@
|
|||
#define trace while (0) std::clog
|
||||
#endif
|
||||
|
||||
#include "ltlast/atomic_prop.hh"
|
||||
#include "ltlast/constant.hh"
|
||||
#include "taexplicit.hh"
|
||||
#include "twa/formula2bdd.hh"
|
||||
#include <cassert>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
// 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/atomic_prop.hh"
|
||||
#include "ltlast/constant.hh"
|
||||
#include "tgtaexplicit.hh"
|
||||
#include "twa/formula2bdd.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