merge tunnabrev/lunnabrev/wmunabbrev into a single function

* src/ltlvisit/lunabbrev.cc, src/ltlvisit/lunabbrev.hh,
src/ltlvisit/tunabbrev.cc, src/ltlvisit/tunabbrev.hh,
src/ltlvisit/wmunabbrev.cc, src/ltlvisit/wmunabbrev.hh: Delete.
* src/ltlvisit/unabbrev.cc, src/ltlvisit/unabbrev.hh: New files.
* src/ltlvisit/Makefile.am: Adjust.
* src/ltlvisit/print.cc, src/tests/equalsf.cc, src/tests/Makefile.am,
src/twaalgos/ltl2taa.cc, wrap/python/spot_impl.i, src/bin/ltlfilt.cc:
Adjust callers.
* src/ltlvisit/contain.cc, src/tests/syntimpl.cc: Remove useless
include.
* wrap/python/tests/formulas.ipynb: New test cases.
* doc/tl/tl.tex: Group all rules in a single section.
* NEWS: Mention it.
This commit is contained in:
Alexandre Duret-Lutz 2015-08-17 15:26:42 +02:00
parent 314a016547
commit d1f915c748
20 changed files with 427 additions and 594 deletions

5
NEWS
View file

@ -10,6 +10,11 @@ New in spot 1.99.2a (not yet released)
SCCs, but it now does remove Fin marks from transitions between SCCs, but it now does remove Fin marks from transitions between
SCCs. SCCs.
* All the unabbreviation functions (unabbreviate_ltl(),
unabbreviate_logic(), unabbreviate_wm()) have been merged into a
single unabbreviate() function that takes a string representing
the list of rewritting rules to enable.
* Bugs fixed * Bugs fixed
- Some acceptance conditions like Fin(0)|Fin(1)|Fin(2)&Inf(3) - Some acceptance conditions like Fin(0)|Fin(1)|Fin(2)&Inf(3)
were not detected as generalized-Rabin. were not detected as generalized-Rabin.

View file

@ -466,17 +466,6 @@ considered equal for the purpose of the above identities. For
instance \samp{(a\&c\&b\&!d)->(c\&!d\&b\&a)} will be rewritten to instance \samp{(a\&c\&b\&!d)->(c\&!d\&b\&a)} will be rewritten to
\samp{1} automatically. \samp{1} automatically.
\subsection{Unabbreviations}\label{sec:unabbbool}
The `\verb=unabbreviate_logic()=' function rewrites all Boolean
operators using only the \samp{!}, \samp{\&}, and \samp{|} operators
using the following rewritings:
\begin{align*}
f\IMPLIES g &\equiv (\NOT f)\OR g\\
f\EQUIV g &\equiv (f\AND g)\OR ((\NOT g)\AND(\NOT f))\\
f\XOR g &\equiv (f\AND\NOT g)\OR (g\AND\NOT f)\\
\end{align*}
\section{Temporal Operators}\label{sec:ltlops} \section{Temporal Operators}\label{sec:ltlops}
Given two temporal formulas $f$, and $g$, the following Given two temporal formulas $f$, and $g$, the following
@ -554,25 +543,6 @@ $\M$, and $\W$ if you are only familiar with $\X$ and $\U$.
f\R f&\equiv f f\R f&\equiv f
\end{align*} \end{align*}
\subsection{Unabbreviations}
The `\verb=unabbreviate_ltl()=' function applies all the rewritings from
section~\ref{sec:unabbbool} as well as the following two rewritings:
\begin{align*}
\F f&\equiv \1\U f\\
\G f&\equiv \0\R f
\end{align*}
The `\verb=unabbreviate_wm()=` function removes only the $\W$ and $\M$
operators using the following two rewritings:
\begin{align*}
f \W g&\equiv g \R (g \OR f)\\
f \M g&\equiv g \U (g \AND f)
\end{align*}
Among all the possible rewritings (see Appendix~\ref{sec:ltl-equiv})
those two were chosen because they are easier to translate in a
tableau construction~\cite[Fig.~11]{duret.11.vecos}.
\section{SERE Operators}\label{sec:sere} \section{SERE Operators}\label{sec:sere}
The ``SERE'' acronym will be translated to different word depending on The ``SERE'' acronym will be translated to different word depending on
@ -1349,6 +1319,30 @@ b))\OR(a\AND b))$ if `\verb|nenoform_stop_on_boolean|' is unset, while
it will produce $\G\F(\NOT(a \XOR b))$ if it will produce $\G\F(\NOT(a \XOR b))$ if
`\verb|nenoform_stop_on_boolean|' is set. `\verb|nenoform_stop_on_boolean|' is set.
\section{Unabbreviations}
The `\verb=unabbreviate()=' function can apply the following rewriting
rules when passed a string denoting the list of rules to apply. For
instance passing the string \texttt{"\^{}ei"} will rewrite all
occurrences of $\XOR$, $\EQUIV$ and $\IMPLIES$.
\[
\begin{array}{lrcl}
``\texttt{i}" & f\IMPLIES g &\equiv& (\NOT f)\OR g\\
``\texttt{e}" & f\EQUIV g &\equiv& (f\AND g)\OR ((\NOT g)\AND(\NOT f))\\
``\texttt{\^{}e}" & f\XOR g &\equiv& (f\AND\NOT g)\OR (g\AND\NOT f)\\
``\texttt{\^{}}"\text{~without~}``\texttt{e}" & f\XOR g &\equiv& \NOT(f\EQUIV g)\\
``\texttt{F}" & \F f&\equiv& \1\U f\\
``\texttt{G}" & \G f&\equiv& \0\R f \\
``\texttt{W}" & f \W g&\equiv& g \R (g \OR f)\\
``\texttt{M}" & f \M g&\equiv& g \U (g \AND f)
\end{array}
\]
Among all the possible rewritings (see Appendix~\ref{sec:ltl-equiv})
for $\W$ and $\M$, those two were chosen because they are easier to
translate in a tableau construction~\cite[Fig.~11]{duret.11.vecos}.
\section{Simplifications} \section{Simplifications}
The `\verb|ltl_simplifier::simplify|' method performs several kinds of The `\verb|ltl_simplifier::simplify|' method performs several kinds of

View file

@ -38,7 +38,7 @@
#include "ltlvisit/simplify.hh" #include "ltlvisit/simplify.hh"
#include "ltlvisit/length.hh" #include "ltlvisit/length.hh"
#include "ltlvisit/relabel.hh" #include "ltlvisit/relabel.hh"
#include "ltlvisit/wmunabbrev.hh" #include "ltlvisit/unabbrev.hh"
#include "ltlvisit/remove_x.hh" #include "ltlvisit/remove_x.hh"
#include "ltlvisit/apcollect.hh" #include "ltlvisit/apcollect.hh"
#include "ltlvisit/exclusive.hh" #include "ltlvisit/exclusive.hh"
@ -562,7 +562,7 @@ namespace
if (remove_wm) if (remove_wm)
{ {
const spot::ltl::formula* res = spot::ltl::unabbreviate_wm(f); const spot::ltl::formula* res = spot::ltl::unabbreviate(f, "WM");
f->destroy(); f->destroy();
f = res; f = res;
} }

View file

@ -33,7 +33,6 @@ ltlvisit_HEADERS = \
dump.hh \ dump.hh \
exclusive.hh \ exclusive.hh \
length.hh \ length.hh \
lunabbrev.hh \
mutation.hh \ mutation.hh \
nenoform.hh \ nenoform.hh \
print.hh \ print.hh \
@ -44,8 +43,7 @@ ltlvisit_HEADERS = \
simpfg.hh \ simpfg.hh \
simplify.hh \ simplify.hh \
snf.hh \ snf.hh \
tunabbrev.hh \ unabbrev.hh
wmunabbrev.hh
noinst_LTLIBRARIES = libltlvisit.la noinst_LTLIBRARIES = libltlvisit.la
libltlvisit_la_SOURCES = \ libltlvisit_la_SOURCES = \
@ -56,7 +54,6 @@ libltlvisit_la_SOURCES = \
dump.cc \ dump.cc \
exclusive.cc \ exclusive.cc \
length.cc \ length.cc \
lunabbrev.cc \
mark.cc \ mark.cc \
mark.hh \ mark.hh \
mutation.cc \ mutation.cc \
@ -69,5 +66,4 @@ libltlvisit_la_SOURCES = \
simpfg.cc \ simpfg.cc \
simplify.cc \ simplify.cc \
snf.cc \ snf.cc \
tunabbrev.cc \ unabbrev.cc
wmunabbrev.cc

View file

@ -22,7 +22,6 @@
#include "contain.hh" #include "contain.hh"
#include "simplify.hh" #include "simplify.hh"
#include "tunabbrev.hh"
#include "ltlast/unop.hh" #include "ltlast/unop.hh"
#include "ltlast/binop.hh" #include "ltlast/binop.hh"
#include "ltlast/multop.hh" #include "ltlast/multop.hh"

View file

@ -1,149 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 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), 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 "lunabbrev.hh"
#include <cassert>
namespace spot
{
namespace ltl
{
unabbreviate_logic_visitor::unabbreviate_logic_visitor(const char* opt)
{
while (*opt)
switch (char c = *opt++)
{
case '^':
rewrite_xor = true;
break;
case 'i':
rewrite_i = true;
break;
case 'e':
rewrite_e = true;
break;
default:
throw std::runtime_error
(std::string("unknown option for unabbreviate_logic_visitor(): ")
+ c);
}
}
unabbreviate_logic_visitor::~unabbreviate_logic_visitor()
{
}
void
unabbreviate_logic_visitor::visit(const binop* bo)
{
const formula* f1 = recurse(bo->first());
const formula* f2 = recurse(bo->second());
binop::type op = bo->op();
switch (op)
{
/* f1 ^ f2 == !(f1 <-> f2) */
/* f1 ^ f2 == (f1 & !f2) | (f2 & !f1) */
case binop::Xor:
{
if (!rewrite_xor)
goto no_rewrite;
if (!rewrite_e)
{
result_ = unop::instance(unop::Not,
binop::instance(binop::Equiv, f1, f2));
return;
}
else
{
const formula* a =
multop::instance(multop::And, f1->clone(),
unop::instance(unop::Not, f2->clone()));
const formula* b =
multop::instance(multop::And, f2,
unop::instance(unop::Not, f1));
result_ = multop::instance(multop::Or, a, b);
return;
}
}
/* f1 => f2 == !f1 | f2 */
case binop::Implies:
if (!rewrite_i)
goto no_rewrite;
result_ = multop::instance(multop::Or,
unop::instance(unop::Not, f1), f2);
return;
/* f1 <=> f2 == (f1 & f2) | (!f1 & !f2) */
case binop::Equiv:
if (!rewrite_e)
goto no_rewrite;
{
const formula* f1c = f1->clone();
const formula* f2c = f2->clone();
result_ =
multop::instance(multop::Or,
multop::instance(multop::And, f1c, f2c),
multop::instance(multop::And,
unop::instance(unop::Not, f1),
unop::instance(unop::Not, f2)));
return;
}
/* f1 U f2 == f1 U f2 */
/* f1 R f2 == f1 R f2 */
/* f1 W f2 == f1 W f2 */
/* f1 M f2 == f1 M f2 */
/* f1 UConcat f2 == f1 UConcat f2 */
/* f1 EConcat f2 == f1 EConcat f2 */
case binop::U:
case binop::R:
case binop::W:
case binop::M:
case binop::UConcat:
case binop::EConcat:
case binop::EConcatMarked:
no_rewrite:
result_ = binop::instance(op, f1, f2);
return;
}
SPOT_UNREACHABLE();
}
const formula*
unabbreviate_logic_visitor::recurse(const formula* f)
{
f->accept(*this);
return result_;
}
const formula*
unabbreviate_logic(const formula* f, const char* xie)
{
if (f->is_sugar_free_boolean())
return f->clone();
unabbreviate_logic_visitor v(xie);
f->accept(v);
return v.result();
}
}
}

View file

@ -1,75 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 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.
//
// 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 "clone.hh"
namespace spot
{
namespace ltl
{
/// \ingroup ltl_visitor
/// \brief Clone and rewrite a formula to remove most of the
/// abbreviated logical operators.
///
/// This will rewrite binary operators such as binop::Implies,
/// binop::Equals, and binop::Xor, using only unop::Not, multop::Or,
/// and multop::And.
///
/// This visitor is public, because it's convenient
/// to derive from it and override some of its methods.
/// But if you just want the functionality, consider using
/// spot::ltl::unabbreviate_logic instead.
class SPOT_API unabbreviate_logic_visitor : public clone_visitor
{
typedef clone_visitor super;
public:
unabbreviate_logic_visitor(const char* opt = "^ie");
virtual ~unabbreviate_logic_visitor();
using super::visit;
void visit(const binop* bo);
virtual const formula* recurse(const formula* f);
private:
bool rewrite_xor = false;
bool rewrite_i = false;
bool rewrite_e = false;
};
/// \ingroup ltl_rewriting
/// \brief Clone and rewrite a formula to remove most of the abbreviated
/// logical operators.
///
/// This will rewrite binary operators such as binop::Implies,
/// binop::Equals, and binop::Xor, using only unop::Not, multop::Or,
/// and multop::And.
///
/// The optional \a opt argument can be a string containing any
/// subset of the string "^ie" to denote the operators (xor,
/// implication, equivalence) to actually remove.
SPOT_API const formula* unabbreviate_logic(const formula* f,
const char* opt = "^ie");
}
}

View file

@ -27,8 +27,7 @@
#include <cstring> #include <cstring>
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
#include "ltlast/visitor.hh" #include "ltlast/visitor.hh"
#include "lunabbrev.hh" #include "unabbrev.hh"
#include "wmunabbrev.hh"
#include "print.hh" #include "print.hh"
#include "misc/escape.hh" #include "misc/escape.hh"
@ -985,11 +984,7 @@ namespace spot
std::ostream& std::ostream&
print_spin_ltl(std::ostream& os, const formula* f, bool full_parent) print_spin_ltl(std::ostream& os, const formula* f, bool full_parent)
{ {
// Rewrite xor. f = unabbreviate(f, "^MW");
const formula* fu = unabbreviate_logic(f, "^");
// Also remove W and M.
f = unabbreviate_wm(fu);
fu->destroy();
to_string_visitor v(os, full_parent, false, spin_kw); to_string_visitor v(os, full_parent, false, spin_kw);
f->accept(v); f->accept(v);
f->destroy(); f->destroy();
@ -1007,8 +1002,7 @@ namespace spot
std::ostream& std::ostream&
print_wring_ltl(std::ostream& os, const formula* f) print_wring_ltl(std::ostream& os, const formula* f)
{ {
// Remove W and M. f = unabbreviate(f, "MW");
f = unabbreviate_wm(f);
to_string_visitor v(os, true, false, wring_kw); to_string_visitor v(os, true, false, wring_kw);
f->accept(v); f->accept(v);
f->destroy(); f->destroy();

View file

@ -1,80 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 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 "ltlast/allnodes.hh"
#include "tunabbrev.hh"
namespace spot
{
namespace ltl
{
unabbreviate_ltl_visitor::unabbreviate_ltl_visitor()
{
}
unabbreviate_ltl_visitor::~unabbreviate_ltl_visitor()
{
}
void
unabbreviate_ltl_visitor::visit(const unop* uo)
{
switch (uo->op())
{
case unop::X:
case unop::Not:
case unop::Closure:
case unop::NegClosure:
case unop::NegClosureMarked:
this->super::visit(uo);
return;
case unop::F:
result_ = binop::instance(binop::U,
constant::true_instance(),
recurse(uo->child()));
return;
case unop::G:
result_ = binop::instance(binop::R,
constant::false_instance(),
recurse(uo->child()));
return;
}
}
const formula*
unabbreviate_ltl_visitor::recurse(const formula* f)
{
return unabbreviate_ltl(f);
}
const formula*
unabbreviate_ltl(const formula* f)
{
if (f->is_sugar_free_boolean() && f->is_sugar_free_ltl())
return f->clone();
unabbreviate_ltl_visitor v;
f->accept(v);
return v.result();
}
}
}

View file

@ -1,69 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 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 "ltlvisit/lunabbrev.hh"
namespace spot
{
namespace ltl
{
/// \ingroup ltl_visitor
/// \brief Clone and rewrite a formula to remove most of the
/// abbreviated LTL and logical operators.
///
/// The rewriting performed on logical operator is
/// the same as the one done by spot::ltl::unabbreviate_logic_visitor.
///
/// This will also rewrite unary operators such as unop::F,
/// and unop::G, using only binop::U, and binop::R.
///
/// This visitor is public, because it's convenient
/// to derive from it and override some of its methods.
/// But if you just want the functionality, consider using
/// spot::ltl::unabbreviate_ltl instead.
class SPOT_API unabbreviate_ltl_visitor : public unabbreviate_logic_visitor
{
typedef unabbreviate_logic_visitor super;
public:
unabbreviate_ltl_visitor();
virtual ~unabbreviate_ltl_visitor();
using super::visit;
void visit(const unop* uo);
const formula* recurse(const formula* f);
};
/// \brief Clone and rewrite a formula to remove most of the
/// abbreviated LTL and logical operators.
///
/// The rewriting performed on logical operator is
/// the same as the one done by spot::ltl::unabbreviate_logic.
///
/// This will also rewrite unary operators such as unop::F,
/// and unop::G, using only binop::U, and binop::R.
SPOT_API const formula* unabbreviate_ltl(const formula* f);
}
}

243
src/ltlvisit/unabbrev.cc Normal file
View file

@ -0,0 +1,243 @@
// -*- coding: utf-8 -*-
// Copyright (C) 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 "unabbrev.hh"
#include "ltlast/allnodes.hh"
#include <cassert>
namespace spot
{
namespace ltl
{
unabbreviator::unabbreviator(const char* opt)
{
while (*opt)
switch (char c = *opt++)
{
case 'e':
re_e_ = true;
re_some_bool_ = true;
break;
case 'F':
re_f_ = true;
re_some_f_g_ = true;
break;
case 'G':
re_g_ = true;
re_some_f_g_ = true;
break;
case 'i':
re_i_ = true;
re_some_bool_ = true;
break;
case 'M':
re_m_ = true;
re_some_other_ = true;
break;
case 'W':
re_w_ = true;
re_some_other_ = true;
break;
case '^':
re_xor_ = true;
re_some_bool_ = true;
break;
default:
throw std::runtime_error
(std::string("unknown unabbreviation option: ")
+ c);
}
}
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)
{
auto entry = cache_.emplace(in, nullptr);
if (!entry.second)
return entry.first->second->clone();
in->clone();
// Skip recursion whenever possible
bool no_boolean_rewrite = !re_some_bool_ || in->is_sugar_free_boolean();
bool no_f_g_rewrite = !re_some_f_g_ || in->is_sugar_free_ltl();
if (no_boolean_rewrite
&& (in->is_boolean() || (no_f_g_rewrite && !re_some_other_)))
{
entry.first->second = in->clone();
return in->clone();
}
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 f1 = true U f1
case unop::F:
if (!re_f_)
goto unop_clone;
out = binop::instance(binop::U, constant::true_instance(), c);
break;
// G f1 = false R f1
case unop::G:
if (!re_g_)
goto unop_clone;
out = binop::instance(binop::R, constant::false_instance(), c);
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)
case binop::W:
if (!re_w_)
goto binop_clone;
out = binop::instance(binop::R, f2,
multop::instance(multop::Or,
f2->clone(), f1));
break;
// f1 M f2 = f2 U (g2 & f1)
case binop::M:
if (!re_m_)
goto binop_clone;
out = binop::instance(binop::U, f2,
multop::instance(multop::And,
f2->clone(), f1));
break;
case binop::U:
case binop::R:
case binop::UConcat:
case binop::EConcat:
case binop::EConcatMarked:
binop_clone:
out = binop::instance(op, f1, f2);
break;
}
break;
}
case formula::MultOp:
{
const multop* mo = static_cast<const multop*>(in);
multop::vec* res = new multop::vec;
unsigned mos = mo->size();
res->reserve(mos);
for (unsigned i = 0; i < mos; ++i)
res->push_back(run(mo->nth(i)));
out = multop::instance(mo->op(), res);
break;
}
case formula::BUnOp:
{
const bunop* bo = static_cast<const bunop*>(in);
out = bunop::instance(bo->op(), run(bo->child()),
bo->min(), bo->max());
break;
}
}
assert(out != nullptr);
entry.first->second = out;
return out->clone();
}
const formula* unabbreviate(const formula* in, const char* opt)
{
unabbreviator un(opt);
return un.run(in);
}
}
}

72
src/ltlvisit/unabbrev.hh Normal file
View file

@ -0,0 +1,72 @@
// -*- coding: utf-8 -*-
// Copyright (C) 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/>.
#pragma once
#include "ltlast/formula.hh"
#include <unordered_map>
namespace spot
{
namespace ltl
{
constexpr const char* default_unabbrev_string = "eFGiMW^";
/// \ingroup ltl_rewriting
/// \brief Clone and rewrite a formula to remove specified operators
/// logical operators.
class SPOT_API unabbreviator final
{
private:
// What to rewrite?
bool re_e_ = false;
bool re_f_ = false;
bool re_g_ = false;
bool re_i_ = false;
bool re_m_ = false;
bool re_w_ = false;
bool re_xor_ = false;
bool re_some_bool_ = false; // rewrite xor, i, or e
bool re_some_f_g_ = false; // rewrite F or G
bool re_some_other_ = false; // rewrite W or M
// Cache of rewritten subformulas
std::unordered_map<const formula*, const formula*> cache_;
public:
/// \brief Constructor
///
/// The set of operators to remove should be passed as a string
/// 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();
};
/// \ingroup ltl_rewriting
/// \brief Clone and rewrite a formula to remove specified operators
/// logical operators.
///
/// 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);
}
}

View file

@ -1,96 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012 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 "ltlast/allnodes.hh"
#include "clone.hh"
#include "wmunabbrev.hh"
#include <cassert>
namespace spot
{
namespace ltl
{
namespace
{
class unabbreviate_wm_visitor : public clone_visitor
{
typedef clone_visitor super;
public:
unabbreviate_wm_visitor()
{
}
virtual
~unabbreviate_wm_visitor()
{
}
using super::visit;
void 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::U:
case binop::R:
case binop::UConcat:
case binop::EConcat:
case binop::EConcatMarked:
result_ = binop::instance(op, f1, f2);
break;
case binop::W:
// f1 W f2 = f2 R (f2 | f1)
result_ =
binop::instance(binop::R, f2,
multop::instance(multop::Or,
f2->clone(), f1));
break;
case binop::M:
// f1 M f2 = f2 U (g2 & f1)
result_ =
binop::instance(binop::U, f2,
multop::instance(multop::And,
f2->clone(), f1));
break;
}
}
virtual const formula* recurse(const formula* f)
{
if (f->is_boolean())
return f->clone();
f->accept(*this);
return this->result();
}
};
}
const formula*
unabbreviate_wm(const formula* f)
{
unabbreviate_wm_visitor v;
return v.recurse(f);
}
}
}

View file

@ -1,41 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013 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/>.
#pragma once
#include "misc/common.hh"
namespace spot
{
namespace ltl
{
class formula;
/// \ingroup ltl_rewriting
/// \brief Rewrite a formula to remove the W and M operators.
///
/// This is necessary if you want to use the formula with a tool
/// that do not support these operators.
///
/// <code>a W b</code> is replaced by <code>b R (b | a)</code>,
/// and <code>a M b</code> is replaced by <code>b U (b & a)</code>.
///
SPOT_API const formula* unabbreviate_wm(const formula* f);
}
}

View file

@ -92,7 +92,7 @@ ltl2dot_CPPFLAGS = $(AM_CPPFLAGS) -DDOTTY
ltl2text_SOURCES = readltl.cc ltl2text_SOURCES = readltl.cc
ltlrel_SOURCES = ltlrel.cc ltlrel_SOURCES = ltlrel.cc
lunabbrev_SOURCES = equalsf.cc lunabbrev_SOURCES = equalsf.cc
lunabbrev_CPPFLAGS = $(AM_CPPFLAGS) -DLUNABBREV lunabbrev_CPPFLAGS = $(AM_CPPFLAGS) -DUNABBREV='"^ie"'
nenoform_SOURCES = equalsf.cc nenoform_SOURCES = equalsf.cc
nenoform_CPPFLAGS = $(AM_CPPFLAGS) -DNENOFORM nenoform_CPPFLAGS = $(AM_CPPFLAGS) -DNENOFORM
nequals_SOURCES = equalsf.cc nequals_SOURCES = equalsf.cc
@ -107,9 +107,9 @@ reductaustr_CPPFLAGS = $(AM_CPPFLAGS) -DREDUC_TAUSTR
syntimpl_SOURCES = syntimpl.cc syntimpl_SOURCES = syntimpl.cc
tostring_SOURCES = tostring.cc tostring_SOURCES = tostring.cc
tunabbrev_SOURCES = equalsf.cc tunabbrev_SOURCES = equalsf.cc
tunabbrev_CPPFLAGS = $(AM_CPPFLAGS) -DTUNABBREV tunabbrev_CPPFLAGS = $(AM_CPPFLAGS) -DUNABBREV='"^ieFG"'
tunenoform_SOURCES = equalsf.cc tunenoform_SOURCES = equalsf.cc
tunenoform_CPPFLAGS = $(AM_CPPFLAGS) -DNENOFORM -DTUNABBREV tunenoform_CPPFLAGS = $(AM_CPPFLAGS) -DNENOFORM -DUNABBREV='"^ieFG"'
# Keep this sorted by STRENGTH. Test basic things first, # Keep this sorted by STRENGTH. Test basic things first,

View file

@ -27,10 +27,8 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include "ltlparse/public.hh" #include "ltlparse/public.hh"
#include "ltlvisit/lunabbrev.hh" #include "ltlvisit/unabbrev.hh"
#include "ltlvisit/tunabbrev.hh"
#include "ltlvisit/dump.hh" #include "ltlvisit/dump.hh"
#include "ltlvisit/wmunabbrev.hh"
#include "ltlvisit/nenoform.hh" #include "ltlvisit/nenoform.hh"
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
#include "ltlvisit/simplify.hh" #include "ltlvisit/simplify.hh"
@ -118,26 +116,12 @@ main(int argc, char** argv)
int exit_code = 0; int exit_code = 0;
{ {
#if defined LUNABBREV || defined TUNABBREV || defined NENOFORM || defined WM #if defined UNABBREV || defined NENOFORM
const spot::ltl::formula* tmp; const spot::ltl::formula* tmp;
#endif #endif
#ifdef LUNABBREV #ifdef UNABBREV
tmp = f1; tmp = f1;
f1 = spot::ltl::unabbreviate_logic(f1); f1 = spot::ltl::unabbreviate(f1, UNABBREV);
tmp->destroy();
spot::ltl::dump(std::cout, f1);
std::cout << std::endl;
#endif
#ifdef TUNABBREV
tmp = f1;
f1 = spot::ltl::unabbreviate_ltl(f1);
tmp->destroy();
spot::ltl::dump(std::cout, f1);
std::cout << std::endl;
#endif
#ifdef WM
tmp = f1;
f1 = spot::ltl::unabbreviate_wm(f1);
tmp->destroy(); tmp->destroy();
spot::ltl::dump(std::cout, f1); spot::ltl::dump(std::cout, f1);
std::cout << std::endl; std::cout << std::endl;

View file

@ -24,8 +24,6 @@
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include "ltlparse/public.hh" #include "ltlparse/public.hh"
#include "ltlvisit/lunabbrev.hh"
#include "ltlvisit/tunabbrev.hh"
#include "ltlvisit/dump.hh" #include "ltlvisit/dump.hh"
#include "ltlvisit/print.hh" #include "ltlvisit/print.hh"
#include "ltlvisit/simplify.hh" #include "ltlvisit/simplify.hh"

View file

@ -21,8 +21,7 @@
#include <algorithm> #include <algorithm>
#include "ltlast/visitor.hh" #include "ltlast/visitor.hh"
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
#include "ltlvisit/lunabbrev.hh" #include "ltlvisit/unabbrev.hh"
#include "ltlvisit/tunabbrev.hh"
#include "ltlvisit/nenoform.hh" #include "ltlvisit/nenoform.hh"
#include "ltlvisit/contain.hh" #include "ltlvisit/contain.hh"
#include "ltl2taa.hh" #include "ltl2taa.hh"
@ -408,9 +407,9 @@ namespace spot
ltl_to_taa(const ltl::formula* f, ltl_to_taa(const ltl::formula* f,
const bdd_dict_ptr& dict, bool refined_rules) const bdd_dict_ptr& dict, bool refined_rules)
{ {
// TODO: s/unabbreviate_ltl/unabbreviate_logic/ // TODO: implement translation of F and G
const ltl::formula* f1 = ltl::unabbreviate_ltl(f); auto f1 = ltl::unabbreviate(f, "^ieFG");
const ltl::formula* f2 = ltl::negative_normal_form(f1); auto f2 = ltl::negative_normal_form(f1);
f1->destroy(); f1->destroy();
auto res = make_taa_tgba_formula(dict); auto res = make_taa_tgba_formula(dict);

View file

@ -100,11 +100,10 @@ namespace std {
#include "ltlvisit/apcollect.hh" #include "ltlvisit/apcollect.hh"
#include "ltlvisit/dot.hh" #include "ltlvisit/dot.hh"
#include "ltlvisit/dump.hh" #include "ltlvisit/dump.hh"
#include "ltlvisit/lunabbrev.hh"
#include "ltlvisit/nenoform.hh" #include "ltlvisit/nenoform.hh"
#include "ltlvisit/print.hh" #include "ltlvisit/print.hh"
#include "ltlvisit/simplify.hh" #include "ltlvisit/simplify.hh"
#include "ltlvisit/tunabbrev.hh" #include "ltlvisit/unabbrev.hh"
#include "ltlvisit/randomltl.hh" #include "ltlvisit/randomltl.hh"
#include "ltlvisit/length.hh" #include "ltlvisit/length.hh"
#include "ltlvisit/remove_x.hh" #include "ltlvisit/remove_x.hh"
@ -265,11 +264,10 @@ namespace std {
%include "ltlvisit/apcollect.hh" %include "ltlvisit/apcollect.hh"
%include "ltlvisit/dot.hh" %include "ltlvisit/dot.hh"
%include "ltlvisit/dump.hh" %include "ltlvisit/dump.hh"
%include "ltlvisit/lunabbrev.hh"
%include "ltlvisit/nenoform.hh" %include "ltlvisit/nenoform.hh"
%include "ltlvisit/print.hh" %include "ltlvisit/print.hh"
%include "ltlvisit/simplify.hh" %include "ltlvisit/simplify.hh"
%include "ltlvisit/tunabbrev.hh" %include "ltlvisit/unabbrev.hh"
%include "ltlvisit/randomltl.hh" %include "ltlvisit/randomltl.hh"
%include "ltlvisit/length.hh" %include "ltlvisit/length.hh"
%include "ltlvisit/remove_x.hh" %include "ltlvisit/remove_x.hh"

View file

@ -1,7 +1,7 @@
{ {
"metadata": { "metadata": {
"name": "", "name": "",
"signature": "sha256:d2086d4faaecc1d0e5a0e29b958657ed86b034326b89a5513d3df6f35301a3e7" "signature": "sha256:08d5f61ba93d2879f4f77ca0c4434c1a60ffcb195505e6065dd5a1c79e07c26a"
}, },
"nbformat": 3, "nbformat": 3,
"nbformat_minor": 0, "nbformat_minor": 0,
@ -493,7 +493,7 @@
"</svg>" "</svg>"
], ],
"text": [ "text": [
"<IPython.core.display.SVG at 0x7fb744184c88>" "<IPython.core.display.SVG at 0x7f9852c56588>"
] ]
} }
], ],
@ -522,6 +522,13 @@
], ],
"prompt_number": 16 "prompt_number": 16
}, },
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Etessami's rule for removing X (valid only in stutter-invariant formulas)"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"collapsed": false, "collapsed": false,
@ -544,6 +551,60 @@
} }
], ],
"prompt_number": 17 "prompt_number": 17
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Removing abbreviated operators"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.formula(\"G(a xor b) -> F(a <-> b)\")\n",
"spot.unabbreviate(f, \"GF^\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$(\\bot \\mathbin{\\mathsf{R}} \\lnot (a \\leftrightarrow b)) \\rightarrow (\\top \\mathbin{\\mathsf{U}} (a \\leftrightarrow b))$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 18,
"text": [
"(0 R !(a <-> b)) -> (1 U (a <-> b))"
]
}
],
"prompt_number": 18
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.unabbreviate(f, \"GF^ei\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$(\\top \\mathbin{\\mathsf{U}} ((a \\land b) \\lor (\\lnot a \\land \\lnot b))) \\lor \\lnot (\\bot \\mathbin{\\mathsf{R}} ((\\lnot a \\land b) \\lor (a \\land \\lnot b)))$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 19,
"text": [
"(1 U ((a & b) | (!a & !b))) | !(0 R ((!a & b) | (a & !b)))"
]
}
],
"prompt_number": 19
} }
], ],
"metadata": {} "metadata": {}