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:
Alexandre Duret-Lutz 2015-09-24 19:44:00 +02:00
parent 1628b188fe
commit b77f7e24c3
177 changed files with 8295 additions and 13332 deletions

View file

@ -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();
}

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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)
{

View file

@ -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;

View file

@ -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);

View file

@ -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);
};

View file

@ -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();
}

View file

@ -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

View file

@ -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;
}
};

View file

@ -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;
}

View file

@ -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)

View file

@ -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;

View file

@ -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 ≡ (ab)→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,22 +446,8 @@ 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)
: 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
matched = false;
}
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;
}
};

View file

@ -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();
}
output_formula_checked(g, filename, linenum);
return 0;
}
};

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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>&

View file

@ -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,8 +109,8 @@ strident "," condition "," follow_list ";"
if (i == fcache.end())
{
parse_error_list pel;
const formula* f = spot::ltl::parse_infix_boolean(*$3, pel,
parse_environment);
formula f = spot::ltl::parse_infix_boolean(*$3, pel,
parse_environment);
for (parse_error_list::iterator i = pel.begin();
i != pel.end(); ++i)
{

View file

@ -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

View file

@ -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"

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
};
}
}

View file

@ -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&

View file

@ -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;

View file

@ -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&

View file

@ -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.

View file

@ -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;

View file

@ -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

View file

@ -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,12 +66,12 @@ namespace spot
///
/// \warning This function is not reentrant.
SPOT_API
const formula* parse_infix_psl(const std::string& ltl_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false,
bool lenient = false);
formula parse_infix_psl(const std::string& ltl_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false,
bool lenient = false);
/// \brief Build a Boolean formula from a string.
/// \param ltl_string The string to parse.
@ -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,12 +92,12 @@ namespace spot
///
/// \warning This function is not reentrant.
SPOT_API
const formula* parse_infix_boolean(const std::string& ltl_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false,
bool lenient = false);
formula parse_infix_boolean(const std::string& ltl_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false,
bool lenient = false);
/// \brief Build a formula from an LTL string in LBT's format.
/// \param ltl_string The string to parse.
@ -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,11 +119,11 @@ namespace spot
///
/// \warning This function is not reentrant.
SPOT_API
const formula* parse_prefix_ltl(const std::string& ltl_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false);
formula parse_prefix_ltl(const std::string& ltl_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false);
/// \brief A simple wrapper to parse_infix_psl() and parse_prefix_ltl().
///
@ -131,7 +131,7 @@ namespace spot
/// parse_infix_psl(); if this fails it tries parse_prefix_ltl();
/// 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,12 +154,12 @@ namespace spot
///
/// \warning This function is not reentrant.
SPOT_API
const formula* parse_infix_sere(const std::string& sere_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false,
bool lenient = false);
formula parse_infix_sere(const std::string& sere_string,
parse_error_list& error_list,
environment& env =
default_environment::instance(),
bool debug = false,
bool lenient = false);
/// \brief Format diagnostics produced by spot::ltl::parse
/// or spot::ltl::ratexp
@ -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

View file

@ -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 \

View file

@ -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;
}
}

View file

@ -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);
/// @}
}

View file

@ -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_;
}
}
}

View file

@ -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_;
};
}
}

View file

@ -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);

View file

@ -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_;

View file

@ -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_;
virtual
~dotty_visitor()
{
}
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";
}
void
visit(const atomic_prop* ap)
~dot_printer()
{
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;
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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;
};

View file

@ -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
int
length(formula f)
{
class length_visitor: public postfix_visitor
{
public:
length_visitor()
: result_(0)
{
}
int
result() const
{
return result_;
}
virtual void
visit(const multop* mo)
{
unsigned s = mo->size();
for (unsigned i = 0; i < s; ++i)
mo->nth(i)->accept(*this);
// "a & b & c" should count for 5, even though it is
// stored as And(a,b,c).
result_ += s - 1;
}
virtual void
doit_default(const formula*)
{
++result_;
}
protected:
int result_; // size of the formula
};
class length_boolone_visitor: public length_visitor
{
virtual void
visit(const unop* uo)
{
++result_;
// Boolean formulas have length one.
if (!uo->is_boolean())
uo->child()->accept(*this);
}
virtual void
visit(const multop* mo)
{
// Boolean formulas have length one.
if (mo->is_boolean())
{
++result_;
return;
}
unsigned s = mo->size();
unsigned bool_seen = 0;
for (unsigned i = 0; i < s; ++i)
{
const formula* f = mo->nth(i);
// Ignore all Boolean children. We only want to count them once.
if (f->is_boolean())
++bool_seen;
else
f->accept(*this);
}
// "a & b & c" should count for 5, even though it is stored
// as And(a,b,c). So add the number of operators here (it
// is either s - 1 or s - bool_seen depending on whether
// Boolean children were encountered). If Boolean were
// seen, also add one (!!bool_seen) to account for the
// "global" Boolean term.
result_ += s - !bool_seen - bool_seen + !!bool_seen;
}
};
int len = 0;
f.traverse([&len](const formula& x)
{
auto s = x.size();
if (s > 1)
len += s - 1;
else
++len;
return false;
});
return len;
}
int
length(const formula* f)
length_boolone(formula f)
{
length_visitor v;
f->accept(v);
return v.result();
}
int
length_boolone(const formula* f)
{
length_boolone_visitor v;
f->accept(v);
return v.result();
int len = 0;
f.traverse([&len](const formula& x)
{
if (x.is_boolean())
{
++len;
return true;
}
auto s = x.size();
if (s > 2)
{
int b = 0;
for (const auto& y: x)
if (y.is_boolean())
++b;
len += s - b * 2 + 1;
}
else if (s > 1)
{
len += s - 1;
}
else
{
++len;
}
return false;
});
return len;
}
}

View file

@ -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);
}
}

View file

@ -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
{
class simplify_mark_visitor : public visitor
{
const formula* result_;
mark_tools* tools_;
public:
simplify_mark_visitor(mark_tools* t)
: tools_(t)
{
}
~simplify_mark_visitor()
{
}
const formula*
result()
{
return result_;
}
void
visit(const atomic_prop* ao)
{
result_ = ao->clone();
}
void
visit(const constant* c)
{
result_ = c->clone();
}
void
visit(const bunop* bo)
{
result_ = bo->clone();
}
void
visit(const unop* uo)
{
result_ = uo->clone();
}
void
visit(const multop* mo)
{
unsigned mos = mo->size();
multop::vec* res = new multop::vec;
switch (mo->op())
{
case multop::OrRat:
case multop::AndNLM:
case multop::AndRat:
case multop::Concat:
case multop::Fusion:
SPOT_UNIMPLEMENTED();
case multop::Or:
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse(mo->nth(i)));
break;
case multop::And:
{
typedef std::set<std::pair<const formula*,
const formula*> > pset;
pset empairs;
typedef std::set<const formula*> sset;
sset nmset;
typedef std::vector<const binop*> unbinop;
unbinop elist;
typedef std::vector<const unop*> ununop;
ununop nlist;
for (unsigned i = 0; i < mos; ++i)
{
const formula* f = mo->nth(i);
if (const binop* bo = is_binop(f))
{
switch (bo->op())
{
case binop::EConcatMarked:
empairs.emplace(bo->first(), bo->second());
// fall through
case binop::Xor:
case binop::Implies:
case binop::Equiv:
case binop::U:
case binop::W:
case binop::M:
case binop::R:
case binop::UConcat:
res->push_back(recurse(f));
break;
case binop::EConcat:
elist.push_back(bo);
break;
}
}
if (const unop* uo = is_unop(f))
{
switch (uo->op())
{
case unop::NegClosureMarked:
nmset.insert(uo->child());
// fall through
case unop::Not:
case unop::X:
case unop::F:
case unop::G:
case unop::Closure:
res->push_back(recurse(f));
break;
case unop::NegClosure:
nlist.push_back(uo);
break;
}
}
else
{
res->push_back(recurse(f));
}
}
// Keep only the non-marked EConcat for which we
// have not seen a similar EConcatMarked.
for (unbinop::const_iterator i = elist.begin();
i != elist.end(); ++i)
if (empairs.find(std::make_pair((*i)->first(),
(*i)->second()))
== empairs.end())
res->push_back((*i)->clone());
// Keep only the non-marked NegClosure for which we
// have not seen a similar NegClosureMarked.
for (ununop::const_iterator i = nlist.begin();
i != nlist.end(); ++i)
if (nmset.find((*i)->child()) == nmset.end())
res->push_back((*i)->clone());
}
}
result_ = multop::instance(mo->op(), res);
}
void
visit(const binop* bo)
{
result_ = bo->clone();
}
const formula*
recurse(const formula* f)
{
return tools_->simplify_mark(f);
}
};
class mark_visitor : public visitor
{
const formula* result_;
mark_tools* tools_;
public:
mark_visitor(mark_tools* t)
: tools_(t)
{
}
~mark_visitor()
{
}
const formula*
result()
{
return result_;
}
void
visit(const atomic_prop* ap)
{
result_ = ap->clone();
}
void
visit(const constant* c)
{
result_ = c->clone();
}
void
visit(const bunop* bo)
{
result_ = bo->clone();
}
void
visit(const unop* uo)
{
switch (uo->op())
{
case unop::Not:
case unop::X:
case unop::F:
case unop::G:
case unop::Closure:
case unop::NegClosureMarked:
result_ = uo->clone();
return;
case unop::NegClosure:
result_ = unop::instance(unop::NegClosureMarked,
uo->child()->clone());
return;
}
SPOT_UNREACHABLE();
}
void
visit(const multop* mo)
{
multop::vec* res = new multop::vec;
unsigned mos = mo->size();
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse(mo->nth(i)));
result_ = multop::instance(mo->op(), res);
}
void
visit(const binop* bo)
{
switch (bo->op())
{
case binop::Xor:
case binop::Implies:
case binop::Equiv:
SPOT_UNIMPLEMENTED();
case binop::U:
case binop::W:
case binop::M:
case binop::R:
case binop::UConcat:
case binop::EConcatMarked:
result_ = bo->clone();
return;
case binop::EConcat:
{
const formula* f1 = bo->first()->clone();
const formula* f2 = bo->second()->clone();
result_ = binop::instance(binop::EConcatMarked, f1, f2);
return;
}
}
SPOT_UNREACHABLE();
}
const formula*
recurse(const formula* f)
{
return tools_->mark_concat_ops(f);
}
};
}
mark_tools::mark_tools()
: simpvisitor_(new simplify_mark_visitor(this)),
markvisitor_(new mark_visitor(this))
{
}
mark_tools::~mark_tools()
{
delete simpvisitor_;
delete markvisitor_;
{
f2f_map::iterator i = simpmark_.begin();
f2f_map::iterator end = simpmark_.end();
while (i != end)
{
f2f_map::iterator old = i++;
old->second->destroy();
old->first->destroy();
}
}
{
f2f_map::iterator i = markops_.begin();
f2f_map::iterator end = markops_.end();
while (i != end)
{
f2f_map::iterator old = i++;
old->second->destroy();
old->first->destroy();
}
}
}
const formula*
mark_tools::mark_concat_ops(const formula* f)
formula
mark_tools::mark_concat_ops(formula f)
{
f2f_map::iterator i = markops_.find(f);
if (i != markops_.end())
return i->second->clone();
return i->second;
f->accept(*markvisitor_);
ltl::formula res;
switch (f.kind())
{
case op::False:
case op::True:
case op::EmptyWord:
case op::AP:
case op::Not:
case op::X:
case op::F:
case op::G:
case op::Closure:
case op::NegClosureMarked:
case op::OrRat:
case op::AndRat:
case op::AndNLM:
case op::Star:
case op::FStar:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcatMarked:
case op::UConcat:
case op::Concat:
case op::Fusion:
res = f;
break;
case op::NegClosure:
res = ltl::formula::NegClosureMarked(f.nth(0));
break;
case op::EConcat:
res = ltl::formula::EConcatMarked(f.nth(0), f.nth(1));
break;
case op::Or:
case op::And:
res = f.map([this](formula f)
{
return this->mark_concat_ops(f);
});
break;
case op::Xor:
case op::Implies:
case op::Equiv:
SPOT_UNIMPLEMENTED();
}
const formula* r = down_cast<mark_visitor*>(markvisitor_)->result();
markops_[f->clone()] = r->clone();
return r;
markops_[f] = res;
return res;
}
const formula*
mark_tools::simplify_mark(const formula* f)
formula
mark_tools::simplify_mark(formula f)
{
if (!f->is_marked())
return f->clone();
if (!f.is_marked())
return f;
f2f_map::iterator i = simpmark_.find(f);
if (i != simpmark_.end())
return i->second->clone();
return i->second;
f->accept(*simpvisitor_);
auto recurse = [this](formula f)
{
return this->simplify_mark(f);
};
const formula* r =
down_cast<simplify_mark_visitor*>(simpvisitor_)->result();
simpmark_[f->clone()] = r->clone();
return r;
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 op::Or:
res = f.map(recurse);
break;
case op::And:
{
std::set<std::pair<formula, formula>> empairs;
std::set<formula> nmset;
std::vector<formula> elist;
std::vector<formula> nlist;
std::vector<formula> v;
for (auto c: f)
{
if (c.is(op::EConcatMarked))
{
empairs.emplace(c.nth(0), c.nth(1));
v.push_back(c.map(recurse));
}
else if (c.is(op::EConcat))
{
elist.push_back(c);
}
else if (c.is(op::NegClosureMarked))
{
nmset.insert(c.nth(0));
v.push_back(c.map(recurse));
}
else if (c.is(op::NegClosure))
{
nlist.push_back(c);
}
else
{
v.push_back(c);
}
}
// Keep only the non-marked EConcat for which we
// have not seen a similar EConcatMarked.
for (auto e: elist)
if (empairs.find(std::make_pair(e.nth(0), e.nth(1)))
== empairs.end())
v.push_back(e);
// Keep only the non-marked NegClosure for which we
// have not seen a similar NegClosureMarked.
for (auto n: nlist)
if (nmset.find(n.nth(0)) == nmset.end())
v.push_back(n);
res = ltl::formula::And(v);
}
break;
case op::Xor:
case op::Implies:
case op::Equiv:
case op::OrRat:
case op::AndRat:
case op::AndNLM:
case op::Star:
case op::FStar:
case op::Concat:
case op::Fusion:
SPOT_UNIMPLEMENTED();
}
simpmark_[f] = res;
return res;
}
}

View file

@ -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_;
};
}

View file

@ -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,355 +36,307 @@ 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)
{
if (ap == ap1_)
result_ = ap2_->clone();
else
result_ = ap->clone();
}
return f.map([&](formula f)
{
if (f == ap_src)
return ap_dst;
else
return substitute_ap(f, ap_src, ap_dst);
});
}
const formula*
replace(const formula* f,
const atomic_prop* ap1,
const atomic_prop* ap2)
{
ap1_ = ap1;
ap2_ = ap2;
return recurse(f);
}
private:
const atomic_prop* ap1_;
const atomic_prop* ap2_;
};
typedef std::vector<const formula*> vec;
class mutation_visitor final : public clone_visitor
typedef std::vector<formula> vec;
class mutator final
{
int mutation_counter_ = 0;
formula f_;
unsigned opts_;
public:
mutation_visitor(const formula* f, unsigned opts) : f_(f), opts_(opts)
mutator(formula f, unsigned opts) : f_(f), opts_(opts)
{
}
void visit(const atomic_prop* ap)
formula mutate(formula f)
{
result_ = 0;
if (opts_ & Mut_Ap2Const)
{
if (mutation_counter_-- == 0)
result_ = constant::true_instance();
if (mutation_counter_-- == 0)
result_ = constant::false_instance();
}
if (!result_)
result_ = ap->clone();
}
void visit(const unop* uo)
{
result_ = 0;
if (opts_ & Mut_Remove_Ops)
{
if ((uo->op() == unop::G
|| uo->op() == unop::F
|| uo->op() == unop::X
|| uo->op() == unop::Not)
&& mutation_counter_-- == 0)
result_ = uo->child()->clone();
}
if (!result_)
{
if (mutation_counter_ < 0)
result_ = uo->clone();
else
{
result_ = unop::instance(uo->op(), recurse(uo->child()));
}
}
}
void visit(const binop* bo)
{
const formula* first = bo->first();
const formula* second = bo->second();
result_ = 0;
auto op = bo->op();
bool left_is_sere = op == binop::EConcat
|| op == binop::EConcatMarked
|| op == binop::UConcat;
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
auto recurse = [this](formula f)
{
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);
}
}
}
return this->mutate(f);
};
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)
switch (f.kind())
{
case op::False:
case op::True:
case op::EmptyWord:
return f;
case op::AP:
if (opts_ & Mut_Ap2Const)
{
if (mutation_counter_-- == 0)
result_ = bunop::instance(op, c, min - 1, max);
return formula::tt();
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;
if (opts_ & Mut_Remove_Multop_Operands)
{
for (i = 0; i < mos; ++i)
if (mutation_counter_-- == 0)
result_ = mo->all_but(i);
}
if (opts_ & Mut_Split_Ops && mo->op() == multop::AndNLM)
{
if (mutation_counter_ >= 0 && mutation_counter_ < 2 * (mos - 1))
{
vec* v1 = new vec();
vec* v2 = new vec();
v1->push_back(mo->nth(0)->clone());
bool reverse = false;
i = 1;
while (i < mos)
{
if (mutation_counter_-- == 0)
break;
if (mutation_counter_-- == 0)
{
reverse = true;
break;
}
v1->push_back(mo->nth(i++)->clone());
}
for (; i < mos; ++i)
v2->push_back(mo->nth(i)->clone());
const formula* tstar =
bunop::instance(bunop::Star, constant::true_instance(),
0,
bunop::unbounded);
const formula* first = AndNLM_(v1);
const formula* second = AndNLM_(v2);
if (!reverse)
result_ = AndRat_(Concat_(first, tstar), second);
else
result_ = AndRat_(Concat_(second, tstar), first);
return formula::ff();
}
return f;
case op::Not:
case op::X:
case op::F:
case op::G:
if ((opts_ & Mut_Remove_Ops)
&& mutation_counter_-- == 0)
return f.nth(0);
// fall through
case op::Closure:
case op::NegClosure:
case op::NegClosureMarked:
if (mutation_counter_ < 0)
return f;
else
mutation_counter_ -= 2 * (mos - 1);
}
return f.map(recurse);
case op::Or:
case op::OrRat:
case op::And:
case op::AndRat:
case op::AndNLM:
case op::Concat:
case op::Fusion:
{
int mos = f.size();
if (opts_ & Mut_Remove_Multop_Operands)
{
for (int i = 0; i < mos; ++i)
if (mutation_counter_-- == 0)
return f.all_but(i);
}
if (!result_)
{
if (mutation_counter_ < 0)
result_ = mo->clone();
else
{
vec* v = new vec();
for (i = 0; i < mos; ++i)
v->push_back(recurse(mo->nth(i)));
result_ = multop::instance(mo->op(), v);
}
}
if (opts_ & Mut_Split_Ops && f.is(op::AndNLM))
{
if (mutation_counter_ >= 0
&& mutation_counter_ < 2 * (mos - 1))
{
vec v1;
vec v2;
v1.push_back(f.nth(0));
bool reverse = false;
int i = 1;
while (i < mos)
{
if (mutation_counter_-- == 0)
break;
if (mutation_counter_-- == 0)
{
reverse = true;
break;
}
v1.push_back(f.nth(i++));
}
for (; i < mos; ++i)
v2.push_back(f.nth(i));
formula first = AndNLM_(v1);
formula second = AndNLM_(v2);
formula ost = formula::one_star();
if (!reverse)
return AndRat_(Concat_(first, ost), second);
else
return AndRat_(Concat_(second, ost), first);
}
else
{
mutation_counter_ -= 2 * (mos - 1);
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
case op::Xor:
case op::Implies:
case op::Equiv:
case op::U:
case op::R:
case op::W:
case op::M:
case op::EConcat:
case op::EConcatMarked:
case op::UConcat:
{
formula first = f.nth(0);
formula second = f.nth(1);
op o = f.kind();
bool left_is_sere = o == op::EConcat
|| o == op::EConcatMarked
|| o == op::UConcat;
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
{
if (!left_is_sere)
return first;
else if (o == op::UConcat)
return formula::NegClosure(first);
else // EConcat or EConcatMarked
return formula::Closure(first);
}
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
return second;
if (opts_ & Mut_Rewrite_Ops)
{
switch (o)
{
case op::U:
if (mutation_counter_-- == 0)
return formula::W(first, second);
break;
case op::M:
if (mutation_counter_-- == 0)
return formula::R(first, second);
if (mutation_counter_-- == 0)
return formula::U(second, first);
break;
case op::R:
if (mutation_counter_-- == 0)
return formula::W(second, first);
break;
default:
break;
}
}
if (opts_ & Mut_Split_Ops)
{
switch (o)
{
case op::Equiv:
if (mutation_counter_-- == 0)
return formula::Implies(first, second);
if (mutation_counter_-- == 0)
return formula::Implies(second, first);
if (mutation_counter_-- == 0)
return formula::And({first, second});
if (mutation_counter_-- == 0)
{
// Negate the two argument sequentially (in this
// case right before left, otherwise different
// compilers will make different choices.
auto right = formula::Not(second);
return formula::And({formula::Not(first), right});
}
break;
case op::Xor:
if (mutation_counter_-- == 0)
return formula::And({first, formula::Not(second)});
if (mutation_counter_-- == 0)
return formula::And({formula::Not(first), second});
break;
default:
break;
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
case op::Star:
case op::FStar:
{
formula c = f.nth(0);
op o = f.kind();
if (opts_ & Mut_Remove_Ops && mutation_counter_-- == 0)
return c;
if (opts_ & Mut_Simplify_Bounds)
{
auto min = f.min();
auto max = f.max();
if (min > 0)
{
if (mutation_counter_-- == 0)
return formula::bunop(o, c, min - 1, max);
if (mutation_counter_-- == 0)
return formula::bunop(o, c, 0, max);
}
if (max != formula::unbounded())
{
if (max > min && mutation_counter_-- == 0)
return formula::bunop(o, c, min, max - 1);
if (mutation_counter_-- == 0)
return formula::bunop(o, c, min,
formula::unbounded());
}
}
if (mutation_counter_ < 0)
return f;
else
return f.map(recurse);
}
}
SPOT_UNREACHABLE();
}
const formula*
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;
}
--n;
}
else
{
const formula* mut(nullptr);
formula mut;
int i = 0;
mutation_visitor mv(f, opts);
while (n > 0 && (mut = mv.get_mutation(i++)))
{
single_mutation_rec(mut, mutations, opts, n, m - 1);
mut->destroy();
}
mutator mv(f, opts);
while (n > 0 && ((mut = mv.get_mutation(i++)) != nullptr))
single_mutation_rec(mut, mutations, opts, n, m - 1);
}
}
void
replace_ap_rec(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;
}
--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;

View file

@ -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,10 +39,10 @@ namespace spot
};
SPOT_API
std::vector<const formula*> mutate(const formula* f,
unsigned opts = Mut_All,
unsigned max_output = -1U,
unsigned mutation_count = 1,
bool sort = true);
std::vector<formula> mutate(formula f,
unsigned opts = Mut_All,
unsigned max_output = -1U,
unsigned mutation_count = 1,
bool sort = true);
}
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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.
}
}
}

View file

@ -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

View file

@ -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);
/// @}
}
}

View file

@ -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
{
ignore = true;
f->destroy();
}
}
if (opt_unique_ && !unique_set_.insert(f).second)
ignore = true;
} 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;
}

View file

@ -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_;

View file

@ -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)
{
}
{
// Connect to parent
auto in = g.emplace(f, succ_vec());
if (!s.empty())
{
formula top = s.top();
in.first->second.push_back(top);
g[top].push_back(f);
if (!in.second)
return;
}
else
{
assert(in.second);
}
}
s.push(f);
void
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 sz = f.size();
unsigned i = 0;
const formula* b = mo->is_boolean() ? 0 : mo->boolean_operands(&i);
if (b)
if (sz > 2 && !f.is_boolean())
{
recurse(b);
b->destroy();
/// 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 < 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())
for (; i < sz; ++i)
visit(f.nth(i));
if (sz > 1 && f.is_boolean())
{
const formula* pred = mo->nth(0);
for (i = 1; i < mos; ++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).
formula pred = f.nth(0);
for (i = 1; i < sz; ++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.
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(mo->nth(0));
g[pred].push_back(f.nth(0));
}
}
void
recurse(const formula* f)
{
auto i = g.emplace(f, succ_vec());
if (!s.empty())
{
const formula* top = s.top();
i.first->second.push_back(top);
g[top].push_back(f);
if (!i.second)
return;
}
else
{
assert(i.second);
}
f->clone();
s.push(f);
f->accept(*this);
s.pop();
}
};
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);
}
}
}

View file

@ -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,8 +37,8 @@ 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,
relabeling_map* m = 0);
formula relabel(formula f, relabeling_style style,
relabeling_map* m = 0);
/// \ingroup ltl_rewriting
@ -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,
relabeling_map* m = 0);
formula relabel_bse(formula f, relabeling_style style,
relabeling_map* m = 0);
}
}

View file

@ -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
{
#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
static formula
remove_x_rec(formula f, atomic_prop_set& aps)
{
typedef clone_visitor super;
atomic_prop_set aps;
if (f.is_syntactic_stutter_invariant())
return f;
public:
remove_x_visitor(const formula* f)
{
atomic_prop_collect(f, &aps);
}
auto rec = [&aps](formula f)
{
return remove_x_rec(f, aps);
};
virtual
~remove_x_visitor()
{
}
if (!f.is(op::X))
return f.map(rec);
using super::visit;
void visit(const unop* uo)
{
const formula* c = recurse(uo->child());
formula c = rec(f.nth(0));
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();
}
};
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);
}
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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;

View file

@ -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)
{
assert(c == constant::empty_word_instance());
(void)c;
result_ = constant::false_instance();
}
void
visit(const bunop* bo)
{
bunop::type op = bo->op();
switch (op)
formula out;
switch (f.kind())
{
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*)
{
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();
break;
case multop::Concat:
case multop::AndNLM:
case op::Concat:
if (bounded)
{
out = f;
break;
}
// Fall through
case op::OrRat:
case op::AndNLM:
// Let F designate expressions that accept [*0],
// and G designate expressions that do not.
@ -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);
v.emplace_back(visit(f.nth(pos)));
out = formula::OrRat(v);
break;
}
break;
case multop::AndRat:
// FIXME: Can we deal with AndRat in a better way
// when it accepts [*0]?
result_ = mo->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;
}
}
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();
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);
}
}

View file

@ -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);
}
}

View file

@ -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_)))
&& (in.is_boolean() || (no_f_g_rewrite && !re_some_other_)))
return entry.first->second = in;
auto rec = [this](formula f)
{
entry.first->second = in->clone();
return 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 op::F:
// F f = true U f
if (!re_f_)
break;
out = formula::U(formula::tt(), out.nth(0));
break;
case op::G:
// G f = false R f
// G f = f W false
// G f = !F!f
// G f = !(true U !f)
if (!re_g_)
break;
if (!re_r_)
{
out = formula::R(formula::ff(), out.nth(0));
break;
}
if (!re_w_)
{
out = formula::W(out.nth(0), formula::ff());
break;
}
{
auto nc = formula::Not(out.nth(0));
if (!re_f_)
{
out = formula::Not(formula::F(nc));
break;
}
out = formula::Not(formula::U(formula::tt(), nc));
break;
}
case op::Xor:
// f1 ^ f2 == !(f1 <-> f2)
// f1 ^ f2 == (f1 & !f2) | (f2 & !f1)
if (!re_xor_)
break;
{
auto f1 = out.nth(0);
auto f2 = out.nth(1);
if (!re_e_)
{
out = formula::Not(formula::Equiv(f1, f2));
}
else
{
auto a = formula::And({f1, formula::Not(f2)});
auto b = formula::And({f2, formula::Not(f1)});
out = formula::Or({a, b});
}
}
break;
case op::Implies:
// f1 => f2 == !f1 | f2
if (!re_i_)
break;
out = formula::Or({formula::Not(out.nth(0)), out.nth(1)});
break;
case op::Equiv:
// f1 <=> f2 == (f1 & f2) | (!f1 & !f2)
if (!re_e_)
break;
{
auto f1 = out.nth(0);
auto f2 = out.nth(1);
auto nf1 = formula::Not(f1);
auto nf2 = formula::Not(f2);
auto term1 = formula::And({f1, f2});
auto term2 = formula::And({nf1, nf2});
out = formula::Or({term1, term2});
break;
}
case op::R:
// f1 R f2 = f2 W (f1 & f2)
// f1 R f2 = f2 U ((f1 & f2) | Gf2)
// f1 R f2 = f2 U ((f1 & f2) | !F!f2)
// f1 R f2 = f2 U ((f1 & f2) | !(1 U !f2))
if (!re_r_)
break;
{
auto f1 = out.nth(0);
auto f2 = out.nth(1);
auto f12 = formula::And({f1, f2});
if (!re_w_)
{
out = formula::W(f2, f12);
break;
}
auto gf2 = formula::G(f2);
if (re_g_)
gf2 = run(gf2);
out = formula::U(f2, formula::Or({f12, out}));
break;
}
case op::W:
// f1 W f2 = f2 R (f2 | f1)
// f1 W f2 = f1 U (f2 | G f1)
// f1 W f2 = f1 U (f2 | !F !f1)
// f1 W f2 = f1 U (f2 | !(1 U !f1))
if (!re_w_)
break;
{
auto f1 = out.nth(0);
auto f2 = out.nth(1);
if (!re_r_)
{
out = formula::R(f2, formula::Or({f2, f1}));
break;
}
auto gf1 = formula::G(f1);
if (re_g_)
gf1 = rec(gf1);
out = formula::U(f1, formula::Or({f2, out}));
break;
}
case op::M:
// f1 M f2 = f2 U (g2 & f1)
if (!re_m_)
break;
{
auto f2 = out.nth(1);
out = formula::U(f2, formula::And({f2, out.nth(0)}));
break;
}
}
const formula* out = nullptr;
switch (in->kind())
{
case formula::AtomicProp:
case formula::Constant:
out = in->clone();
break;
case formula::UnOp:
{
const unop* uo = static_cast<const unop*>(in);
auto c = run(uo->child());
switch (auto op = uo->op())
{
// F f = true U f
case unop::F:
if (!re_f_)
goto unop_clone;
out = binop::instance(binop::U, constant::true_instance(), c);
break;
// G f = false R f
// G f = f W false
// G f = !F!f
// G f = !(true U !f)
case unop::G:
if (!re_g_)
goto unop_clone;
if (!re_r_)
{
out = binop::instance(binop::R,
constant::false_instance(), c);
break;
}
if (!re_w_)
{
out = binop::instance(binop::W,
c, constant::false_instance());
break;
}
{
auto nc = unop::instance(unop::Not, c);
if (!re_f_)
{
out = unop::instance(unop::Not,
unop::instance(unop::F, nc));
break;
}
auto u = binop::instance(binop::U,
constant::true_instance(), nc);
out = unop::instance(unop::Not, u);
break;
}
case unop::Not:
case unop::X:
case unop::Closure:
case unop::NegClosure:
case unop::NegClosureMarked:
unop_clone:
out = unop::instance(op, c);
break;
}
break;
}
case formula::BinOp:
{
const binop* bo = static_cast<const binop*>(in);
auto f1 = run(bo->first());
auto f2 = run(bo->second());
switch (auto op = bo->op())
{
// f1 ^ f2 == !(f1 <-> f2)
// f1 ^ f2 == (f1 & !f2) | (f2 & !f1)
case binop::Xor:
{
if (!re_xor_)
goto binop_clone;
if (!re_e_)
{
out = unop::instance(unop::Not,
binop::instance(binop::Equiv,
f1, f2));
}
else
{
auto a = multop::instance(multop::And, f1->clone(),
unop::instance(unop::Not,
f2->clone()));
auto b = multop::instance(multop::And, f2,
unop::instance(unop::Not, f1));
out = multop::instance(multop::Or, a, b);
}
break;
}
// f1 => f2 == !f1 | f2
case binop::Implies:
if (!re_i_)
goto binop_clone;
out = multop::instance(multop::Or,
unop::instance(unop::Not, f1), f2);
break;
// f1 <=> f2 == (f1 & f2) | (!f1 & !f2)
case binop::Equiv:
if (!re_e_)
goto binop_clone;
{
auto nf1 = unop::instance(unop::Not, f1->clone());
auto nf2 = unop::instance(unop::Not, f2->clone());
auto term1 = multop::instance(multop::And, f1, f2);
auto term2 = multop::instance(multop::And, nf1, nf2);
out = multop::instance(multop::Or, term1, term2);
break;
}
// f1 W f2 = f2 R (f2 | f1)
// f1 W f2 = f1 U (f2 | G f1)
// f1 W f2 = f1 U (f2 | !F !f1)
// f1 W f2 = f1 U (f2 | !(1 U !f1))
case binop::W:
if (!re_w_)
goto binop_clone;
if (!re_r_)
{
out = binop::instance(binop::R, f2,
multop::instance(multop::Or,
f2->clone(), f1));
break;
}
f1->clone();
out = unop::instance(unop::G, f1);
if (re_g_)
{
auto tmp = out;
out = run(out);
tmp->destroy();
}
out = binop::instance(binop::U, f1,
multop::instance(multop::Or, f2, out));
break;
// f1 M f2 = f2 U (g2 & f1)
case binop::M:
if (!re_m_)
goto binop_clone;
out = binop::instance(binop::U, f2,
multop::instance(multop::And,
f2->clone(), f1));
break;
// f1 R f2 = f2 W (f1 & f2)
// f1 R f2 = f2 U ((f1 & f2) | Gf2)
// f1 R f2 = f2 U ((f1 & f2) | !F!f2)
// f1 R f2 = f2 U ((f1 & f2) | !(1 U !f2))
case binop::R:
if (!re_r_)
goto binop_clone;
{
auto f12 = multop::instance(multop::And, f1, f2->clone());
if (!re_w_)
{
out = binop::instance(binop::W, f2, f12);
break;
}
out = unop::instance(unop::G, f2->clone());
if (re_g_)
{
auto tmp = out;
out = run(tmp);
tmp->destroy();
}
out = binop::instance(binop::U, f2,
multop::instance(multop::Or, f12, out));
}
break;
case binop::U:
case binop::UConcat:
case binop::EConcat:
case binop::EConcatMarked:
binop_clone:
out = binop::instance(op, f1, f2);
break;
}
break;
}
case formula::MultOp:
{
const multop* mo = static_cast<const multop*>(in);
multop::vec* res = new multop::vec;
unsigned mos = mo->size();
res->reserve(mos);
for (unsigned i = 0; i < mos; ++i)
res->push_back(run(mo->nth(i)));
out = multop::instance(mo->op(), res);
break;
}
case formula::BUnOp:
{
const bunop* bo = static_cast<const bunop*>(in);
out = bunop::instance(bo->op(), run(bo->child()),
bo->min(), bo->max());
break;
}
}
assert(out != nullptr);
entry.first->second = out;
return out->clone();
return entry.first->second = out;
}
const formula* unabbreviate(const formula* in, const char* opt)
formula unabbreviate(formula in, const char* opt)
{
unabbreviator un(opt);
return un.run(in);

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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 &&

View file

@ -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>

View file

@ -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"

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013, 2014 Laboratoire de Recherche
// et Développement de l'Epita (LRDE).
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
@ -30,7 +30,6 @@
#include <list>
#include <sstream>
#include "minimize.hh"
#include "ltlast/allnodes.hh"
#include "misc/hash.hh"
#include "misc/bddlt.hh"
#include "ta/tgtaexplicit.hh"

View file

@ -26,8 +26,6 @@
#define trace while (0) std::clog
#endif
#include "ltlast/atomic_prop.hh"
#include "ltlast/constant.hh"
#include "twa/formula2bdd.hh"
#include <cassert>
#include <iostream>

View file

@ -1,6 +1,6 @@
#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2012 Laboratoire de Recherche et Développement
# Copyright (C) 2012, 2015 Laboratoire de Recherche et Développement
# de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
@ -21,10 +21,10 @@
. ./defs
set -e
test "`../../bin/ltlfilt -p -f 'GFP_0.b_c'`" = "(G(F(P_0.b_c)))"
test "`../../bin/ltlfilt -p -f 'GFP_0.b_c'`" = "G(F(P_0.b_c))"
test "`../../bin/ltlfilt -f 'GFP_0.b_c'`" = "GFP_0.b_c"
foo=`../../bin/ltlfilt -p -f 'GF"P_0.b_c"'`
test "$foo" = "(G(F(P_0.b_c)))"
test "$foo" = "G(F(P_0.b_c))"
foo=`../../bin/ltlfilt -p -f '"a.b" U c.d.e'`
test "$foo" = "(a.b) U (c.d.e)"

View file

@ -23,7 +23,6 @@
#include <cstdlib>
#include <cstring>
#include "ltlparse/public.hh"
#include "ltlast/allnodes.hh"
#include "twaalgos/ltl2tgba_fm.hh"
#include "twaalgos/ltl2taa.hh"
#include "twaalgos/sccfilter.hh"
@ -67,8 +66,7 @@ main(int argc, char** argv)
if (spot::ltl::format_parse_errors(std::cerr, s, pe))
return 2;
auto fneg =
spot::ltl::unop::instance(spot::ltl::unop::Not, fpos->clone());
auto fneg = spot::ltl::formula::Not(fpos);
{
auto apos = scc_filter(ltl_to_tgba_fm(fpos, d));
@ -90,7 +88,7 @@ main(int argc, char** argv)
}
}
if (fpos->is_ltl_formula())
if (fpos.is_ltl_formula())
{
auto apos =
scc_filter(make_twa_graph(ltl_to_taa(fpos, d),
@ -104,17 +102,8 @@ main(int argc, char** argv)
exit(2);
}
}
fpos->destroy();
fneg->destroy();
}
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);
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::fnode::instances_check());
return 0;
}

View file

@ -24,7 +24,6 @@
#include <cstdlib>
#include <cstring>
#include "ltlparse/public.hh"
#include "ltlast/allnodes.hh"
#include "twaalgos/ltl2tgba_fm.hh"
#include "twaalgos/sccfilter.hh"
#include "twaalgos/degen.hh"
@ -219,17 +218,8 @@ main(int argc, char** argv)
}
}
f->destroy();
}
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);
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::fnode::instances_check());
return 0;
}

View file

@ -28,7 +28,6 @@
#include "ltlparse/public.hh"
#include "twaalgos/stats.hh"
#include "twaalgos/emptiness.hh"
#include "ltlast/unop.hh"
#include "twaalgos/stats.hh"
#include "twaalgos/emptiness_stats.hh"
#include "twaalgos/degen.hh"
@ -149,7 +148,7 @@ int main(int argc, char* argv[])
else if (print_formula)
{
spot::ltl::parse_error_list p1;
auto* f1 = spot::ltl::parse_infix_psl(file, p1);
auto f1 = spot::ltl::parse_infix_psl(file, p1);
if (spot::ltl::format_parse_errors(std::cerr, file, p1))
return 2;
@ -159,12 +158,11 @@ int main(int argc, char* argv[])
complement = spot::make_safra_complement(a);
spot::print_dot(std::cout, complement);
f1->destroy();
}
else if (stats)
{
spot::twa_graph_ptr a;
const spot::ltl::formula* f1 = 0;
spot::ltl::formula f1 = nullptr;
if (formula)
{
@ -211,29 +209,25 @@ int main(int argc, char* argv[])
if (formula)
{
auto nf1 = spot::ltl::unop::instance(spot::ltl::unop::Not, f1->clone());
auto a2 = spot::ltl_to_tgba_fm(nf1, dict);
spot::tgba_statistics a_size = spot::stats_reachable(a2);
auto a2 = spot::ltl_to_tgba_fm(spot::ltl::formula::Not(f1), dict);
spot::tgba_statistics a_size = spot::stats_reachable(a2);
std::cout << "Not Formula: "
<< a_size.states << ", "
<< a_size.transitions << ", "
<< a2->acc().num_sets()
<< std::endl;
f1->destroy();
nf1->destroy();
}
}
else
{
spot::ltl::parse_error_list p1;
auto* f1 = spot::ltl::parse_infix_psl(file, p1);
auto f1 = spot::ltl::parse_infix_psl(file, p1);
if (spot::ltl::format_parse_errors(std::cerr, file, p1))
return 2;
auto Af = spot::ltl_to_tgba_fm(f1, dict);
auto nf1 = spot::ltl::unop::instance(spot::ltl::unop::Not, f1->clone());
auto nf1 = spot::ltl::formula::Not(f1);
auto Anf = spot::ltl_to_tgba_fm(nf1, dict);
auto nAf = spot::make_safra_complement(Af);
auto nAnf = spot::make_safra_complement(Anf);
@ -261,8 +255,6 @@ int main(int argc, char* argv[])
{
std::cout << "OK\n";
}
nf1->destroy();
f1->destroy();
}
return return_value;

View file

@ -23,7 +23,6 @@
#include <cassert>
#include <cstdlib>
#include "ltlparse/public.hh"
#include "ltlast/allnodes.hh"
void
syntax(char *prog)
@ -60,11 +59,11 @@ main(int argc, char **argv)
ss >> expected;
spot::ltl::parse_error_list p1;
auto* f1 = spot::ltl::parse_infix_sere(form, p1);
auto f1 = spot::ltl::parse_infix_sere(form, p1);
if (spot::ltl::format_parse_errors(std::cerr, form, p1))
return 2;
bool b = f1->accepts_eword();
bool b = f1.accepts_eword();
std::cout << form << ',' << b << '\n';
if (b != expected)
{
@ -72,13 +71,8 @@ main(int argc, char **argv)
<< "' but expected '" << expected << "'\n";
return 2;
}
f1->destroy();
}
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::bunop::instance_count() == 0);
assert(spot::ltl::multop::instance_count() == 0);
assert(spot::ltl::fnode::instances_check());
return 0;
}

View file

@ -23,7 +23,6 @@
#include <cstdlib>
#include <cstring>
#include "ltlparse/public.hh"
#include "ltlast/allnodes.hh"
#include "twaalgos/ltl2tgba_fm.hh"
#include "twaalgos/ltl2taa.hh"
#include "twaalgos/sccfilter.hh"
@ -198,16 +197,8 @@ main(int argc, char** argv)
}
}
}
f->destroy();
}
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);
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::fnode::instances_check());
return 0;
}

View file

@ -28,9 +28,7 @@
#include <cstring>
#include "ltlparse/public.hh"
#include "ltlvisit/unabbrev.hh"
#include "ltlvisit/dump.hh"
#include "ltlvisit/nenoform.hh"
#include "ltlast/allnodes.hh"
#include "ltlvisit/simplify.hh"
#include "ltlvisit/print.hh"
@ -98,7 +96,7 @@ main(int argc, char** argv)
}
spot::ltl::parse_error_list p2;
auto* f2 = spot::ltl::parse_infix_psl(formulas[size - 1], p2);
auto f2 = spot::ltl::parse_infix_psl(formulas[size - 1], p2);
if (spot::ltl::format_parse_errors(std::cerr, formulas[size - 1], p2))
return 2;
@ -107,7 +105,7 @@ main(int argc, char** argv)
{
spot::ltl::parse_error_list p1;
auto* f1 = spot::ltl::parse_infix_psl(formulas[n], p1);
auto f1 = spot::ltl::parse_infix_psl(formulas[n], p1);
if (check_first &&
spot::ltl::format_parse_errors(std::cerr, formulas[n], p1))
@ -117,21 +115,17 @@ main(int argc, char** argv)
{
#if defined UNABBREV || defined NENOFORM
const spot::ltl::formula* tmp;
spot::ltl::formula tmp;
#endif
#ifdef UNABBREV
tmp = f1;
f1 = spot::ltl::unabbreviate(f1, UNABBREV);
tmp->destroy();
spot::ltl::dump(std::cout, f1);
std::cout << std::endl;
f1.dump(std::cout) << std::endl;
#endif
#ifdef NENOFORM
tmp = f1;
f1 = spot::ltl::negative_normal_form(f1);
tmp->destroy();
spot::ltl::dump(std::cout, f1);
std::cout << std::endl;
f1.dump(std::cout) << std::endl;
#endif
#ifdef REDUC
spot::ltl::ltl_simplifier_options opt(true, true, true,
@ -141,7 +135,7 @@ main(int argc, char** argv)
# endif
spot::ltl::ltl_simplifier simp(opt);
{
const spot::ltl::formula* tmp;
spot::ltl::formula tmp;
tmp = f1;
f1 = simp.simplify(f1);
@ -152,18 +146,15 @@ main(int argc, char** argv)
spot::ltl::print_psl(std::cerr << "Simplified: ", f1) << '\n';
exit_code = 1;
}
tmp->destroy();
}
spot::ltl::dump(std::cout, f1);
std::cout << std::endl;
f1.dump(std::cout) << std::endl;
#endif
#ifdef REDUC_TAU
spot::ltl::ltl_simplifier_options opt(false, false, false,
true, false);
spot::ltl::ltl_simplifier simp(opt);
{
const spot::ltl::formula* tmp;
spot::ltl::formula tmp;
tmp = f1;
f1 = simp.simplify(f1);
@ -174,18 +165,15 @@ main(int argc, char** argv)
spot::ltl::print_psl(std::cerr << "Simplified: ", f1) << '\n';
exit_code = 1;
}
tmp->destroy();
}
spot::ltl::dump(std::cout, f1);
std::cout << std::endl;
f1.dump(std::cout) << std::endl;
#endif
#ifdef REDUC_TAUSTR
spot::ltl::ltl_simplifier_options opt(false, false, false,
true, true);
spot::ltl::ltl_simplifier simp(opt);
{
const spot::ltl::formula* tmp;
spot::ltl::formula tmp;
tmp = f1;
f1 = simp.simplify(f1);
@ -196,11 +184,8 @@ main(int argc, char** argv)
spot::ltl::print_psl(std::cerr << "Simplified: ", f1) << '\n';
exit_code = 1;
}
tmp->destroy();
}
spot::ltl::dump(std::cout, f1);
std::cout << std::endl;
f1.dump(std::cout) << std::endl;
#endif
exit_code |= f1 != f2;
@ -225,25 +210,11 @@ main(int argc, char** argv)
exit_code ^= 1;
#endif
if (exit_code)
{
spot::ltl::dump(std::cerr, f1) << std::endl;
spot::ltl::dump(std::cerr, f2) << std::endl;
return exit_code;
}
return exit_code;
}
f1->destroy();
}
f2->destroy();
}
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);
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::fnode::instances_check());
return 0;
}

View file

@ -28,7 +28,7 @@
#include <cstdlib>
#include "ltlvisit/print.hh"
#include "ltlvisit/apcollect.hh"
#include "ltlast/allnodes.hh"
#include "ltlast/formula.hh"
#include "ltlparse/public.hh"
#include "twaalgos/ltl2tgba_fm.hh"
#include "twaalgos/ltl2taa.hh"
@ -923,7 +923,7 @@ checked_main(int argc, char** argv)
input = argv[formula_index];
}
const spot::ltl::formula* f = 0;
spot::ltl::formula f = nullptr;
if (!from_file) // Reading a formula, not reading an automaton from a file.
{
switch (translation)
@ -971,8 +971,7 @@ checked_main(int argc, char** argv)
if (simp)
{
tm.start("reducing formula");
const spot::ltl::formula* t = simp->simplify(f);
f->destroy();
spot::ltl::formula t = simp->simplify(f);
tm.stop("reducing formula");
f = t;
if (display_reduced_form)
@ -987,8 +986,8 @@ checked_main(int argc, char** argv)
simp->clear_as_bdd_cache();
}
if (f->is_psl_formula()
&& !f->is_ltl_formula()
if (f.is_psl_formula()
&& !f.is_ltl_formula()
&& (translation != TransFM && translation != TransCompo))
{
std::cerr << "Only the FM algorithm can translate PSL formulae;"
@ -1152,7 +1151,7 @@ checked_main(int argc, char** argv)
}
if (opt_determinize && a->acc().num_sets() <= 1
&& (!f || f->is_syntactic_recurrence()))
&& (!f || f.is_syntactic_recurrence()))
{
tm.start("determinization 2");
auto determinized = tba_determinize(ensure_digraph(a), 0,
@ -1642,8 +1641,6 @@ checked_main(int argc, char** argv)
}
while (search_many);
}
if (f)
f->destroy();
}
else
{
@ -1653,14 +1650,7 @@ checked_main(int argc, char** argv)
if (use_timer)
tm.print(std::cout);
if (unobservables)
{
for (spot::ltl::atomic_prop_set::iterator i =
unobservables->begin(); i != unobservables->end(); ++i)
(*i)->destroy();
delete unobservables;
}
delete unobservables;
return exit_code;
}
@ -1669,13 +1659,6 @@ int
main(int argc, char** argv)
{
int exit_code = checked_main(argc, argv);
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);
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::fnode::instances_check());
return exit_code;
}

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