* src/tgbatest/ltl2tgba.cc: Add option -t to output the LBTT automata.
* src/tgbaalgos/lbtt.cc, src/tgbaalgos/lbtt.hh: New files. * src/tgbaalgos/Makefile.am (tgbaalgos_HEADERS): Add lbtt.hh. (libtgbaalgos_la_SOURCES): Add lbtt.cc. * src/tgba/bddprint.cc (print_sat_handler): Put a space after "!". * src/tgbatest/readsave.test: Adjust spaces after "!".
This commit is contained in:
parent
a307c0d0ae
commit
f9c8eb1cb7
7 changed files with 272 additions and 3 deletions
|
|
@ -1,5 +1,12 @@
|
||||||
2003-07-08 Alexandre Duret-Lutz <aduret@src.lip6.fr>
|
2003-07-08 Alexandre Duret-Lutz <aduret@src.lip6.fr>
|
||||||
|
|
||||||
|
* src/tgbatest/ltl2tgba.cc: Add option -t to output the LBTT automata.
|
||||||
|
* src/tgbaalgos/lbtt.cc, src/tgbaalgos/lbtt.hh: New files.
|
||||||
|
* src/tgbaalgos/Makefile.am (tgbaalgos_HEADERS): Add lbtt.hh.
|
||||||
|
(libtgbaalgos_la_SOURCES): Add lbtt.cc.
|
||||||
|
* src/tgba/bddprint.cc (print_sat_handler): Put a space after "!".
|
||||||
|
* src/tgbatest/readsave.test: Adjust spaces after "!".
|
||||||
|
|
||||||
* src/ltlvisit/dump.cc: Strip useless spot::ltl:: prefixes.
|
* src/ltlvisit/dump.cc: Strip useless spot::ltl:: prefixes.
|
||||||
|
|
||||||
2003-07-07 Alexandre Duret-Lutz <aduret@src.lip6.fr>
|
2003-07-07 Alexandre Duret-Lutz <aduret@src.lip6.fr>
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,8 @@ namespace spot
|
||||||
else
|
else
|
||||||
not_first = true;
|
not_first = true;
|
||||||
if (varset[v] == 0)
|
if (varset[v] == 0)
|
||||||
*where << "!";
|
// The space is important for LBTT.
|
||||||
|
*where << "! ";
|
||||||
print_handler(*where, v);
|
print_handler(*where, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ tgbaalgosdir = $(pkgincludedir)/tgbaalgos
|
||||||
|
|
||||||
tgbaalgos_HEADERS = \
|
tgbaalgos_HEADERS = \
|
||||||
dotty.hh \
|
dotty.hh \
|
||||||
|
lbtt.hh \
|
||||||
ltl2tgba.hh \
|
ltl2tgba.hh \
|
||||||
save.hh
|
save.hh
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libtgbaalgos.la
|
noinst_LTLIBRARIES = libtgbaalgos.la
|
||||||
libtgbaalgos_la_SOURCES = \
|
libtgbaalgos_la_SOURCES = \
|
||||||
dotty.cc \
|
dotty.cc \
|
||||||
|
lbtt.cc \
|
||||||
ltl2tgba.cc \
|
ltl2tgba.cc \
|
||||||
save.cc
|
save.cc
|
||||||
|
|
|
||||||
220
src/tgbaalgos/lbtt.cc
Normal file
220
src/tgbaalgos/lbtt.cc
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include "tgba/tgba.hh"
|
||||||
|
#include "save.hh"
|
||||||
|
#include "tgba/bddprint.hh"
|
||||||
|
#include "ltlvisit/tostring.hh"
|
||||||
|
#include "tgba/bddprint.hh"
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
struct bdd_less_than
|
||||||
|
{
|
||||||
|
bool
|
||||||
|
operator()(const bdd& left, const bdd& right) const
|
||||||
|
{
|
||||||
|
return left.id() < right.id();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// At some point we'll need to print an accepting set into LBTT's
|
||||||
|
// forma. LBTT expect numbered accepting sets, so first we'll
|
||||||
|
// number each accepting condition, and latter when we have to print
|
||||||
|
// them we'll just have to look up each of them.
|
||||||
|
class accepting_cond_splitter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
accepting_cond_splitter(bdd all_acc)
|
||||||
|
{
|
||||||
|
unsigned count = 0;
|
||||||
|
while (all_acc != bddfalse)
|
||||||
|
{
|
||||||
|
bdd acc = bdd_satone(all_acc);
|
||||||
|
all_acc &= !acc;
|
||||||
|
sm[acc] = count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
split(std::ostream& os, bdd b)
|
||||||
|
{
|
||||||
|
while (b != bddfalse)
|
||||||
|
{
|
||||||
|
bdd acc = bdd_satone(b);
|
||||||
|
b &= !acc;
|
||||||
|
os << sm[acc] << " ";
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
count() const
|
||||||
|
{
|
||||||
|
return sm.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::map<bdd, unsigned, bdd_less_than> split_map;
|
||||||
|
split_map sm;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert a BDD formula to the syntax used by LBTT's transition guards.
|
||||||
|
// Conjunctions are printed by bdd_format_sat, so we just have
|
||||||
|
// to handle the other cases.
|
||||||
|
static std::string
|
||||||
|
bdd_to_lbtt(bdd b, const tgba_bdd_dict& d)
|
||||||
|
{
|
||||||
|
if (b == bddfalse)
|
||||||
|
return "f";
|
||||||
|
else if (b == bddtrue)
|
||||||
|
return "t";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bdd cube = bdd_satone(b);
|
||||||
|
b &= !cube;
|
||||||
|
if (b != bddfalse)
|
||||||
|
{
|
||||||
|
return "| " + bdd_to_lbtt(b, d) + " " + bdd_to_lbtt(cube, d);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string res = "";
|
||||||
|
for (int count = bdd_nodecount(cube); count > 1; --count)
|
||||||
|
res += "& ";
|
||||||
|
return res + bdd_format_sat(d, cube);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each state in the produced automata corresponds to
|
||||||
|
// a (state, accepting set) pair for the source automata.
|
||||||
|
|
||||||
|
typedef std::pair<state*, bdd> state_acc_pair;
|
||||||
|
|
||||||
|
struct state_acc_pair_less_than
|
||||||
|
{
|
||||||
|
bool
|
||||||
|
operator()(const state_acc_pair& left, const state_acc_pair& right) const
|
||||||
|
{
|
||||||
|
int cmp = left.first->compare(right.first);
|
||||||
|
if (cmp < 0)
|
||||||
|
return true;
|
||||||
|
if (cmp > 0)
|
||||||
|
return false;
|
||||||
|
return left.second.id() < right.second.id();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Each state of the produced automata is numbered. Map of state seen.
|
||||||
|
typedef std::map<state_acc_pair, unsigned, state_acc_pair_less_than> acp_seen_map;
|
||||||
|
|
||||||
|
// Set of states yet to produce.
|
||||||
|
typedef std::set<state_acc_pair, state_acc_pair_less_than> todo_set;
|
||||||
|
|
||||||
|
// Each *source* car correspond to several state in the produced
|
||||||
|
// automate. A minmax_pair specify the range of such associated states.
|
||||||
|
typedef std::pair<unsigned, unsigned> minmax_pair;
|
||||||
|
typedef std::map<state*, minmax_pair, state_ptr_less_than> seen_map;
|
||||||
|
|
||||||
|
// Take a STATE from the source automata, and fill TODO with
|
||||||
|
// the list of associated states to output. Return the correponding
|
||||||
|
// range in MMP. Update SEEN, ACP_SEEN, and STATE_NUMBER.
|
||||||
|
void
|
||||||
|
fill_todo(todo_set& todo, seen_map& seen, acp_seen_map& acp_seen,
|
||||||
|
state* state, const tgba& g,
|
||||||
|
minmax_pair& mmp, unsigned& state_number)
|
||||||
|
{
|
||||||
|
typedef std::set<bdd, bdd_less_than> bdd_set;
|
||||||
|
|
||||||
|
seen_map::iterator i = seen.find(state);
|
||||||
|
if (i != seen.end())
|
||||||
|
{
|
||||||
|
mmp = i->second;
|
||||||
|
delete state;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Browse the successors of STATE to gather accepting
|
||||||
|
// conditions of outgoing transitions.
|
||||||
|
bdd_set acc_seen;
|
||||||
|
tgba_succ_iterator* si = g.succ_iter(state);
|
||||||
|
for (si->first(); !si->done(); si->next())
|
||||||
|
{
|
||||||
|
acc_seen.insert(si->current_accepting_conditions());
|
||||||
|
}
|
||||||
|
mmp.first = state_number;
|
||||||
|
for (bdd_set::iterator i = acc_seen.begin(); i != acc_seen.end(); ++i)
|
||||||
|
{
|
||||||
|
state_acc_pair p(state, *i);
|
||||||
|
todo.insert(p);
|
||||||
|
acp_seen[p] = state_number++;
|
||||||
|
}
|
||||||
|
mmp.second = state_number;
|
||||||
|
seen[state] = mmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
lbtt_reachable(std::ostream& os, const tgba& g)
|
||||||
|
{
|
||||||
|
const tgba_bdd_dict& d = g.get_dict();
|
||||||
|
std::ostringstream body;
|
||||||
|
|
||||||
|
seen_map seen;
|
||||||
|
acp_seen_map acp_seen;
|
||||||
|
todo_set todo;
|
||||||
|
unsigned state_number = 0;
|
||||||
|
|
||||||
|
minmax_pair mmp;
|
||||||
|
|
||||||
|
fill_todo(todo, seen, acp_seen,
|
||||||
|
g.get_init_state(), g, mmp, state_number);
|
||||||
|
accepting_cond_splitter acs(g.all_accepting_conditions());
|
||||||
|
|
||||||
|
while(! todo.empty())
|
||||||
|
{
|
||||||
|
state_acc_pair sap = *todo.begin();
|
||||||
|
todo.erase(todo.begin());
|
||||||
|
unsigned number = acp_seen[sap];
|
||||||
|
|
||||||
|
body << number << " "
|
||||||
|
// Mark the initial state.
|
||||||
|
<< ((number >= mmp.first && number < mmp.second) ? 1 : 0) << " ";
|
||||||
|
|
||||||
|
acs.split(body, sap.second);
|
||||||
|
body << "-1" << std::endl;
|
||||||
|
|
||||||
|
tgba_succ_iterator* si = g.succ_iter(sap.first);
|
||||||
|
for (si->first(); !si->done(); si->next())
|
||||||
|
{
|
||||||
|
// We have put the accepting conditions on the state,
|
||||||
|
// so draw only outgoing transition with these accepting
|
||||||
|
// conditions.
|
||||||
|
if (si->current_accepting_conditions() != sap.second)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
minmax_pair destrange;
|
||||||
|
fill_todo(todo, seen, acp_seen,
|
||||||
|
si->current_state(), g, destrange, state_number);
|
||||||
|
|
||||||
|
// Link to all instances of the successor.
|
||||||
|
std::string s = bdd_to_lbtt(si->current_condition(), d);
|
||||||
|
for (unsigned i = destrange.first; i < destrange.second; ++i)
|
||||||
|
{
|
||||||
|
body << i << " " << s << " " << "-1" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body << "-1" << std::endl;
|
||||||
|
delete si;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << state_number << " " << acs.count() << std::endl;
|
||||||
|
os << body.str();
|
||||||
|
// Finally delete all states used as keys in m:
|
||||||
|
for (seen_map::iterator i = seen.begin(); i != seen.end(); ++i)
|
||||||
|
delete i->first;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/tgbaalgos/lbtt.hh
Normal file
31
src/tgbaalgos/lbtt.hh
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef SPOT_TGBAALGOS_LBTT_HH
|
||||||
|
# define SPOT_TGBAALGOS_LBTT_HH
|
||||||
|
|
||||||
|
#include "tgba/tgba.hh"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
/// \brief Print reachable states in LBTT format.
|
||||||
|
///
|
||||||
|
/// Note that LBTT expects an automaton with transition
|
||||||
|
/// labeled by propositional formulae, and generalized
|
||||||
|
/// Büchi accepting conditions on \emph states. This
|
||||||
|
/// is unlike our spot::tgba automata which put
|
||||||
|
/// botg generalized accepting conditions and propositional
|
||||||
|
/// formulae) on \emph transitions.
|
||||||
|
///
|
||||||
|
/// This algorithm will therefore produce an automata
|
||||||
|
/// where accepting conditions have been moved from
|
||||||
|
/// each transition to previous state. In the worst
|
||||||
|
/// case, doing so will multiply the number of states
|
||||||
|
/// and transitions of the automata by <code>2^|Acc|</code>.
|
||||||
|
/// where <code>|Acc|</code> is the number of accepting
|
||||||
|
/// conditions used by the automata. You have been warned.
|
||||||
|
///
|
||||||
|
/// \param g The automata to print.
|
||||||
|
/// \param os Where to print.
|
||||||
|
std::ostream& lbtt_reachable(std::ostream& os, const tgba& g);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SPOT_TGBAALGOS_LBTT_HH
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "tgba/bddprint.hh"
|
#include "tgba/bddprint.hh"
|
||||||
#include "tgba/tgbabddtranslatefactory.hh"
|
#include "tgba/tgbabddtranslatefactory.hh"
|
||||||
#include "tgbaalgos/dotty.hh"
|
#include "tgbaalgos/dotty.hh"
|
||||||
|
#include "tgbaalgos/lbtt.hh"
|
||||||
|
|
||||||
void
|
void
|
||||||
syntax(char* prog)
|
syntax(char* prog)
|
||||||
|
|
@ -19,10 +20,10 @@ syntax(char* prog)
|
||||||
<< " -A same as -a, but as a set" << std::endl
|
<< " -A same as -a, but as a set" << std::endl
|
||||||
<< " -d turn on traces during parsing" << std::endl
|
<< " -d turn on traces during parsing" << std::endl
|
||||||
<< " -o re-order BDD variables in the automata" << std::endl
|
<< " -o re-order BDD variables in the automata" << std::endl
|
||||||
<< std::endl
|
|
||||||
<< " -r display the relation BDD, not the reachability graph"
|
<< " -r display the relation BDD, not the reachability graph"
|
||||||
<< std::endl
|
<< std::endl
|
||||||
<< " -R same as -r, but as a set" << std::endl
|
<< " -R same as -r, but as a set" << std::endl
|
||||||
|
<< " -t display reachable states in LBTT's format" << std::endl
|
||||||
<< " -v display the BDD variables used by the automaton"
|
<< " -v display the BDD variables used by the automaton"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
exit(2);
|
exit(2);
|
||||||
|
|
@ -69,6 +70,10 @@ main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
output = 3;
|
output = 3;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(argv[formula_index], "-t"))
|
||||||
|
{
|
||||||
|
output = 6;
|
||||||
|
}
|
||||||
else if (!strcmp(argv[formula_index], "-v"))
|
else if (!strcmp(argv[formula_index], "-v"))
|
||||||
{
|
{
|
||||||
output = 5;
|
output = 5;
|
||||||
|
|
@ -118,6 +123,9 @@ main(int argc, char** argv)
|
||||||
case 5:
|
case 5:
|
||||||
a.get_dict().dump(std::cout);
|
a.get_dict().dump(std::cout);
|
||||||
break;
|
break;
|
||||||
|
case 6:
|
||||||
|
spot::lbtt_reachable(std::cout, a);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(!"unknown output option");
|
assert(!"unknown output option");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ EOF
|
||||||
|
|
||||||
cat >expected <<EOF
|
cat >expected <<EOF
|
||||||
acc = "c" "d";
|
acc = "c" "d";
|
||||||
"s1", "s2", a !b, "c" "d";
|
"s1", "s2", a ! b, "c" "d";
|
||||||
"s2", "state 3", a, "c";
|
"s2", "state 3", a, "c";
|
||||||
"state 3", "s1", ,;
|
"state 3", "s1", ,;
|
||||||
EOF
|
EOF
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue