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:
parent
314a016547
commit
d1f915c748
20 changed files with 427 additions and 594 deletions
243
src/ltlvisit/unabbrev.cc
Normal file
243
src/ltlvisit/unabbrev.cc
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue