tgba_digraph: add a copy constructor, and obsolete dupexp

* src/tgba/tgbagraph.hh, src/tgba/tgbagraph.cc: Add a copy constructor,
and some method to purge unreachable states.
* src/graph/graph.hh (defrag_states): Erase transition of removed
states.
* src/tgbaalgos/complete.cc, src/tgbaalgos/compsusp.cc,
src/tgbaalgos/dtgbacomp.cc, src/tgbaalgos/simulation.cc,
src/tgbatest/checkpsl.cc, src/tgbatest/emptchk.cc,
src/tgbatest/ltl2tgba.cc: Adjust to use make_tgba_digraph() instead
of tgba_dupexp_dfs() or tgba_dupexp_bfs().
* src/tgbaalgos/dupexp.cc, src/tgbaalgos/dupexp.hh: Use
make_tgba_digraph() when possible.
* src/tgbatest/det.test, src/tgbatest/sim.test: Adjust expected results.
This commit is contained in:
Alexandre Duret-Lutz 2014-10-28 18:47:19 +01:00
parent 971788fdbe
commit 923785f76a
14 changed files with 128 additions and 27 deletions

View file

@ -656,8 +656,18 @@ namespace spot
for (state s = 0; s < send; ++s) for (state s = 0; s < send; ++s)
{ {
state dst = newst[s]; state dst = newst[s];
if (dst == s || dst == -1U) if (dst == s)
continue; continue;
if (dst == -1U)
{
// This is an erased state. Mark all its transitions as
// dead (i.e., t.next_succ should point to t for each of
// them).
auto t = states_[s].succ;
while (t)
std::swap(t, transitions_[t].next_succ);
continue;
}
states_[dst] = std::move(states_[s]); states_[dst] = std::move(states_[s]);
} }
states_.resize(used_states); states_.resize(used_states);

View file

@ -62,6 +62,40 @@ namespace spot
g_.defrag(); g_.defrag();
} }
void tgba_digraph::purge_unreachable_states()
{
unsigned num_states = g_.num_states();
if (num_states == 0)
return;
std::vector<unsigned> seen(num_states, 0);
std::vector<unsigned> todo;
todo.reserve(num_states);
todo.push_back(init_number_);
seen[init_number_] = 1;
auto todo_pos = todo.begin();
while (todo_pos != todo.end())
{
for (auto& t: g_.out(*todo_pos))
if (!seen[t.dst])
{
seen[t.dst] = 1;
todo.push_back(t.dst);
}
++todo_pos;
}
// Now renumber each used state.
unsigned current = 0;
for (auto& v: seen)
if (!v)
v = -1U;
else
v = current++;
if (current == seen.size())
return; // No useless state.
init_number_ = seen[init_number_];
g_.defrag_states(std::move(seen), current);
}
void tgba_digraph::purge_dead_states() void tgba_digraph::purge_dead_states()
{ {
unsigned num_states = g_.num_states(); unsigned num_states = g_.num_states();

View file

@ -25,6 +25,7 @@
#include "graph/ngraph.hh" #include "graph/ngraph.hh"
#include "tgba/bdddict.hh" #include "tgba/bdddict.hh"
#include "tgba/tgba.hh" #include "tgba/tgba.hh"
#include "tgbaalgos/dupexp.hh"
#include "misc/bddop.hh" #include "misc/bddop.hh"
#include <sstream> #include <sstream>
@ -170,6 +171,14 @@ namespace spot
{ {
} }
explicit tgba_digraph(const const_tgba_digraph_ptr& other)
: tgba(other->get_dict()),
g_(other->g_), init_number_(other->init_number_)
{
copy_acceptance_conditions_of(other);
copy_ap_of(other);
}
virtual ~tgba_digraph() virtual ~tgba_digraph()
{ {
get_dict()->unregister_all_my_variables(this); get_dict()->unregister_all_my_variables(this);
@ -228,7 +237,7 @@ namespace spot
set_init_state(state_number(s)); set_init_state(state_number(s));
} }
virtual graph_t::state get_init_state_number() const graph_t::state get_init_state_number() const
{ {
if (num_states() == 0) if (num_states() == 0)
const_cast<graph_t&>(g_).new_state(); const_cast<graph_t&>(g_).new_state();
@ -391,6 +400,9 @@ namespace spot
/// Remove all states without successors. /// Remove all states without successors.
void purge_dead_states(); void purge_dead_states();
/// Remove all unreachable states.
void purge_unreachable_states();
bool state_is_accepting(unsigned s) const bool state_is_accepting(unsigned s) const
{ {
assert(has_state_based_acc()); assert(has_state_based_acc());
@ -412,6 +424,21 @@ namespace spot
{ {
return std::make_shared<tgba_digraph>(dict); return std::make_shared<tgba_digraph>(dict);
} }
inline tgba_digraph_ptr make_tgba_digraph(const const_tgba_digraph_ptr& aut)
{
return std::make_shared<tgba_digraph>(aut);
}
inline tgba_digraph_ptr make_tgba_digraph(const const_tgba_ptr& aut)
{
auto p = std::dynamic_pointer_cast<const tgba_digraph>(aut);
if (p)
return std::make_shared<tgba_digraph>(p);
else
return tgba_dupexp_dfs(aut);
}
} }
#endif // SPOT_TGBA_TGBAGRAPH_HH #endif // SPOT_TGBA_TGBAGRAPH_HH

View file

@ -18,7 +18,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "complete.hh" #include "complete.hh"
#include "dupexp.hh"
namespace spot namespace spot
{ {
@ -105,7 +104,12 @@ namespace spot
tgba_digraph_ptr tgba_complete(const const_tgba_ptr& aut) tgba_digraph_ptr tgba_complete(const const_tgba_ptr& aut)
{ {
tgba_digraph_ptr res = tgba_dupexp_dfs(aut); auto res = make_tgba_digraph(aut);
res->prop_copy(aut,
true, // state based
true, // single acc
true, // inherently_weak
true); // deterministic
tgba_complete_here(res); tgba_complete_here(res);
return res; return res;
} }

View file

@ -25,7 +25,6 @@
#include "minimize.hh" #include "minimize.hh"
#include "simulation.hh" #include "simulation.hh"
#include "safety.hh" #include "safety.hh"
#include "dupexp.hh"
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
#include "ltlvisit/tostring.hh" #include "ltlvisit/tostring.hh"
#include "ltlvisit/clone.hh" #include "ltlvisit/clone.hh"

View file

@ -18,7 +18,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dtgbacomp.hh" #include "dtgbacomp.hh"
#include "dupexp.hh"
#include "sccinfo.hh" #include "sccinfo.hh"
namespace spot namespace spot
@ -26,9 +25,12 @@ namespace spot
tgba_digraph_ptr dtgba_complement_nonweak(const const_tgba_ptr& aut) tgba_digraph_ptr dtgba_complement_nonweak(const const_tgba_ptr& aut)
{ {
// Clone the original automaton. // Clone the original automaton.
tgba_digraph_ptr res = tgba_dupexp_dfs(aut); auto res = make_tgba_digraph(aut);
res->prop_copy(aut,
false, // state based
false, // single acc
false, // inherently_weak
false); // deterministic
// Copy the old acceptance condition before we replace it. // Copy the old acceptance condition before we replace it.
acc_cond oldacc = aut->acc(); // Copy it! acc_cond oldacc = aut->acc(); // Copy it!
@ -36,6 +38,9 @@ namespace spot
// automaton will only have one acceptance set. // automaton will only have one acceptance set.
// This changes aut->acc(); // This changes aut->acc();
res->set_single_acceptance_set(); res->set_single_acceptance_set();
// The resulting automaton is weak.
res->prop_inherently_weak();
res->prop_state_based_acc();
unsigned num_sets = oldacc.num_sets(); unsigned num_sets = oldacc.num_sets();
unsigned n = res->num_states(); unsigned n = res->num_states();
@ -108,8 +113,7 @@ namespace spot
tgba_digraph_ptr dtgba_complement_weak(const const_tgba_ptr& aut) tgba_digraph_ptr dtgba_complement_weak(const const_tgba_ptr& aut)
{ {
// Clone the original automaton. // Clone the original automaton.
tgba_digraph_ptr res = tgba_dupexp_dfs(aut); auto res = make_tgba_digraph(aut);
res->prop_copy(aut, res->prop_copy(aut,
true, // state based true, // state based
true, // single acc true, // single acc

View file

@ -21,10 +21,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dupexp.hh" #include "dupexp.hh"
#include "tgba/tgbagraph.hh"
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <map> #include <map>
#include "reachiter.hh" #include "reachiter.hh"
#include "dotty.hh"
namespace spot namespace spot
{ {
@ -119,6 +121,20 @@ namespace spot
tgba_digraph_ptr tgba_digraph_ptr
tgba_dupexp_dfs(const const_tgba_ptr& aut, std::vector<const state*>& rel) tgba_dupexp_dfs(const const_tgba_ptr& aut, std::vector<const state*>& rel)
{ {
auto aa = std::dynamic_pointer_cast<const spot::tgba_digraph>(aut);
if (aa)
{
aa->get_init_state_number(); // Create an initial state if needed.
auto res = make_tgba_digraph(aa);
unsigned ns = aa->num_states();
rel.reserve(ns);
// The state numbers are common to both automata, but
// the state pointers are to the older one.
for (unsigned n = 0; n < ns; ++n)
rel.push_back(aa->state_from_number(n));
return res;
}
dupexp_iter_save<tgba_reachable_iterator_depth_first> di(aut, rel); dupexp_iter_save<tgba_reachable_iterator_depth_first> di(aut, rel);
di.run(); di.run();
return di.result(); return di.result();

View file

@ -23,7 +23,10 @@
#ifndef SPOT_TGBAALGOS_DUPEXP_HH #ifndef SPOT_TGBAALGOS_DUPEXP_HH
# define SPOT_TGBAALGOS_DUPEXP_HH # define SPOT_TGBAALGOS_DUPEXP_HH
# include "tgba/tgbagraph.hh" # include "misc/common.hh"
# include "tgba/fwd.hh"
# include "tgba/tgba.hh"
# include <vector>
namespace spot namespace spot
{ {

View file

@ -256,7 +256,6 @@ namespace spot
scc_info_.reset(new scc_info(a_)); scc_info_.reset(new scc_info(a_));
old_a_ = a_; old_a_ = a_;
// Replace all the acceptance conditions by their complements. // Replace all the acceptance conditions by their complements.
// (In the case of Cosimulation, we also flip the transitions.) // (In the case of Cosimulation, we also flip the transitions.)
{ {
@ -298,6 +297,8 @@ namespace spot
else else
t.acc = acc; t.acc = acc;
} }
if (Cosimulation)
a_->set_init_state(old_a_->get_init_state_number());
} }
size_a_ = ns; size_a_ = ns;
} }
@ -435,7 +436,7 @@ namespace spot
// When we Cosimulate, we add a special flag to differentiate // When we Cosimulate, we add a special flag to differentiate
// the initial state from the other. // the initial state from the other.
if (Cosimulation && src == 0) if (Cosimulation && src == a_->get_init_state_number())
res |= bdd_initial; res |= bdd_initial;
return res; return res;
@ -696,6 +697,8 @@ namespace spot
} }
} }
res->purge_unreachable_states();
delete gb; delete gb;
res->prop_copy(original_, res->prop_copy(original_,
false, // state-based acc forced below false, // state-based acc forced below
@ -835,6 +838,8 @@ namespace spot
bdd res = bddfalse; bdd res = bddfalse;
unsigned scc = scc_info_->scc_of(src); unsigned scc = scc_info_->scc_of(src);
if (scc == -1U) // Unreachable
return bddfalse;
bool sccacc = scc_info_->is_accepting_scc(scc); bool sccacc = scc_info_->is_accepting_scc(scc);
for (auto& t: a_->out(src)) for (auto& t: a_->out(src))
@ -1353,12 +1358,13 @@ namespace spot
direct_simulation<true, Sba> cosimul(res); direct_simulation<true, Sba> cosimul(res);
res = cosimul.run(); res = cosimul.run();
next.set_size(res);
if (Sba) if (Sba)
res = scc_filter_states(res); res = scc_filter_states(res);
else else
res = scc_filter(res, false); res = scc_filter(res, false);
next.set_size(res);
} }
while (prev != next); while (prev != next);
return res; return res;

View file

@ -29,7 +29,6 @@
#include "tgbaalgos/sccfilter.hh" #include "tgbaalgos/sccfilter.hh"
#include "tgba/tgbaproduct.hh" #include "tgba/tgbaproduct.hh"
#include "tgbaalgos/dotty.hh" #include "tgbaalgos/dotty.hh"
#include "tgbaalgos/dupexp.hh"
void void
syntax(char* prog) syntax(char* prog)
@ -93,8 +92,8 @@ main(int argc, char** argv)
if (fpos->is_ltl_formula()) if (fpos->is_ltl_formula())
{ {
auto apos = scc_filter(spot::tgba_dupexp_dfs(ltl_to_taa(fpos, d))); auto apos = scc_filter(make_tgba_digraph(ltl_to_taa(fpos, d)));
auto aneg = scc_filter(spot::tgba_dupexp_dfs(ltl_to_taa(fneg, d))); auto aneg = scc_filter(make_tgba_digraph(ltl_to_taa(fneg, d)));
if (!spot::product(apos, aneg)->is_empty()) if (!spot::product(apos, aneg)->is_empty())
{ {
std::cerr << "non-empty intersection between pos and neg (TAA)\n"; std::cerr << "non-empty intersection between pos and neg (TAA)\n";

View file

@ -103,9 +103,9 @@ digraph G {
2 -> 2 [label="1"] 2 -> 2 [label="1"]
2 -> 3 [label="!a"] 2 -> 3 [label="!a"]
2 -> 4 [label="!b"] 2 -> 4 [label="!b"]
3 [label="3"] 3 [label="3", peripheries=2]
3 -> 3 [label="!a\n{0}"] 3 -> 3 [label="!a\n{0}"]
4 [label="4"] 4 [label="4", peripheries=2]
4 -> 4 [label="!b\n{0}"] 4 -> 4 [label="!b\n{0}"]
} }
EOF EOF

View file

@ -31,7 +31,6 @@
#include "tgba/tgbaproduct.hh" #include "tgba/tgbaproduct.hh"
#include "tgbaalgos/gtec/gtec.hh" #include "tgbaalgos/gtec/gtec.hh"
#include "tgbaalgos/dotty.hh" #include "tgbaalgos/dotty.hh"
#include "tgbaalgos/dupexp.hh"
#include "tgbaalgos/emptiness.hh" #include "tgbaalgos/emptiness.hh"
void void
@ -103,7 +102,7 @@ main(int argc, char** argv)
{ {
auto a = spot::ltl_to_taa(f, d); auto a = spot::ltl_to_taa(f, d);
aut[0] = a; aut[0] = a;
aut[1] = spot::degeneralize_tba(spot::tgba_dupexp_bfs(a)); aut[1] = spot::degeneralize_tba(spot::make_tgba_digraph(a));
} }
{ {
auto a = spot::ltl_to_tgba_fm(f, d); auto a = spot::ltl_to_tgba_fm(f, d);

View file

@ -324,7 +324,7 @@ spot::tgba_digraph_ptr ensure_digraph(const spot::tgba_ptr& a)
auto aa = std::dynamic_pointer_cast<spot::tgba_digraph>(a); auto aa = std::dynamic_pointer_cast<spot::tgba_digraph>(a);
if (aa) if (aa)
return aa; return aa;
return spot::tgba_dupexp_dfs(a); return spot::make_tgba_digraph(a);
} }
int int

View file

@ -35,8 +35,8 @@ run 0 ../ltl2tgba -X -RDCS -b in.tgba > out.tgba
cat >expected.tgba <<EOF cat >expected.tgba <<EOF
acc = "0"; acc = "0";
"0", "3", "b",; "0", "1", "b",;
"3", "3", "a", "0"; "1", "1", "a", "0";
EOF EOF
diff out.tgba expected.tgba diff out.tgba expected.tgba
@ -44,8 +44,8 @@ diff out.tgba expected.tgba
run 0 ../ltl2tgba -RDCIS -b XXXXGFa > out.tgba run 0 ../ltl2tgba -RDCIS -b XXXXGFa > out.tgba
cat >expected.tgba <<EOF cat >expected.tgba <<EOF
acc = "a"; acc = "0";
"0", "0", "a", "a"; "0", "0", "a", "0";
"0", "0", "!a",; "0", "0", "!a",;
EOF EOF