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

replace sba_explicit_* by tgba_digraph, and use tgba_digraph is postproc

This is a huge patch.  tgba_digraph are equiped with some boolean
properties that can be used to indicate whether they represent SBA
(and will carry more informations later).  All algorithms that produce
or use sba_explicit_* automata are changed to use tgba_digraph.
postproc has been rewritten using only tgba_digraph, and this required
changing the return types of many algorithms from tgba* to
tgba_digraph*.

* src/bin/dstar2tgba.cc, src/bin/ltlfilt.cc, src/dstarparse/dra2ba.cc,
src/dstarparse/dstar2tgba.cc, src/dstarparse/nra2nba.cc,
src/dstarparse/nsa2tgba.cc, src/dstarparse/public.hh,
src/tgba/tgbagraph.hh, src/tgba/tgbasafracomplement.cc,
src/tgbaalgos/compsusp.cc, src/tgbaalgos/compsusp.hh,
src/tgbaalgos/degen.cc, src/tgbaalgos/degen.hh,
src/tgbaalgos/dotty.cc, src/tgbaalgos/minimize.cc,
src/tgbaalgos/minimize.hh, src/tgbaalgos/postproc.cc,
src/tgbaalgos/postproc.hh, src/tgbaalgos/sccfilter.cc,
src/tgbaalgos/sccinfo.cc, src/tgbaalgos/stripacc.cc,
src/tgbaalgos/stripacc.hh, src/tgbaalgos/translate.cc,
src/tgbaalgos/translate.hh, src/tgbatest/ltl2tgba.cc,
wrap/python/spot.i: Update.
parent 637aeff2
......@@ -307,8 +307,8 @@ namespace
const xtime_t before = gethrxtime();
spot::tgba* nba = spot::dstar_to_tgba(daut);
const spot::tgba* aut = post.run(nba, 0);
auto nba = spot::dstar_to_tgba(daut);
auto aut = post.run(nba, 0);
const xtime_t after = gethrxtime();
const double prec = XTIME_PRECISION;
......
......@@ -548,8 +548,8 @@ namespace
// other reasons.
if (matched && obligation)
{
spot::tgba* aut = ltl_to_tgba_fm(f, simpl.get_dict());
spot::tgba* min = minimize_obligation(aut, f);
auto aut = ltl_to_tgba_fm(f, simpl.get_dict());
auto min = minimize_obligation(aut, f);
assert(min);
if (aut == min)
{
......
......@@ -49,7 +49,7 @@ namespace spot
// This function is defined in nra2nba.cc, and used only here.
SPOT_LOCAL
tgba* nra_to_nba(const dstar_aut* nra, const tgba* aut);
tgba_digraph* nra_to_nba(const dstar_aut* nra, const tgba* aut);
namespace
{
......@@ -320,7 +320,7 @@ namespace spot
}
tgba* dra_to_ba(const dstar_aut* dra, bool* dba)
tgba_digraph* dra_to_ba(const dstar_aut* dra, bool* dba)
{
assert(dra->type == Rabin);
......
......@@ -21,7 +21,7 @@
namespace spot
{
tgba*
tgba_digraph*
dstar_to_tgba(const dstar_aut* daut)
{
switch (daut->type)
......
......@@ -122,7 +122,7 @@ namespace spot
// In dra_to_dba() we call this function with a second argument
// that is a masked version of nra->aut.
SPOT_LOCAL
tgba* nra_to_nba(const dstar_aut* nra, const tgba* aut)
tgba_digraph* nra_to_nba(const dstar_aut* nra, const tgba* aut)
{
assert(nra->type == Rabin);
nra_to_nba_worker w(nra, aut);
......@@ -134,7 +134,7 @@ namespace spot
}
SPOT_API
tgba* nra_to_nba(const dstar_aut* nra)
tgba_digraph* nra_to_nba(const dstar_aut* nra)
{
return nra_to_nba(nra, nra->aut);
}
......
......@@ -99,7 +99,7 @@ namespace spot
}
SPOT_API
tgba* nsa_to_tgba(const dstar_aut* nsa)
tgba_digraph* nsa_to_tgba(const dstar_aut* nsa)
{
assert(nsa->type == Streett);
tgba_digraph* a = nsa->aut;
......
......@@ -106,14 +106,14 @@ namespace spot
/// \brief Convert a non-deterministic Rabin automaton into a
/// non-deterministic Büchi automaton.
SPOT_API tgba*
SPOT_API tgba_digraph*
nra_to_nba(const dstar_aut* nra);
/// \brief Convert a non-deterministic Rabin automaton into a
/// non-deterministic Büchi automaton.
///
/// This version simply ignores all states in \a ignore.
SPOT_API tgba*
SPOT_API tgba_digraph*
nra_to_nba(const dstar_aut* nra, const state_set* ignore);
/// \brief Convert a deterministic Rabin automaton into a
......@@ -132,18 +132,18 @@ namespace spot
/// If the optional \a dba_output argument is non-null, the
/// pointed Boolean will be updated to indicate whether the
/// returned Büchi automaton is deterministic.
SPOT_API tgba*
SPOT_API tgba_digraph*
dra_to_ba(const dstar_aut* dra, bool* dba_output = 0);
/// \brief Convert a non-deterministic Streett automaton into a
/// non-deterministic tgba.
SPOT_API tgba*
SPOT_API tgba_digraph*
nsa_to_tgba(const dstar_aut* nra);
/// \brief Convert a Rabin or Streett automaton into a TGBA.
///
/// This function calls dra_to_ba() or nsa_to_tgba().
SPOT_API tgba*
SPOT_API tgba_digraph*
dstar_to_tgba(const dstar_aut* dstar);
......
......@@ -411,6 +411,48 @@ namespace spot
}
g_.defrag();
}
protected:
unsigned bprops_ = 0;
public:
enum bprop {
StateBasedAcc = 1,
SingleAccSet = 2,
SBA = StateBasedAcc | SingleAccSet,
};
bool get_bprop(bprop p) const
{
return (bprops_ & p) == p;
}
void set_bprop(bprop p)
{
bprops_ |= p;
}
void clear_bprop(bprop p)
{
bprops_ &= ~p;
}
bool state_is_accepting(unsigned s) const
{
assert(get_bprop(StateBasedAcc));
for (auto& t: g_.out(s))
// Stop at the first transition, since the remaining should be
// labeled identically.
return t.acc == all_acceptance_conditions_;
return false;
}
bool state_is_accepting(const state* s) const
{
return state_is_accepting(state_number(s));
}
};
}
......
......@@ -34,7 +34,6 @@
#include "ltlast/constant.hh"
#include "tgbaalgos/dotty.hh"
#include "tgba/tgbasafracomplement.hh"
#include "tgba/sba.hh"
#include "tgbaalgos/degen.hh"
namespace spot
......@@ -54,7 +53,7 @@ namespace spot
/// \brief Automaton with Safra's tree as states.
struct safra_tree_automaton
{
safra_tree_automaton(const tgba* sba);
safra_tree_automaton(const tgba_digraph* sba);
~safra_tree_automaton();
typedef std::map<bdd, const safra_tree*, bdd_less_than> transition_list;
typedef
......@@ -67,14 +66,14 @@ namespace spot
int get_nb_acceptance_pairs() const;
safra_tree* get_initial_state() const;
void set_initial_state(safra_tree* s);
const tgba* get_sba(void) const
const tgba_digraph* get_sba(void) const
{
return a_;
}
private:
mutable int max_nb_pairs_;
safra_tree* initial_state;
const tgba* a_;
const tgba_digraph* a_;
};
/// \brief A Safra tree, used as state during the determinization
......@@ -112,7 +111,7 @@ namespace spot
int max_name() const;
// Operations to get successors of a tree.
safra_tree* branch_accepting(const sba& a);
safra_tree* branch_accepting(const tgba_digraph& a);
safra_tree* succ_create(const bdd& condition,
cache_t& cache_transition);
safra_tree* normalize_siblings();
......@@ -316,7 +315,7 @@ namespace spot
/// is inserted with the set of all accepting states of \c nodes
/// as label and an unused name.
safra_tree*
safra_tree::branch_accepting(const sba& a)
safra_tree::branch_accepting(const tgba_digraph& a)
{
for (auto c: children)
c->branch_accepting(a);
......@@ -574,7 +573,8 @@ namespace spot
private:
typedef std::set<int> atomic_list_t;
typedef std::set<bdd, bdd_less_than> conjunction_list_t;
static void retrieve_atomics(const safra_tree* node, sba* sba_aut,
static void retrieve_atomics(const safra_tree* node,
tgba_digraph* sba_aut,
safra_tree::cache_t& cache,
atomic_list_t& atomic_list);
static void set_atomic_list(atomic_list_t& list, bdd condition);
......@@ -587,7 +587,7 @@ namespace spot
safra_determinisation::create_safra_automaton(const tgba* a)
{
// initialization.
sba* sba_aut = degeneralize(a);
auto sba_aut = degeneralize(a);
safra_tree_automaton* st = new safra_tree_automaton(sba_aut);
......@@ -664,7 +664,7 @@ namespace spot
/// of the states in the label of the node.
void
safra_determinisation::retrieve_atomics(const safra_tree* node,
sba* sba_aut,
tgba_digraph* sba_aut,
safra_tree::cache_t& cache,
atomic_list_t& atomic_list)
{
......@@ -1031,7 +1031,7 @@ namespace spot
// safra_tree_automaton
////////////////////////
safra_tree_automaton::safra_tree_automaton(const tgba* a)
safra_tree_automaton::safra_tree_automaton(const tgba_digraph* a)
: max_nb_pairs_(-1), initial_state(0), a_(a)
{
a->get_dict()->register_all_variables_of(a, this);
......
......@@ -349,7 +349,7 @@ namespace spot
}
tgba*
tgba_digraph*
compsusp(const ltl::formula* f, bdd_dict* dict,
bool no_wdba, bool no_simulation,
bool early_susp, bool no_susp_product, bool wdba_smaller,
......@@ -371,18 +371,11 @@ namespace spot
if (!no_wdba)
{
tgba* min = minimize_obligation(res, g, 0, wdba_smaller);
tgba_digraph* min = minimize_obligation(res, g, 0, wdba_smaller);
if (min != res)
{
delete res;
// FIXME: minimize_obligation does not yet return a
// tgba_digraph, so we convert the result using dupexp.
// Once minimize_obligation is fixed, we should remove the
// call to dupexp.
assert(dynamic_cast<tgba_digraph*>(min) == nullptr);
res = tgba_dupexp_dfs(min);
delete min;
//res = min;
res = min;
no_simulation = true;
}
}
......
......@@ -21,6 +21,7 @@
# define SPOT_TGBAALGOS_COMPSUSP_HH
#include "ltlast/formula.hh"
#include "tgba/tgbagraph.hh"
namespace spot
{
......@@ -49,7 +50,7 @@ namespace spot
/// This interface is subject to change, and clients aiming for
/// long-term stability should better use the services of the
/// spot::translator class instead.
SPOT_API tgba*
SPOT_API tgba_digraph*
compsusp(const ltl::formula* f, bdd_dict* dict,
bool no_wdba = false, bool no_simulation = false,
bool early_susp = false, bool no_susp_product = false,
......
......@@ -19,7 +19,7 @@
#include "degen.hh"
#include "tgba/tgbaexplicit.hh"
#include "tgba/tgbagraph.hh"
#include "misc/hash.hh"
#include "misc/hashfunc.hh"
#include "ltlast/constant.hh"
......@@ -251,7 +251,7 @@ namespace spot
};
}
sba*
tgba_digraph*
degeneralize(const tgba* a, bool use_z_lvl, bool use_cust_acc_orders,
int use_lvl_cache, bool skip_levels)
{
......@@ -259,8 +259,9 @@ namespace spot
bdd_dict* dict = a->get_dict();
// The result (degeneralized) automaton uses numbered states.
sba_explicit_number* res = new sba_explicit_number(dict);
// The result automaton is an SBA.
auto res = new tgba_digraph(dict);
res->set_bprop(tgba_digraph::SBA);
// We use the same BDD variables as the input, except for the
// acceptance.
......@@ -314,7 +315,7 @@ namespace spot
// (dest*2+acc) where dest is the destination state number, and
// acc is 1 iff the transition is accepting. The source
// is always that of the current iteration.
typedef std::map<int, state_explicit_number::transition*> tr_cache_t;
typedef std::map<int, unsigned> tr_cache_t;
tr_cache_t tr_cache;
// State level cache
......@@ -355,16 +356,7 @@ namespace spot
}
}
#ifdef DEGEN_DEBUG
std::map<const state*, int>names;
names[s.first] = 1;
ds2num[s] =
10000 * names[s.first] + 100 * s.second + m.scc_of_state(s.first);
#else
ds2num[s] = 0;
#endif
ds2num[s] = res->new_state();
todo.push_back(s);
// If use_lvl_cache is on insert initial state to level cache
......@@ -557,11 +549,7 @@ namespace spot
}
else
{
#ifdef DEGEN_DEBUG
dest = 10000 * names[d.first] + 100 * d.second + scc;
#else
dest = ds2num.size();
#endif
dest = res->new_state();
ds2num[d] = dest;
todo.push_back(d);
// Insert new state to cache
......@@ -582,24 +570,24 @@ namespace spot
}
}
state_explicit_number::transition*& t =
tr_cache[dest * 2 + is_acc];
unsigned& t = tr_cache[dest * 2 + is_acc];
if (t == 0)
{
// Actually create the transition.
t = res->create_transition(src, dest);
t->condition = i->current_condition();
// If the source state is accepting, we have to put
// degen_acc on all outgoing transitions. (We are still
// building a TGBA; we only assure that it can be used as
// an SBA.)
// Actually create the transition. If the source
// state is accepting, we have to put degen_acc on all
// outgoing transitions. (We are still building a
// TGBA; we only assure that it can be used as an
// SBA.)
bdd acc = bddfalse;
if (is_acc)
t->acceptance_conditions = degen_acc;
acc = degen_acc;
t = res->new_transition(src, dest,
i->current_condition(), acc);
}
else
{
t->condition |= i->current_condition();
res->trans_data(t).cond |= i->current_condition();
}
}
tr_cache.clear();
......
......@@ -20,13 +20,10 @@
#ifndef SPOT_TGBAALGOS_DEGEN_HH
# define SPOT_TGBAALGOS_DEGEN_HH
# include "misc/common.hh"
# include "tgba/tgbagraph.hh"
namespace spot
{
class sba;
class tgba;
/// \ingroup tgba_misc
/// \brief Degeneralize a spot::tgba into an equivalent sba with
/// only one acceptance condition.
......@@ -52,7 +49,7 @@ namespace spot
/// \a a to be computed prior to its actual degeneralization.
///
/// \see tgba_sba_proxy, tgba_tba_proxy
SPOT_API sba*
SPOT_API tgba_digraph*
degeneralize(const tgba* a, bool use_z_lvl = true,
bool use_cust_acc_orders = false,
int use_lvl_cache = 1,
......
......@@ -28,7 +28,7 @@
#include "tgba/bddprint.hh"
#include "reachiter.hh"
#include "misc/escape.hh"
#include "tgba/tgbatba.hh"
#include "tgba/tgbagraph.hh"
#include "tgba/formula2bdd.hh"
namespace spot
......@@ -130,6 +130,9 @@ namespace spot
{
if (!dd)
dd = dotty_decorator::instance();
if (const tgba_digraph* gd = dynamic_cast<const tgba_digraph*>(g))
assume_sba |= gd->get_bprop(tgba_digraph::StateBasedAcc);
dotty_bfs d(os, g, assume_sba, dd);
d.run();
return os;
......
......@@ -48,7 +48,6 @@
#include "tgbaalgos/bfssteps.hh"
#include "tgbaalgos/isdet.hh"
#include "tgbaalgos/dtgbacomp.hh"
#include "priv/countstates.hh"
namespace spot
{
......@@ -115,30 +114,43 @@ namespace spot
// From the base automaton and the list of sets, build the minimal
// resulting automaton
sba_explicit_number* build_result(const tgba* a,
std::list<hash_set*>& sets,
hash_set* final)
tgba_digraph* build_result(const tgba* a,
std::list<hash_set*>& sets,
hash_set* final)
{
auto dict = a->get_dict();
auto res = new tgba_digraph(dict);
dict->register_all_variables_of(a, res);
dict->unregister_all_typed_variables(bdd_dict::acc, res);
res->set_bprop(tgba_digraph::StateBasedAcc);
// For each set, create a state in the resulting automaton.
// For a state s, state_num[s] is the number of the state in the minimal
// automaton.
hash_map state_num;
std::list<hash_set*>::iterator sit;
unsigned num = 0;
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set::iterator hit;
hash_set* h = *sit;
unsigned num = res->new_state();
for (hit = h->begin(); hit != h->end(); ++hit)
state_num[*hit] = num;
++num;
}
typedef state_explicit_number::transition trs;
sba_explicit_number* res = new sba_explicit_number(a->get_dict());
// For each transition in the initial automaton, add the corresponding
// transition in res.
bdd allacc = bddfalse;
if (!final->empty())
res->declare_acceptance_condition(ltl::constant::true_instance());
{
res->set_bprop(tgba_digraph::SingleAccSet);
int accvar =
dict->register_acceptance_variable(ltl::constant::true_instance(),
res);
allacc = bdd_ithvar(accvar);
res->set_acceptance_conditions(allacc);
}
for (sit = sets.begin(); sit != sets.end(); ++sit)
{
hash_set::iterator hit;
......@@ -157,17 +169,21 @@ namespace spot
dst->destroy();
if (i == state_num.end()) // Ignore useless destinations.
continue;
trs* t = res->create_transition(src_num, i->second);
res->add_conditions(t, succit->current_condition());
bdd acc = bddfalse;
if (accepting)
res->add_acceptance_condition(t, ltl::constant::true_instance());
acc = allacc;
res->new_transition(src_num, i->second,
succit->current_condition(), acc);
}
}
res->merge_transitions();
const state* init_state = a->get_init_state();
unsigned init_num = state_num[init_state];
init_state->destroy();
res->set_init_state(init_num);
if (res->num_states() > 0)
{
const state* init_state = a->get_init_state();
unsigned init_num = state_num[init_state];
init_state->destroy();
res->set_init_state(init_num);
}
return res;
}
......@@ -212,6 +228,7 @@ namespace spot
wdba_scc_is_accepting(const tgba_digraph* det_a, unsigned scc_n,
const tgba* orig_a, scc_map& sm, power_map& pm)
{
// Get some state from the SCC #n.
const state* start = sm.one_state_of(scc_n)->clone();
......@@ -272,8 +289,8 @@ namespace spot
}
sba_explicit_number* minimize_dfa(const tgba_digraph* det_a,
hash_set* final, hash_set* non_final)
tgba_digraph* minimize_dfa(const tgba_digraph* det_a,
hash_set* final, hash_set* non_final)
{
typedef std::list<hash_set*> partition_t;
partition_t cur_run;
......@@ -460,7 +477,7 @@ namespace spot
#endif
// Build the result.
sba_explicit_number* res = build_result(det_a, done, final_copy);
auto* res = build_result(det_a, done, final_copy);
// Free all the allocated memory.
delete final_copy;
......@@ -479,7 +496,7 @@ namespace spot
}
sba_explicit_number* minimize_monitor(const tgba* a)
tgba_digraph* minimize_monitor(const tgba* a)
{
hash_set* final = new hash_set;
hash_set* non_final = new hash_set;
......@@ -497,7 +514,7 @@ namespace spot
return minimize_dfa(det_a, final, non_final);
}
sba_explicit_number* minimize_wdba(const tgba* a)
tgba_digraph* minimize_wdba(const tgba* a)
{
hash_set* final = new hash_set;
hash_set* non_final = new hash_set;
......@@ -596,21 +613,21 @@ namespace spot
return minimize_dfa(det_a, final, non_final);
}
tgba*
minimize_obligation(const tgba* aut_f,
tgba_digraph*
minimize_obligation(const tgba_digraph* aut_f,
const ltl::formula* f, const tgba* aut_neg_f,
bool reject_bigger)
{
sba_explicit_number* min_aut_f = minimize_wdba(aut_f);
auto min_aut_f = minimize_wdba(aut_f);
if (reject_bigger)
{
// Abort if min_aut_f has more states than aut_f.
unsigned orig_states = count_states(aut_f);
unsigned orig_states = aut_f->num_states();
if (orig_states < min_aut_f->num_states())
{
delete min_aut_f;
return const_cast<tgba*>(aut_f);
return const_cast<tgba_digraph*>(aut_f);
}
}
......@@ -653,7 +670,7 @@ namespace spot
{
// Otherwise, we cannot check if the minimization is safe.
delete min_aut_f;
return 0;
return nullptr;
}
}
......@@ -705,6 +722,6 @@ namespace spot
if (ok)
return min_aut_f;
delete min_aut_f;