Commit 2fb436a1 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

Replace most uses of scc_map by scc_info.

This involves reimplementing some algorithms using tgba_digraph, and
implementing an explicit product that takes two tgba_digraphs and
produces a tgba_digraph.

* src/tgbaalgos/product.cc, src/tgbaalgos/product.hh: New files.
* src/tgbaalgos/Makefile.am: Adjust.
* src/bin/ltlcross.cc, src/tgba/tgba.cc, src/tgba/tgba.hh,
src/tgba/tgbasafracomplement.cc, src/tgba/tgbasafracomplement.hh,
src/tgbaalgos/cycles.cc, src/tgbaalgos/cycles.hh,
src/tgbaalgos/degen.cc, src/tgbaalgos/degen.hh,
src/tgbaalgos/isweakscc.cc, src/tgbaalgos/isweakscc.hh,
src/tgbaalgos/minimize.cc, src/tgbaalgos/minimize.hh,
src/tgbaalgos/powerset.cc, src/tgbaalgos/powerset.hh,
src/tgbaalgos/safety.cc, src/tgbaalgos/safety.hh,
src/tgbaalgos/sccinfo.cc, src/tgbaalgos/sccinfo.hh,
src/tgbatest/complementation.cc, src/tgbatest/emptchk.cc,
src/tgbatest/ltl2ta.test, src/tgbatest/ltl2tgba.cc,
src/tgbatest/randtgba.cc: Update to use scc_info and/or tgba_digraph.
parent b6745482
...@@ -46,12 +46,10 @@ ...@@ -46,12 +46,10 @@
#include "ltlvisit/mutation.hh" #include "ltlvisit/mutation.hh"
#include "ltlvisit/relabel.hh" #include "ltlvisit/relabel.hh"
#include "tgbaalgos/lbtt.hh" #include "tgbaalgos/lbtt.hh"
#include "tgba/tgbaproduct.hh" #include "tgbaalgos/product.hh"
#include "tgbaalgos/gtec/gtec.hh" #include "tgbaalgos/gtec/gtec.hh"
#include "tgbaalgos/randomgraph.hh" #include "tgbaalgos/randomgraph.hh"
#include "tgbaalgos/sccinfo.hh" #include "tgbaalgos/sccinfo.hh"
#include "tgbaalgos/scc.hh"
#include "tgbaalgos/dotty.hh"
#include "tgbaalgos/isweakscc.hh" #include "tgbaalgos/isweakscc.hh"
#include "tgbaalgos/reducerun.hh" #include "tgbaalgos/reducerun.hh"
#include "tgbaalgos/word.hh" #include "tgbaalgos/word.hh"
...@@ -880,7 +878,7 @@ namespace ...@@ -880,7 +878,7 @@ namespace
string_to_tmp(string_ltl_wring, serial, filename_ltl_wring); string_to_tmp(string_ltl_wring, serial, filename_ltl_wring);
} }
spot::const_tgba_ptr spot::const_tgba_digraph_ptr
translate(unsigned int translator_num, char l, statistics_formula* fstats, translate(unsigned int translator_num, char l, statistics_formula* fstats,
bool& problem) bool& problem)
{ {
...@@ -900,7 +898,7 @@ namespace ...@@ -900,7 +898,7 @@ namespace
const char* status_str = 0; const char* status_str = 0;
spot::const_tgba_ptr res = 0; spot::const_tgba_digraph_ptr res = 0;
if (timed_out) if (timed_out)
{ {
// This is not considered to be a global error. // This is not considered to be a global error.
...@@ -1059,15 +1057,14 @@ namespace ...@@ -1059,15 +1057,14 @@ namespace
st->edges = s.transitions; st->edges = s.transitions;
st->transitions = s.sub_transitions; st->transitions = s.sub_transitions;
st->acc = res->acc().num_sets(); st->acc = res->acc().num_sets();
spot::scc_map m(res); spot::scc_info m(res);
m.build_map();
unsigned c = m.scc_count(); unsigned c = m.scc_count();
st->scc = c; st->scc = c;
st->nondetstates = spot::count_nondet_states(res); st->nondetstates = spot::count_nondet_states(res);
st->nondeterministic = st->nondetstates != 0; st->nondeterministic = st->nondetstates != 0;
for (unsigned n = 0; n < c; ++n) for (unsigned n = 0; n < c; ++n)
{ {
if (!m.accepting(n)) if (!m.is_accepting_scc(n))
++st->nonacc_scc; ++st->nonacc_scc;
else if (is_terminal_scc(m, n)) else if (is_terminal_scc(m, n))
++st->terminal_scc; ++st->terminal_scc;
...@@ -1090,8 +1087,8 @@ namespace ...@@ -1090,8 +1087,8 @@ namespace
}; };
static bool static bool
check_empty_prod(const spot::const_tgba_ptr& aut_i, check_empty_prod(const spot::const_tgba_digraph_ptr& aut_i,
const spot::const_tgba_ptr& aut_j, const spot::const_tgba_digraph_ptr& aut_j,
size_t i, size_t j, bool icomp, bool jcomp) size_t i, size_t j, bool icomp, bool jcomp)
{ {
auto prod = spot::product(aut_i, aut_j); auto prod = spot::product(aut_i, aut_j);
...@@ -1145,7 +1142,7 @@ namespace ...@@ -1145,7 +1142,7 @@ namespace
} }
static bool static bool
cross_check(const std::vector<spot::scc_map*>& maps, char l, unsigned p) cross_check(const std::vector<spot::scc_info*>& maps, char l, unsigned p)
{ {
size_t m = maps.size(); size_t m = maps.size();
if (verbose) if (verbose)
...@@ -1167,13 +1164,17 @@ namespace ...@@ -1167,13 +1164,17 @@ namespace
unsigned verified = 0; unsigned verified = 0;
unsigned violated = 0; unsigned violated = 0;
for (size_t i = 0; i < m; ++i) for (size_t i = 0; i < m; ++i)
if (spot::scc_map* m = maps[i]) if (spot::scc_info* m = maps[i])
{ {
// r == true iff the automaton i is accepting. // r == true iff the automaton i is accepting.
bool r = false; bool r = false;
unsigned c = m->scc_count(); unsigned c = m->scc_count();
for (unsigned j = 0; (j < c) && !r; ++j) for (unsigned j = 0; j < c; ++j)
r |= m->accepting(j); if (m->is_accepting_scc(j))
{
r = true;
break;
}
res[i] = r; res[i] = r;
if (r) if (r)
++verified; ++verified;
...@@ -1216,41 +1217,34 @@ namespace ...@@ -1216,41 +1217,34 @@ namespace
return false; return false;
} }
typedef std::set<spot::state*, spot::state_ptr_less_than> state_set; typedef std::set<unsigned> state_set;
// Collect all the states of SSPACE that appear in the accepting SCCs // Collect all the states of SSPACE that appear in the accepting SCCs
// of PROD. // of PROD. (Trivial SCCs are considered accepting.)
static void static void
states_in_acc(const spot::scc_map* m, states_in_acc(const spot::scc_info* m,
const spot::const_tgba_ptr& sspace,
state_set& s) state_set& s)
{ {
auto aut = m->get_aut(); auto aut = m->get_aut();
auto ps = static_cast<const spot::product_states*>
(aut->get_named_prop("product-states"));
unsigned c = m->scc_count(); unsigned c = m->scc_count();
for (unsigned n = 0; n < c; ++n) for (unsigned n = 0; n < c; ++n)
if (m->accepting(n)) if (m->is_accepting_scc(n) || m->is_trivial(n))
for (auto i: m->states_of(n)) for (auto i: m->states_of(n))
{ // Get the projection on sspace.
spot::state* x = aut->project_state(i, sspace); s.insert((*ps)[i].second);
assert(x);
if (!s.insert(x).second)
x->destroy();
}
} }
static bool static bool
consistency_check(const spot::scc_map* pos, const spot::scc_map* neg, consistency_check(const spot::scc_info* pos, const spot::scc_info* neg)
const spot::const_tgba_ptr& sspace)
{ {
// the states of SSPACE should appear in the accepting SCC of at // the states of SSPACE should appear in the accepting SCC of at
// least one of POS or NEG. Maybe both. // least one of POS or NEG. Maybe both.
state_set s; state_set s;
states_in_acc(pos, sspace, s); states_in_acc(pos, s);
states_in_acc(neg, sspace, s); states_in_acc(neg, s);
bool res = s.size() == states; return s.size() == states;
for (auto i: s)
i->destroy();
return res;
} }
typedef typedef
...@@ -1423,12 +1417,12 @@ namespace ...@@ -1423,12 +1417,12 @@ namespace
// These store the result of the translation of the positive and // These store the result of the translation of the positive and
// negative formulas. // negative formulas.
size_t m = translators.size(); size_t m = translators.size();
std::vector<spot::const_tgba_ptr> pos(m); std::vector<spot::const_tgba_digraph_ptr> pos(m);
std::vector<spot::const_tgba_ptr> neg(m); std::vector<spot::const_tgba_digraph_ptr> neg(m);
// These store the complement of the above results, when we can // These store the complement of the above results, when we can
// compute it easily. // compute it easily.
std::vector<spot::const_tgba_ptr> comp_pos(m); std::vector<spot::const_tgba_digraph_ptr> comp_pos(m);
std::vector<spot::const_tgba_ptr> comp_neg(m); std::vector<spot::const_tgba_digraph_ptr> comp_neg(m);
unsigned n = vstats.size(); unsigned n = vstats.size();
...@@ -1577,19 +1571,18 @@ namespace ...@@ -1577,19 +1571,18 @@ namespace
auto statespace = spot::random_graph(states, density, ap, dict); auto statespace = spot::random_graph(states, density, ap, dict);
// Products of the state space with the positive automata. // Products of the state space with the positive automata.
std::vector<spot::const_tgba_ptr> pos_prod(m); std::vector<spot::const_tgba_digraph_ptr> pos_prod(m);
// Products of the state space with the negative automata. // Products of the state space with the negative automata.
std::vector<spot::const_tgba_ptr> neg_prod(m); std::vector<spot::const_tgba_digraph_ptr> neg_prod(m);
// Associated SCC maps. // Associated SCC maps.
std::vector<spot::scc_map*> pos_map(m); std::vector<spot::scc_info*> pos_map(m);
std::vector<spot::scc_map*> neg_map(m); std::vector<spot::scc_info*> neg_map(m);
for (size_t i = 0; i < m; ++i) for (size_t i = 0; i < m; ++i)
if (pos[i]) if (pos[i])
{ {
auto p = spot::product(pos[i], statespace); auto p = spot::product(pos[i], statespace);
pos_prod[i] = p; pos_prod[i] = p;
spot::scc_map* sm = new spot::scc_map(p); auto sm = new spot::scc_info(p);
sm->build_map();
pos_map[i] = sm; pos_map[i] = sm;
// Statistics // Statistics
...@@ -1608,8 +1601,7 @@ namespace ...@@ -1608,8 +1601,7 @@ namespace
{ {
auto p = spot::product(neg[i], statespace); auto p = spot::product(neg[i], statespace);
neg_prod[i] = p; neg_prod[i] = p;
spot::scc_map* sm = new spot::scc_map(p); auto sm = new spot::scc_info(p);
sm->build_map();
neg_map[i] = sm; neg_map[i] = sm;
// Statistics // Statistics
...@@ -1636,8 +1628,7 @@ namespace ...@@ -1636,8 +1628,7 @@ namespace
std::cerr << "info: consistency_check (P" << i std::cerr << "info: consistency_check (P" << i
<< ",N" << i << "), state-space #" << ",N" << i << "), state-space #"
<< p << '/' << products << '\n'; << p << '/' << products << '\n';
if (!(consistency_check(pos_map[i], neg_map[i], if (!(consistency_check(pos_map[i], neg_map[i])))
statespace)))
{ {
++problems; ++problems;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "tgba.hh" #include "tgba.hh"
#include "tgbaalgos/gtec/gtec.hh" #include "tgbaalgos/gtec/gtec.hh"
#include <utility>
namespace spot namespace spot
{ {
...@@ -38,6 +39,10 @@ namespace spot ...@@ -38,6 +39,10 @@ namespace spot
if (last_support_conditions_input_) if (last_support_conditions_input_)
last_support_conditions_input_->destroy(); last_support_conditions_input_->destroy();
delete iter_cache_; delete iter_cache_;
// Destroy all named properties.
for (auto& np: named_prop_)
np.second.second(np.second.first);
} }
bdd bdd
...@@ -78,4 +83,30 @@ namespace spot ...@@ -78,4 +83,30 @@ namespace spot
return !couvreur99(shared_from_this())->check(); return !couvreur99(shared_from_this())->check();
} }
void
tgba::set_named_prop(std::string s,
void* val, std::function<void(void*)> destructor)
{
auto p = named_prop_.emplace(std::piecewise_construct,
std::forward_as_tuple(s),
std::forward_as_tuple(val, destructor));
if (!p.second)
{
p.first->second.second(p.first->second.first);
p.first->second = std::make_pair(val, destructor);
}
}
void*
tgba::get_named_prop(std::string s) const
{
auto i = named_prop_.find(s);
if (i == named_prop_.end())
return nullptr;
return i->second.first;
}
} }
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "acc.hh" #include "acc.hh"
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include <unordered_map>
#include <functional>
#include "misc/casts.hh" #include "misc/casts.hh"
#include "misc/hash.hh" #include "misc/hash.hh"
...@@ -657,8 +659,20 @@ namespace spot ...@@ -657,8 +659,20 @@ namespace spot
bprop is; bprop is;
}; };
#ifndef SWIG
// Dynamic properties, are given with a name and a destructor function.
std::unordered_map<std::string,
std::pair<void*,
std::function<void(void*)>>> named_prop_;
#endif
public: public:
#ifndef SWIG
void set_named_prop(std::string s,
void* val, std::function<void(void*)> destructor);
void* get_named_prop(std::string s) const;
#endif
bool has_single_acc_set() const bool has_single_acc_set() const
{ {
return is.single_acc_set; return is.single_acc_set;
......
...@@ -570,7 +570,7 @@ namespace spot ...@@ -570,7 +570,7 @@ namespace spot
{ {
public: public:
static safra_tree_automaton* static safra_tree_automaton*
create_safra_automaton(const const_tgba_ptr& a); create_safra_automaton(const const_tgba_digraph_ptr& a);
private: private:
typedef std::set<int> atomic_list_t; typedef std::set<int> atomic_list_t;
typedef std::set<bdd, bdd_less_than> conjunction_list_t; typedef std::set<bdd, bdd_less_than> conjunction_list_t;
...@@ -585,7 +585,8 @@ namespace spot ...@@ -585,7 +585,8 @@ namespace spot
/// \brief The body of Safra's construction. /// \brief The body of Safra's construction.
safra_tree_automaton* safra_tree_automaton*
safra_determinisation::create_safra_automaton(const const_tgba_ptr& a) safra_determinisation::create_safra_automaton
(const const_tgba_digraph_ptr& a)
{ {
// initialization. // initialization.
auto sba_aut = degeneralize(a); auto sba_aut = degeneralize(a);
...@@ -1074,7 +1075,7 @@ namespace spot ...@@ -1074,7 +1075,7 @@ namespace spot
// tgba_safra_complement // tgba_safra_complement
////////////////////////// //////////////////////////
tgba_safra_complement::tgba_safra_complement(const const_tgba_ptr& a) tgba_safra_complement::tgba_safra_complement(const const_tgba_digraph_ptr& a)
: tgba(a->get_dict()), automaton_(a), : tgba(a->get_dict()), automaton_(a),
safra_(safra_determinisation::create_safra_automaton(a)) safra_(safra_determinisation::create_safra_automaton(a))
{ {
......
...@@ -50,7 +50,7 @@ namespace spot ...@@ -50,7 +50,7 @@ namespace spot
class SPOT_API tgba_safra_complement : public tgba class SPOT_API tgba_safra_complement : public tgba
{ {
public: public:
tgba_safra_complement(const const_tgba_ptr& a); tgba_safra_complement(const const_tgba_digraph_ptr& a);
virtual ~tgba_safra_complement(); virtual ~tgba_safra_complement();
// tgba interface. // tgba interface.
...@@ -67,7 +67,7 @@ namespace spot ...@@ -67,7 +67,7 @@ namespace spot
protected: protected:
virtual bdd compute_support_conditions(const state* state) const; virtual bdd compute_support_conditions(const state* state) const;
private: private:
const_tgba_ptr automaton_; const_tgba_digraph_ptr automaton_;
void* safra_; void* safra_;
#if TRANSFORM_TO_TBA #if TRANSFORM_TO_TBA
acc_cond::mark_t the_acceptance_cond_; acc_cond::mark_t the_acceptance_cond_;
...@@ -82,7 +82,7 @@ namespace spot ...@@ -82,7 +82,7 @@ namespace spot
typedef std::shared_ptr<const tgba_safra_complement> typedef std::shared_ptr<const tgba_safra_complement>
const_tgba_safra_complement_ptr; const_tgba_safra_complement_ptr;
inline tgba_safra_complement_ptr inline tgba_safra_complement_ptr
make_safra_complement(const const_tgba_ptr& a) make_safra_complement(const const_tgba_digraph_ptr& a)
{ {
return std::make_shared<tgba_safra_complement>(a); return std::make_shared<tgba_safra_complement>(a);
} }
......
...@@ -53,6 +53,7 @@ tgbaalgos_HEADERS = \ ...@@ -53,6 +53,7 @@ tgbaalgos_HEADERS = \
neverclaim.hh \ neverclaim.hh \
postproc.hh \ postproc.hh \
powerset.hh \ powerset.hh \
product.hh \
projrun.hh \ projrun.hh \
randomgraph.hh \ randomgraph.hh \
reachiter.hh \ reachiter.hh \
...@@ -100,6 +101,7 @@ libtgbaalgos_la_SOURCES = \ ...@@ -100,6 +101,7 @@ libtgbaalgos_la_SOURCES = \
neverclaim.cc \ neverclaim.cc \
postproc.cc \ postproc.cc \
powerset.cc \ powerset.cc \
product.cc \
projrun.cc \ projrun.cc \
randomgraph.cc \ randomgraph.cc \
reachiter.cc \ reachiter.cc \
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
namespace spot namespace spot
{ {
enumerate_cycles::enumerate_cycles(const scc_map& map) enumerate_cycles::enumerate_cycles(const scc_info& map)
: aut_(map.get_aut()), sm_(map) : aut_(map.get_aut()), sm_(map)
{ {
} }
...@@ -84,12 +84,13 @@ namespace spot ...@@ -84,12 +84,13 @@ namespace spot
dfs_.push_back(e); dfs_.push_back(e);
} }
// FIXME: Recode this algorithm using unsigned states.
void void
enumerate_cycles::run(unsigned scc) enumerate_cycles::run(unsigned scc)
{ {
bool keep_going = true; bool keep_going = true;
push_state(tag_state(sm_.one_state_of(scc)->clone())); push_state(tag_state(aut_->state_from_number(sm_.one_state_of(scc))));
while (keep_going && !dfs_.empty()) while (keep_going && !dfs_.empty())
{ {
...@@ -109,7 +110,7 @@ namespace spot ...@@ -109,7 +110,7 @@ namespace spot
// Ignore those that are not on the SCC, or destination // Ignore those that are not on the SCC, or destination
// that have been "virtually" deleted from A(v). // that have been "virtually" deleted from A(v).
state* s = cur.succ->current_state(); state* s = cur.succ->current_state();
if ((sm_.scc_of_state(s) != scc) if ((sm_.scc_of(aut_->state_number(s)) != scc)
|| (cur.ts->second.del.find(s) != cur.ts->second.del.end())) || (cur.ts->second.del.find(s) != cur.ts->second.del.end()))
{ {
s->destroy(); s->destroy();
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#ifndef SPOT_TGBAALGOS_CYCLES_HH #ifndef SPOT_TGBAALGOS_CYCLES_HH
# define SPOT_TGBAALGOS_CYCLES_HH # define SPOT_TGBAALGOS_CYCLES_HH
#include "scc.hh" #include "sccinfo.hh"
#include "misc/hash.hh" #include "misc/hash.hh"
#include <deque> #include <deque>
...@@ -62,13 +62,11 @@ namespace spot ...@@ -62,13 +62,11 @@ namespace spot
/// dfs_ stack. Only the last portion of this stack may form a /// dfs_ stack. Only the last portion of this stack may form a
/// cycle. /// cycle.
/// ///
/// The class constructor takes an scc_map that should already have /// Calling <code>run(n)</code> will enumerate all elementary cycles
/// been built for its automaton. Calling <code>run(n)</code> will /// in SCC <code>n</code>. Each time an SCC is found, the method
/// enumerate all elementary cycles in SCC <code>n</code>. Each /// cycle_found(s) is called with the initial state s of the cycle:
/// time an SCC is found, the method cycle_found(s) is called with /// the cycle is constituted from all the states that are on the \c
/// the initial state s of the cycle: the cycle is constituted from /// dfs_ stack after \c s (including \c s).
/// all the states that are on the \c dfs_ stack after \c s
/// (including \c s).
/// ///
/// You should inherit from this class and redefine the /// You should inherit from this class and redefine the
/// cycle_found() method to perform any work you would like to do on /// cycle_found() method to perform any work you would like to do on
...@@ -112,9 +110,9 @@ namespace spot ...@@ -112,9 +110,9 @@ namespace spot
typedef hash_type::iterator tagged_state; typedef hash_type::iterator tagged_state;
// The automaton we are working on. // The automaton we are working on.
const_tgba_ptr aut_; const_tgba_digraph_ptr aut_;
// The SCC map built for aut_. // The SCC map built for aut_.
const scc_map& sm_; const scc_info& sm_;
// The DFS stack. Each entry contains a tagged state, an iterator // The DFS stack. Each entry contains a tagged state, an iterator
// on the transitions leaving that state, and a Boolean f // on the transitions leaving that state, and a Boolean f
...@@ -131,7 +129,7 @@ namespace spot ...@@ -131,7 +129,7 @@ namespace spot
dfs_stack dfs_; dfs_stack dfs_;
public: public:
enumerate_cycles(const scc_map& map); enumerate_cycles(const scc_info& map);
virtual ~enumerate_cycles() {} virtual ~enumerate_cycles() {}
/// \brief Run in SCC scc, and call \a cycle_found() for any new /// \brief Run in SCC scc, and call \a cycle_found() for any new
......