Commit c0393414 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

Initial code for TGBA (Transition Generalized Bchi Automata).

Contains tgba_bdd, a BDD-encoded TGBA, and ltl_to_tgba,
a LTL-to-TGBA translator using Couvreur's algorithm.

* src/Makefile.am (SUBDIRS): Add tgba.
(libspot_la_LIBADD): Add tgba/libtgba.la.
* src/tgba/Makefile.am, src/tgba/bddfactory.cc,
src/tgba/bddfactory.hh, src/tgba/dictunion.cc,
src/tgba/dictunion.hh, src/tgba/ltl2tgba.cc, src/tgba/ltl2tgba.hh,
src/tgba/state.hh, src/tgba/statebdd.cc, src/tgba/statebdd.hh,
src/tgba/succiter.hh, src/tgba/succiterconcrete.cc,
src/tgba/succiterconcrete.hh, src/tgba/succlist.hh,
src/tgba/tgba.hh, src/tgba/tgbabddconcrete.cc,
src/tgba/tgbabddconcrete.hh, src/tgba/tgbabddconcretefactory.cc,
src/tgba/tgbabddconcretefactory.hh,
src/tgba/tgbabddconcreteproduct.cc,
src/tgba/tgbabddconcreteproduct.hh, src/tgba/tgbabddcoredata.cc,
src/tgba/tgbabddcoredata.hh, src/tgba/tgbabdddict.cc,
src/tgba/tgbabdddict.hh, src/tgba/tgbabddfactory.hh,
src/tgba/tgbabddtranslatefactory.cc,
src/tgba/tgbabddtranslatefactory.hh: New files.
parent 5100c197
2003-05-26 Alexandre Duret-Lutz <aduret@src.lip6.fr>
Initial code for TGBA (Transition Generalized Bchi Automata).
Contains tgba_bdd, a BDD-encoded TGBA, and ltl_to_tgba,
a LTL-to-TGBA translator using Couvreur's algorithm.
* src/Makefile.am (SUBDIRS): Add tgba.
(libspot_la_LIBADD): Add tgba/libtgba.la.
* src/tgba/Makefile.am, src/tgba/bddfactory.cc,
src/tgba/bddfactory.hh, src/tgba/dictunion.cc,
src/tgba/dictunion.hh, src/tgba/ltl2tgba.cc, src/tgba/ltl2tgba.hh,
src/tgba/state.hh, src/tgba/statebdd.cc, src/tgba/statebdd.hh,
src/tgba/succiter.hh, src/tgba/succiterconcrete.cc,
src/tgba/succiterconcrete.hh, src/tgba/succlist.hh,
src/tgba/tgba.hh, src/tgba/tgbabddconcrete.cc,
src/tgba/tgbabddconcrete.hh, src/tgba/tgbabddconcretefactory.cc,
src/tgba/tgbabddconcretefactory.hh,
src/tgba/tgbabddconcreteproduct.cc,
src/tgba/tgbabddconcreteproduct.hh, src/tgba/tgbabddcoredata.cc,
src/tgba/tgbabddcoredata.hh, src/tgba/tgbabdddict.cc,
src/tgba/tgbabdddict.hh, src/tgba/tgbabddfactory.hh,
src/tgba/tgbabddtranslatefactory.cc,
src/tgba/tgbabddtranslatefactory.hh: New files.
2003-05-23 Alexandre Duret-Lutz <aduret@src.lip6.fr>
* m4/gccwarn.m4: Do not use -Winline, this is inappropriate
......
......@@ -31,6 +31,7 @@ AC_CONFIG_FILES([
src/ltltest/Makefile
src/ltltest/defs
src/ltlvisit/Makefile
src/tgba/Makefile
src/misc/Makefile
wrap/Makefile
])
......
AUTOMAKE_OPTIONS = subdir-objects
# List directories in the order they must be built.
SUBDIRS = misc ltlenv ltlast ltlvisit ltlparse ltltest
SUBDIRS = misc ltlenv ltlast ltlvisit ltlparse ltltest tgba
lib_LTLIBRARIES = libspot.la
libspot_la_SOURCES =
......@@ -9,4 +9,5 @@ libspot_la_LIBADD = \
ltlenv/libltlenv.la \
ltlparse/libltlparse.la \
ltlvisit/libltlvisit.la \
ltlast/libltlast.la
ltlast/libltlast.la \
tgba/libtgba.la
.deps
.libs
*.lo
*.la
Makefile
Makefile.in
AM_CPPFLAGS = -I$(srcdir)/..
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
noinst_LTLIBRARIES = libtgba.la
libtgba_la_SOURCES = \
bddfactory.cc \
bddfactory.hh \
dictunion.cc \
dictunion.hh \
ltl2tgba.cc \
ltl2tgba.hh \
state.hh \
statebdd.cc \
statebdd.hh \
succiter.hh \
succiterconcrete.cc \
succiterconcrete.hh \
tgba.hh \
tgbabddconcrete.cc \
tgbabddconcrete.hh \
tgbabddconcretefactory.cc \
tgbabddconcretefactory.hh \
tgbabddconcreteproduct.cc \
tgbabddconcreteproduct.hh \
tgbabddcoredata.cc \
tgbabddcoredata.hh \
tgbabdddict.cc \
tgbabdddict.hh \
tgbabddfactory.hh \
tgbabddtranslatefactory.cc \
tgbabddtranslatefactory.hh
#include "bddfactory.hh"
namespace spot
{
bdd_factory::bdd_factory()
: varused(0)
{
initialize();
}
int
bdd_factory::create_node()
{
return create_nodes(1);
}
int
bdd_factory::create_pair()
{
return create_nodes(2);
}
int
bdd_factory::create_nodes(int i)
{
int res = varused;
varused += i;
if (varnum < varused)
{
bdd_extvarnum(varused - varnum);
varnum = varused;
}
return res;
}
void
bdd_factory::initialize()
{
if (initialized)
return;
initialized = true;
bdd_init(50000, 5000);
bdd_setvarnum(varnum);
}
bool bdd_factory::initialized = false;
int bdd_factory::varnum = 2;
}
#ifndef SPOT_TGBA_BDDFACTORY_HH
# define SPOT_TGBA_BDDFACTORY_HH
#include <bdd.h>
namespace spot
{
class bdd_factory
{
public:
bdd_factory();
int create_node();
int create_pair();
static bdd
ithvar(int i)
{
return bdd_ithvar(i);
}
protected:
static void initialize();
int create_nodes(int i);
static bool initialized;
static int varnum;
int varused;
};
}
#endif // SPOT_TGBA_BDDFACTORY_HH
#include <set>
#include "dictunion.hh"
#include <bdd.h>
namespace spot
{
tgba_bdd_dict
tgba_bdd_dict_union(const tgba_bdd_dict& l, const tgba_bdd_dict& r)
{
tgba_bdd_dict res;
std::set<const ltl::formula*> now;
std::set<const ltl::formula*> var;
std::set<const ltl::formula*> prom;
tgba_bdd_dict::fv_map::const_iterator i;
// Merge Now variables.
for (i = l.now_map.begin(); i != l.now_map.end(); ++i)
now.insert(i->first);
for (i = r.now_map.begin(); i != r.now_map.end(); ++i)
now.insert(i->first);
// Merge atomic propositions.
for (i = l.var_map.begin(); i != l.var_map.end(); ++i)
var.insert(i->first);
for (i = r.var_map.begin(); i != r.var_map.end(); ++i)
var.insert(i->first);
// Merge promises.
for (i = l.prom_map.begin(); i != l.prom_map.end(); ++i)
prom.insert(i->first);
for (i = r.prom_map.begin(); i != r.prom_map.end(); ++i)
prom.insert(i->first);
// Ensure we have enough BDD variables.
int have = bdd_extvarnum(0);
int want = now.size() * 2 + var.size() + prom.size();
if (have < want)
bdd_setvarnum(want);
// Fill in the "defragmented" union dictionary.
// FIXME: Make some experiments with ordering of prom/var/now variables.
// Maybe there is one order that usually produces smaller BDDs?
// Next BDD variable to use.
int v = 0;
std::set<const ltl::formula*>::const_iterator f;
for (f = prom.begin(); f != prom.end(); ++f)
{
res.prom_map[*f] = v;
res.prom_formula_map[v] = *f;
++v;
}
for (f = var.begin(); f != var.end(); ++f)
{
res.var_map[*f] = v;
res.var_formula_map[v] = *f;
++v;
}
for (f = now.begin(); f != now.end(); ++f)
{
res.now_map[*f] = v;
res.now_formula_map[v] = *f;
v += 2;
}
assert (v == want);
return res;
}
}
#ifndef SPOT_TGBA_DICTUNION_HH
# define SPOT_TGBA_DICTUNION_HH
#include "tgbabdddict.hh"
namespace spot
{
tgba_bdd_dict
tgba_bdd_dict_union(const tgba_bdd_dict& l, const tgba_bdd_dict& r);
}
#endif // SPOT_TGBA_DICTUNION_HH
#include "ltlast/visitor.hh"
#include "ltlast/allnodes.hh"
#include "tgbabddconcretefactory.hh"
#include "ltl2tgba.hh"
// FIXME: Add ref to Couvreur's paper.
namespace spot
{
using namespace ltl;
class ltl_trad_visitor: public const_visitor
{
public:
ltl_trad_visitor(tgba_bdd_concrete_factory& fact)
: fact_(fact)
{
}
virtual
~ltl_trad_visitor()
{
}
bdd
result()
{
return res_;
}
void
visit(const atomic_prop* node)
{
res_ = fact_.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::F:
case unop::G:
// FIXME: We can normalize on the fly, here.
assert(!"unexpected operator, normalize first");
case unop::Not:
res_ = bdd_not(recurse(node->child()));
return;
case unop::X:
// FIXME: Can be smarter on X(a U b) and X(a R b).
int v = fact_.create_state(node->child());
bdd now = fact_.ithvar(v);
bdd next = fact_.ithvar(v + 1);
fact_.add_relation(bdd_apply(now, recurse(node->child()),
bddop_biimp));
res_ = next;
return;
}
/* 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:
{
int v = fact_.create_state(node);
bdd now = fact_.ithvar(v);
bdd next = fact_.ithvar(v + 1);
bdd promise_f2 =
fact_.ithvar(fact_.create_promise(node->second()));
/*
f1 U f2 <=> f2 | (f1 & X(f1 U f2))
In other words:
now <=> f2 | (f1 & next)
The rightmost conjunction, f1 & next, doesn't actually
encodes the fact that f2 should be fulfilled at some
point. We use the `promise_f2' variable for this purpose.
*/
fact_.add_relation(bdd_apply(now,
f2 | (promise_f2 & f1 & next),
bddop_biimp));
res_ = now;
return;
}
case binop::R:
{
int v = fact_.create_state(node);
bdd now = fact_.ithvar(v);
bdd next = fact_.ithvar(v + 1);
/*
f1 R f2 <=> f2 & (f1 | X(f1 U f2))
In other words:
now <=> f2 & (f1 | next)
*/
fact_.add_relation(bdd_apply(now, f2 & (f1 | next), bddop_biimp));
res_ = now;
return;
}
}
/* Unreachable code. */
assert(0);
}
void
visit(const multop* node)
{
int op = -1;
switch (node->op())
{
case multop::And:
op = bddop_and;
res_ = bddtrue;
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)), op);
}
}
bdd
recurse(const formula* f)
{
ltl_trad_visitor v(*this);
f->accept(v);
return v.result();
}
private:
bdd res_;
tgba_bdd_concrete_factory& fact_;
};
tgba_bdd_concrete
ltl_to_tgba(const formula* f)
{
tgba_bdd_concrete_factory fact;
ltl_trad_visitor v(fact);
f->accept(v);
tgba_bdd_concrete g(fact);
g.set_init_state(v.result());
return g;
}
}
#ifndef SPOT_TGBA_LTL2TGBA_HH
# define SPOT_TGBA_LTL2TGBA_HH
#include "ltlast/formula.hh"
#include "tgbabddconcrete.hh"
namespace spot
{
tgba_bdd_concrete ltl_to_tgba(const ltl::formula* f);
}
#endif // SPOT_TGBA_LTL2TGBA_HH
#ifndef SPOT_TGBA_STATE_HH
# define SPOT_TGBA_STATE_HH
namespace spot
{
class state
{
public:
// Compares two states (that come from the same automaton).
//
// This method returns an integer less than, equal to, or greater
// than zero if THIS is found, respectively, to be less than, equal
// to, or greater than OTHER according to some implicit total order.
//
// This method should not be called to compare state from
// different automata.
virtual int compare(const state& other) const = 0;
virtual ~state()
{
}
};
}
#endif // SPOT_TGBA_STATE_HH
#include "statebdd.hh"
#include <cassert>
namespace spot
{
int
state_bdd::compare(const state& other) const
{
// This method should not be called to compare states from different
// automata, and all states from the same automaton will use the same
// state class.
const state_bdd* o = dynamic_cast<const state_bdd*>(&other);
assert(o);
return o->as_bdd().id() - state_.id();
}
}
#ifndef SPOT_TGBA_STATEBDD_HH
# define SPOT_TGBA_STATEBDD_HH
#include <bdd.h>
#include "state.hh"
namespace spot
{
class state_bdd: public state
{
public:
state_bdd(bdd s)
: state_(s)
{
}
bdd
as_bdd() const
{
return state_;
}
virtual int compare(const state& other) const;
protected:
bdd state_;
};
}
#endif // SPOT_TGBA_STATEBDD_HH
#ifndef SPOT_TGBA_SUCCITER_H
# define SPOT_TGBA_SUCCITER_H
#include "statebdd.hh"
namespace spot
{
class tgba_succ_iterator
{
public:
virtual
~tgba_succ_iterator()
{
}
// iteration
virtual void first() = 0;
virtual void next() = 0;
virtual bool done() = 0;
// inspection
virtual state_bdd current_state() = 0;
virtual bdd current_condition() = 0;
virtual bdd current_promise() = 0;
};
}
#endif // SPOT_TGBA_SUCCITER_H
#include "succiterconcrete.hh"
namespace spot
{
tgba_succ_iterator_concrete::tgba_succ_iterator_concrete
(const tgba_bdd_core_data& d, bdd successors)
: data_(d), succ_set_(successors), next_succ_set_(successors),
current_(bddfalse)
{
}
tgba_succ_iterator_concrete::~tgba_succ_iterator_concrete()
{
}
void
tgba_succ_iterator_concrete::first()
{
next_succ_set_ = succ_set_;
if (!done())
next();
}
void
tgba_succ_iterator_concrete::next()
{
assert(!done());
// FIXME: Iterating on the successors this way (calling bdd_satone
// and NANDing out the result from the set) requires several descent
// of the BDD. Maybe it would be faster to compute all satisfying
// formula in one operation.
next_succ_set_ &= !current_;
current_ = bdd_satone(next_succ_set_);
}
bool
tgba_succ_iterator_concrete::done()
{
return next_succ_set_ == bddfalse;
}
state_bdd
tgba_succ_iterator_concrete::current_state()
{
assert(!done());
return bdd_exist(current_, data_.notnow_set);
}
bdd
tgba_succ_iterator_concrete::current_condition()
{
assert(!done());