Implement star-normal-form rewriting.
* src/ltlvisit/snf.cc, src/ltlvisit/snf.hh: New files. * src/ltlvisit/Makefile.am: Distribute them. * src/ltlvisit/simplify.cc, src/ltlvisit/simplify.hh: Call snf(f) for all f[*]. * src/ltltest/reduccmp.test: Test it. * doc/tl/tl.tex, doc/tl/tl.bib: Document it.
This commit is contained in:
parent
e7cf7b422d
commit
6eb830c8ae
8 changed files with 327 additions and 10 deletions
175
src/ltlvisit/snf.cc
Normal file
175
src/ltlvisit/snf.cc
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2012 Laboratoire de Recherche et Developpement
|
||||
// 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 Spot; see the file COPYING. If not, write to the Free
|
||||
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
|
||||
#include "snf.hh"
|
||||
#include "ltlast/allnodes.hh"
|
||||
#include "ltlast/visitor.hh"
|
||||
#include "ltlvisit/tostring.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace ltl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// E°
|
||||
class snf_visitor: public visitor
|
||||
{
|
||||
formula* result_;
|
||||
snf_cache* cache_;
|
||||
public:
|
||||
|
||||
snf_visitor(snf_cache* c): cache_(c)
|
||||
{
|
||||
}
|
||||
|
||||
formula*
|
||||
result() const
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
void
|
||||
visit(atomic_prop*)
|
||||
{
|
||||
assert(!"unexpected operator");
|
||||
}
|
||||
|
||||
void
|
||||
visit(constant* c)
|
||||
{
|
||||
assert(c == constant::empty_word_instance());
|
||||
result_ = constant::false_instance();
|
||||
}
|
||||
|
||||
void
|
||||
visit(bunop* bo)
|
||||
{
|
||||
bunop::type op = bo->op();
|
||||
switch (op)
|
||||
{
|
||||
case bunop::Star:
|
||||
assert(bo->accepts_eword());
|
||||
// Strip the star.
|
||||
result_ = recurse(bo->child());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visit(unop*)
|
||||
{
|
||||
assert(!"unexpected operator");
|
||||
}
|
||||
|
||||
void
|
||||
visit(binop*)
|
||||
{
|
||||
assert(!"unexpected operator");
|
||||
}
|
||||
|
||||
void
|
||||
visit(automatop*)
|
||||
{
|
||||
assert(!"unexpected operator");
|
||||
}
|
||||
|
||||
void
|
||||
visit(multop* mo)
|
||||
{
|
||||
multop::type op = mo->op();
|
||||
switch (op)
|
||||
{
|
||||
case multop::And:
|
||||
case multop::Or:
|
||||
case multop::Fusion:
|
||||
assert(!"unexpected operator");
|
||||
break;
|
||||
case multop::Concat:
|
||||
case multop::AndNLM:
|
||||
// Let F designate expressions that accept [*0],
|
||||
// and G designate expressions that do not.
|
||||
|
||||
// (G₁;G₂;G₃)° = G₁;G₂;G₃
|
||||
// (G₁;F₂;G₃)° = (G₁°);F₂;(G₃°) = G₁;F₂;G₃
|
||||
// because there is nothing to do recursively on a G.
|
||||
//
|
||||
// AndNLM can be dealt with similarly.
|
||||
//
|
||||
// This case is already handled in recurse().
|
||||
// if 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());
|
||||
{
|
||||
unsigned s = mo->size();
|
||||
multop::vec* v = new multop::vec;
|
||||
v->reserve(s);
|
||||
for (unsigned pos = 0; pos < s; ++pos)
|
||||
v->push_back(recurse(mo->nth(pos)));
|
||||
result_ = multop::instance(multop::OrRat, v);
|
||||
}
|
||||
break;
|
||||
case multop::AndRat:
|
||||
// FIXME: Can we deal with AndRat in a better way
|
||||
// when it accepts [*0].
|
||||
result_ = mo->clone();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
formula*
|
||||
recurse(formula* f)
|
||||
{
|
||||
if (!f->accepts_eword())
|
||||
return f->clone();
|
||||
|
||||
if (cache_)
|
||||
{
|
||||
snf_cache::const_iterator i = cache_->find(f);
|
||||
if (i != cache_->end())
|
||||
return i->second->clone();
|
||||
}
|
||||
|
||||
f->accept(*this);
|
||||
|
||||
if (cache_)
|
||||
(*cache_)[f->clone()] = result_->clone();
|
||||
return result_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
formula*
|
||||
star_normal_form(const formula* sere, snf_cache* cache)
|
||||
{
|
||||
snf_visitor v(cache);
|
||||
return v.recurse(const_cast<formula*>(sere));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue