Add support for ELTL (AST & parser), and an adaptation of LaCIM

for ELTL.  This is a new version of the work started in 2008 with
LTL and ELTL formulae now sharing the same class hierarchy.

* configure.ac: Adjust for src/eltlparse/ and src/eltltest/
directories, and call AX_BOOST_BASE.
* m4/boost.m4: New file defining AX_BOOST_BASE([MINIMUM-VERSION]).
* src/Makefile.am: Add eltlparse and eltltest.
* src/eltlparse/: New directory.  Contains the ELTL parser.
* src/eltltest/: New directory.  Contains tests related to
ELTL (parser and AST).
* src/ltlast/Makefile.am: Adjust for ELTL AST files.
* src/ltlast/automatop.cc, src/ltlast/automatop.hh: New files.
Represent automaton operators nodes used in ELTL ASTs.
* src/ltlast/nfa.cc, src/ltlast/nfa.hh: New files.  Represent
simple NFAs used internally by automatop nodes.
* src/ltlast/allnode.hh, src/ltlast/predecl.hh,
src/ltlast/visitor.hh: Adjust for automatop.
* src/ltlvisit/basicreduce.cc, src/ltlvisit/clone.cc,
src/ltlvisit/clone.hh, src/ltlvisit/contain.cc,
src/ltlvisit/dotty.cc, src/ltlvisit/nenoform.cc,
src/ltlvisit/postfix.cc, src/ltlvisit/postfix.hh,
src/ltlvisit/reduce.cc, src/ltlvisit/syntimpl.cc,
src/ltlvisit/tostring.cc: Because LTL and ELTL formulae share the
same class hierarchy, LTL visitors need to handle automatop nodes
to compile.  When it's meaningful the visitor applies on automatop
nodes or simply assert(0) otherwise.
* src/tgba/tgbabddconcretefactory.cc (create_anonymous_state),
src/tgba/tgbabddconcretefactory.hh (create_anonymous_state): New
function used by the LaCIM translation algorithm for ELTL.
* src/tgbaalgos/Makefile.am: Adjust for eltl2tgba_lacim* files.
* src/tgbaalgos/eltl2tgba_lacim.cc,
src/tgbaalgos/eltl2tgba_lacim.hh: New files.  Implementation of
the LaCIM translation algorithm for ELTL.
* src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/ltl2tgba_lacim.cc:
Handle automatop nodes in the translation by an assert(0).
* src/tgbatest/Makefile.am: Adjust for eltl2tgba.* files.
* src/src/tgbatest/eltl2tgba.cc, src/tgbatest/eltl2tgba.test: New
files
This commit is contained in:
Damien Lefortier 2009-03-02 17:31:12 +01:00
parent 90332d8d77
commit 2fbcd7e52f
46 changed files with 2509 additions and 3 deletions

View file

@ -31,6 +31,7 @@ tgbaalgos_HEADERS = \
dotty.hh \
dottydec.hh \
dupexp.hh \
eltl2tgba_lacim.hh \
emptiness.hh \
emptiness_stats.hh \
gv04.hh \
@ -61,6 +62,7 @@ libtgbaalgos_la_SOURCES = \
dotty.cc \
dottydec.cc \
dupexp.cc \
eltl2tgba_lacim.cc \
emptiness.cc \
gv04.cc \
lbtt.cc \

View file

@ -0,0 +1,261 @@
// Copyright (C) 2008 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 2 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 "ltlast/visitor.hh"
#include "ltlast/allnodes.hh"
#include "ltlvisit/lunabbrev.hh"
#include "ltlvisit/nenoform.hh"
#include "ltlvisit/destroy.hh"
#include "tgba/tgbabddconcretefactory.hh"
#include <cassert>
#include "eltl2tgba_lacim.hh"
namespace spot
{
namespace
{
using namespace ltl;
/// \brief Recursively translate a formula into a BDD.
class eltl_trad_visitor: public const_visitor
{
public:
eltl_trad_visitor(tgba_bdd_concrete_factory& fact, bool root = false)
: fact_(fact), root_(root)
{
}
virtual
~eltl_trad_visitor()
{
}
bdd
result()
{
return res_;
}
void
visit(const atomic_prop* node)
{
res_ = bdd_ithvar(fact_.create_atomic_prop(node));
}
void
visit(const constant* node)
{
switch (node->val())
{
case constant::True:
res_ = bddtrue;
return;
case constant::False:
res_ = bddfalse;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const unop* node)
{
switch (node->op())
{
case unop::Not:
{
res_ = bdd_not(recurse(node->child()));
return;
}
case unop::X:
case unop::F:
case unop::G:
assert(!"unsupported operator");
}
/* Unreachable code. */
assert(0);
}
void
visit(const binop* node)
{
bdd f1 = recurse(node->first());
bdd f2 = recurse(node->second());
switch (node->op())
{
case binop::Xor:
res_ = bdd_apply(f1, f2, bddop_xor);
return;
case binop::Implies:
res_ = bdd_apply(f1, f2, bddop_imp);
return;
case binop::Equiv:
res_ = bdd_apply(f1, f2, bddop_biimp);
return;
case binop::U:
case binop::R:
assert(!"unsupported operator");
}
/* Unreachable code. */
assert(0);
}
void
visit(const multop* node)
{
int op = -1;
bool root = false;
switch (node->op())
{
case multop::And:
op = bddop_and;
res_ = bddtrue;
// When the root formula is a conjunction it's ok to
// consider all children as root formulae. This allows the
// root-G trick to save many more variable. (See the
// translation of G.)
root = root_;
break;
case multop::Or:
op = bddop_or;
res_ = bddfalse;
break;
}
assert(op != -1);
unsigned s = node->size();
for (unsigned n = 0; n < s; ++n)
{
res_ = bdd_apply(res_, recurse(node->nth(n), root), op);
}
}
void
visit (const automatop* node)
{
nmap m;
bdd acc = bddtrue;
std::pair<int, int> vp =
recurse_state(node, node->nfa()->get_init_state(), m, acc);
bdd tmp = bddtrue;
for (nmap::iterator it = m.begin(); it != m.end(); ++it)
tmp &= bdd_apply(bdd_ithvar(it->second.first + 1),
bdd_ithvar(it->second.second + 1), bddop_biimp);
fact_.constrain_relation(bdd_apply(acc, tmp, bddop_imp));
if (!node->nfa()->is_loop())
fact_.declare_acceptance_condition(acc, node);
bdd init = bdd_ithvar(vp.first);
res_ = node->negated_ ? bdd_not(init) : init;
}
bdd
recurse(const formula* f, bool root = false)
{
eltl_trad_visitor v(fact_, root);
f->accept(v);
return v.result();
}
private:
bdd res_;
tgba_bdd_concrete_factory& fact_;
bool root_;
// Table containing the two now variables associated with each state.
// TODO: a little documentation about that.
typedef Sgi::hash_map<
const nfa::state*, std::pair<int, int>, ptr_hash<nfa::state> > nmap;
std::pair<int, int>&
recurse_state(const automatop* n, const nfa::state* s, nmap& m, bdd& acc)
{
const nfa::ptr nfa = n->nfa();
nmap::iterator it;
it = m.find(s);
int v1 = 0;
int v2 = 0;
if (it != m.end())
return it->second;
else
{
v1 = fact_.create_anonymous_state();
v2 = fact_.create_anonymous_state();
m[s] = std::make_pair(v1, v2);
}
bdd tmp1 = bddfalse;
bdd tmp2 = bddfalse;
bdd tmpacc = !bdd_ithvar(v2);
for (nfa::iterator i = nfa->begin(s); i != nfa->end(s); ++i)
{
bdd f = (*i)->label == -1 ? bddtrue : recurse(n->nth((*i)->label));
if (nfa->is_final((*i)->dst))
{
tmp1 |= f;
tmp2 |= f;
tmpacc |= f;
}
else
{
std::pair<int, int> vp = recurse_state(n, (*i)->dst, m, acc);
tmp1 |= (f & bdd_ithvar(vp.first + 1));
tmp2 |= (f & bdd_ithvar(vp.second + 1));
}
}
acc &= tmpacc;
fact_.constrain_relation(bdd_apply(bdd_ithvar(v1), tmp1, bddop_biimp));
fact_.constrain_relation(bdd_apply(bdd_ithvar(v2), tmp2, bddop_imp));
fact_.constrain_relation(
bdd_apply(bdd_ithvar(v2), bdd_ithvar(v1), bddop_imp));
return m[s];
}
};
} // anonymous
tgba_bdd_concrete*
eltl_to_tgba_lacim(const ltl::formula* f, bdd_dict* dict)
{
// Normalize the formula. We want all the negations on
// the atomic propositions. We also suppress logic
// abbreviations such as <=>, =>, or XOR, since they
// would involve negations at the BDD level.
const ltl::formula* f1 = ltl::unabbreviate_logic(f);
const ltl::formula* f2 = ltl::negative_normal_form(f1);
ltl::destroy(f1);
// Traverse the formula and draft the automaton in a factory.
tgba_bdd_concrete_factory fact(dict);
eltl_trad_visitor v(fact, true);
f2->accept(v);
ltl::destroy(f2);
fact.finish();
// Finally setup the resulting automaton.
return new tgba_bdd_concrete(fact, v.result());
}
}

View file

@ -0,0 +1,55 @@
// Copyright (C) 2008 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 2 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.
#ifndef SPOT_TGBAALGOS_ELTL2TGBA_LACIM_HH
# define SPOT_TGBAALGOS_ELTL2TGBA_LACIM_HH
#include "ltlast/formula.hh"
#include "tgba/tgbabddconcrete.hh"
namespace spot
{
/// \brief Build a spot::tgba_bdd_concrete from an ELTL formula.
/// \ingroup tgba_eltl
///
/// This is based on the following paper.
/// \verbatim
/// @InProceedings{ couvreur.00.lacim,
/// author = {Jean-Michel Couvreur},
/// title = {Un point de vue symbolique sur la logique temporelle
/// lin{\'e}aire},
/// booktitle = {Actes du Colloque LaCIM 2000},
/// month = {August},
/// year = {2000},
/// pages = {131--140},
/// volume = {27},
/// series = {Publications du LaCIM},
/// publisher = {Universit{\'e} du Qu{\'e}bec {\`a} Montr{\'e}al},
/// editor = {Pierre Leroux}
/// }
/// \endverbatim
/// \param f The formula to translate into an automaton.
/// \param dict The spot::bdd_dict the constructed automata should use.
/// \return A spot::tgba_bdd_concrete that recognizes the language of \a f.
tgba_bdd_concrete* eltl_to_tgba_lacim(const ltl::formula* f, bdd_dict* dict);
}
#endif // SPOT_TGBAALGOS_LTL2TGBA_LACIM_HH

View file

@ -401,6 +401,12 @@ namespace spot
assert(0);
}
void
visit(const automatop*)
{
assert(!"unsupported operator");
}
void
visit(const multop* node)
{
@ -500,6 +506,12 @@ namespace spot
assert(0);
}
void
visit(const automatop*)
{
assert(!"unsupported operator");
}
void
visit(const multop* node)
{

View file

@ -210,6 +210,12 @@ namespace spot
assert(0);
}
void
visit(const automatop*)
{
assert(!"unsupported operator");
}
void
visit(const multop* node)
{