Automatic mass renaming. * src/graphtest/tgbagraph.cc, src/tgba/acc.cc, src/tgba/acc.hh, src/tgba/bdddict.cc, src/tgba/bdddict.hh, src/tgba/bddprint.cc, src/tgba/bddprint.hh, src/tgba/formula2bdd.cc, src/tgba/formula2bdd.hh, src/tgba/fwd.hh, src/tgba/Makefile.am, src/tgba/taatgba.cc, src/tgba/taatgba.hh, src/tgba/tgba.cc, src/tgba/tgbagraph.cc, src/tgba/tgbagraph.hh, src/tgba/tgba.hh, src/tgba/tgbamask.cc, src/tgba/tgbamask.hh, src/tgba/tgbaproduct.cc, src/tgba/tgbaproduct.hh, src/tgba/tgbaproxy.cc, src/tgba/tgbaproxy.hh, src/tgba/tgbasafracomplement.cc, src/tgba/tgbasafracomplement.hh, src/tgba/.cvsignore: Rename as... * src/graphtest/twagraph.cc, src/twa/acc.cc, src/twa/acc.hh, src/twa/bdddict.cc, src/twa/bdddict.hh, src/twa/bddprint.cc, src/twa/bddprint.hh, src/twa/formula2bdd.cc, src/twa/formula2bdd.hh, src/twa/fwd.hh, src/twa/Makefile.am, src/twa/taatgba.cc, src/twa/taatgba.hh, src/twa/twa.cc, src/twa/twagraph.cc, src/twa/twagraph.hh, src/twa/twa.hh, src/twa/twamask.cc, src/twa/twamask.hh, src/twa/twaproduct.cc, src/twa/twaproduct.hh, src/twa/twaproxy.cc, src/twa/twaproxy.hh, src/twa/twasafracomplement.cc, src/twa/twasafracomplement.hh, src/twa/.cvsignore: ... these. * README, bench/stutter/stutter_invariance_randomgraph.cc, configure.ac, iface/ltsmin/modelcheck.cc, src/Makefile.am, src/bin/common_aoutput.cc, src/bin/common_conv.hh, src/bin/common_trans.hh, src/bin/dstar2tgba.cc, src/bin/ltl2tgta.cc, src/bin/randaut.cc, src/dstarparse/dra2ba.cc, src/dstarparse/public.hh, src/graphtest/Makefile.am, src/graphtest/ngraph.cc, src/hoaparse/hoaparse.yy, src/hoaparse/public.hh, src/kripke/fairkripke.hh, src/kripke/kripkeexplicit.cc, src/kripke/kripkeprint.cc, src/kripkeparse/kripkeparse.yy, src/ltlvisit/apcollect.cc, src/ltlvisit/apcollect.hh, src/ltlvisit/exclusive.hh, src/ltlvisit/simplify.cc, src/ltlvisit/simplify.hh, src/priv/accmap.hh, src/ta/ta.hh, src/ta/taexplicit.cc, src/ta/taexplicit.hh, src/ta/tgta.hh, src/ta/tgtaexplicit.cc, src/ta/tgtaexplicit.hh, src/ta/tgtaproduct.hh, src/taalgos/dotty.cc, src/taalgos/emptinessta.cc, src/taalgos/minimize.cc, src/taalgos/tgba2ta.cc, src/taalgos/tgba2ta.hh, src/tgbaalgos/are_isomorphic.cc, src/tgbaalgos/are_isomorphic.hh, src/tgbaalgos/bfssteps.cc, src/tgbaalgos/canonicalize.cc, src/tgbaalgos/canonicalize.hh, src/tgbaalgos/cleanacc.hh, src/tgbaalgos/complete.hh, src/tgbaalgos/compsusp.cc, src/tgbaalgos/compsusp.hh, src/tgbaalgos/degen.cc, src/tgbaalgos/degen.hh, src/tgbaalgos/dotty.cc, src/tgbaalgos/dotty.hh, src/tgbaalgos/dtbasat.cc, src/tgbaalgos/dtbasat.hh, src/tgbaalgos/dtgbacomp.hh, src/tgbaalgos/dtgbasat.cc, src/tgbaalgos/dtgbasat.hh, src/tgbaalgos/dupexp.cc, src/tgbaalgos/dupexp.hh, src/tgbaalgos/emptiness.cc, src/tgbaalgos/emptiness.hh, src/tgbaalgos/gtec/sccstack.hh, src/tgbaalgos/gtec/status.hh, src/tgbaalgos/gv04.cc, src/tgbaalgos/gv04.hh, src/tgbaalgos/hoa.cc, src/tgbaalgos/hoa.hh, src/tgbaalgos/isdet.hh, src/tgbaalgos/lbtt.cc, src/tgbaalgos/lbtt.hh, src/tgbaalgos/ltl2taa.hh, src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/ltl2tgba_fm.hh, src/tgbaalgos/magic.cc, src/tgbaalgos/magic.hh, src/tgbaalgos/mask.hh, src/tgbaalgos/minimize.hh, src/tgbaalgos/ndfs_result.hxx, src/tgbaalgos/neverclaim.cc, src/tgbaalgos/neverclaim.hh, src/tgbaalgos/postproc.hh, src/tgbaalgos/powerset.cc, src/tgbaalgos/powerset.hh, src/tgbaalgos/product.cc, src/tgbaalgos/product.hh, src/tgbaalgos/projrun.cc, src/tgbaalgos/projrun.hh, src/tgbaalgos/randomgraph.cc, src/tgbaalgos/randomgraph.hh, src/tgbaalgos/randomize.hh, src/tgbaalgos/reachiter.hh, src/tgbaalgos/reducerun.cc, src/tgbaalgos/reducerun.hh, src/tgbaalgos/relabel.hh, src/tgbaalgos/remfin.hh, src/tgbaalgos/remprop.hh, src/tgbaalgos/replayrun.cc, src/tgbaalgos/replayrun.hh, src/tgbaalgos/sbacc.hh, src/tgbaalgos/scc.cc, src/tgbaalgos/scc.hh, src/tgbaalgos/sccfilter.hh, src/tgbaalgos/sccinfo.cc, src/tgbaalgos/sccinfo.hh, src/tgbaalgos/se05.cc, src/tgbaalgos/se05.hh, src/tgbaalgos/simulation.cc, src/tgbaalgos/simulation.hh, src/tgbaalgos/stats.cc, src/tgbaalgos/stats.hh, src/tgbaalgos/stripacc.hh, src/tgbaalgos/stutter.cc, src/tgbaalgos/stutter.hh, src/tgbaalgos/tau03.cc, src/tgbaalgos/tau03.hh, src/tgbaalgos/tau03opt.cc, src/tgbaalgos/tau03opt.hh, src/tgbaalgos/totgba.cc, src/tgbaalgos/totgba.hh, src/tgbaalgos/weight.hh, src/tgbaalgos/word.cc, src/tgbatest/acc.cc, src/tgbatest/complementation.cc, src/tgbatest/emptchk.cc, src/tgbatest/ltl2tgba.cc, src/tgbatest/taatgba.cc, wrap/python/spot_impl.i: Adjust.
251 lines
6.6 KiB
C++
251 lines
6.6 KiB
C++
// -*- coding: utf-8 -*-
|
|
// Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement de
|
|
// l'Epita.
|
|
//
|
|
// This file is part of Spot, a model checking library.
|
|
//
|
|
// Spot is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
// License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "twagraph.hh"
|
|
#include "ltlast/constant.hh"
|
|
|
|
namespace spot
|
|
{
|
|
|
|
void twa_graph::merge_transitions()
|
|
{
|
|
g_.remove_dead_transitions_();
|
|
|
|
typedef graph_t::trans_storage_t tr_t;
|
|
g_.sort_transitions_([](const tr_t& lhs, const tr_t& rhs)
|
|
{
|
|
if (lhs.src < rhs.src)
|
|
return true;
|
|
if (lhs.src > rhs.src)
|
|
return false;
|
|
if (lhs.dst < rhs.dst)
|
|
return true;
|
|
if (lhs.dst > rhs.dst)
|
|
return false;
|
|
return lhs.acc < rhs.acc;
|
|
// Do not sort on conditions, we'll merge
|
|
// them.
|
|
});
|
|
|
|
auto& trans = this->transition_vector();
|
|
unsigned tend = trans.size();
|
|
unsigned out = 0;
|
|
unsigned in = 1;
|
|
// Skip any leading false transition.
|
|
while (in < tend && trans[in].cond == bddfalse)
|
|
++in;
|
|
if (in < tend)
|
|
{
|
|
++out;
|
|
if (out != in)
|
|
trans[out] = trans[in];
|
|
for (++in; in < tend; ++in)
|
|
{
|
|
if (trans[in].cond == bddfalse) // Unusable transition
|
|
continue;
|
|
// Merge transitions with the same source, destination, and
|
|
// acceptance. (We test the source last, because this is the
|
|
// most likely test to be true as transitions are ordered by
|
|
// sources and then destinations.)
|
|
if (trans[out].dst == trans[in].dst
|
|
&& trans[out].acc == trans[in].acc
|
|
&& trans[out].src == trans[in].src)
|
|
{
|
|
trans[out].cond |= trans[in].cond;
|
|
}
|
|
else
|
|
{
|
|
++out;
|
|
if (in != out)
|
|
trans[out] = trans[in];
|
|
}
|
|
}
|
|
}
|
|
if (++out != tend)
|
|
trans.resize(out);
|
|
|
|
tend = out;
|
|
out = in = 2;
|
|
|
|
// FIXME: We could should also merge transitions when using
|
|
// fin_acceptance, but the rule for Fin sets are different than
|
|
// those for Inf sets, (and we need to be careful if a set is used
|
|
// both as Inf and Fin)
|
|
if ((in < tend) && !acc().uses_fin_acceptance())
|
|
{
|
|
typedef graph_t::trans_storage_t tr_t;
|
|
g_.sort_transitions_([](const tr_t& lhs, const tr_t& rhs)
|
|
{
|
|
if (lhs.src < rhs.src)
|
|
return true;
|
|
if (lhs.src > rhs.src)
|
|
return false;
|
|
if (lhs.dst < rhs.dst)
|
|
return true;
|
|
if (lhs.dst > rhs.dst)
|
|
return false;
|
|
return lhs.cond.id() < rhs.cond.id();
|
|
// Do not sort on acceptance, we'll merge
|
|
// them.
|
|
});
|
|
|
|
for (; in < tend; ++in)
|
|
{
|
|
// Merge transitions with the same source, destination,
|
|
// and conditions. (We test the source last, for the
|
|
// same reason as above.)
|
|
if (trans[out].dst == trans[in].dst
|
|
&& trans[out].cond.id() == trans[in].cond.id()
|
|
&& trans[out].src == trans[in].src)
|
|
{
|
|
trans[out].acc |= trans[in].acc;
|
|
}
|
|
else
|
|
{
|
|
++out;
|
|
if (in != out)
|
|
trans[out] = trans[in];
|
|
}
|
|
}
|
|
if (++out != tend)
|
|
trans.resize(out);
|
|
}
|
|
|
|
g_.chain_transitions_();
|
|
}
|
|
|
|
void twa_graph::purge_unreachable_states()
|
|
{
|
|
unsigned num_states = g_.num_states();
|
|
if (SPOT_UNLIKELY(num_states == 0))
|
|
return;
|
|
// The TODO vector serves two purposes:
|
|
// - it is a stack of state to process,
|
|
// - it is a set of processed states.
|
|
// The lower 31 bits of each entry is a state on the stack. (The
|
|
// next usable entry on the stack is indicated by todo_pos.) The
|
|
// 32th bit (i.e., the sign bit) of todo[x] indicates whether
|
|
// states number x has been seen.
|
|
std::vector<unsigned> todo(num_states, 0);
|
|
const unsigned seen = 1 << (sizeof(unsigned)*8-1);
|
|
const unsigned mask = seen - 1;
|
|
todo[0] = init_number_;
|
|
todo[init_number_] |= seen;
|
|
unsigned todo_pos = 1;
|
|
do
|
|
{
|
|
unsigned cur = todo[--todo_pos] & mask;
|
|
todo[todo_pos] ^= cur; // Zero the state
|
|
for (auto& t: g_.out(cur))
|
|
if (!(todo[t.dst] & seen))
|
|
{
|
|
todo[t.dst] |= seen;
|
|
todo[todo_pos++] |= t.dst;
|
|
}
|
|
}
|
|
while (todo_pos > 0);
|
|
// Now renumber each used state.
|
|
unsigned current = 0;
|
|
for (auto& v: todo)
|
|
if (!(v & seen))
|
|
v = -1U;
|
|
else
|
|
v = current++;
|
|
if (current == todo.size())
|
|
return; // No unreachable state.
|
|
init_number_ = todo[init_number_];
|
|
g_.defrag_states(std::move(todo), current);
|
|
}
|
|
|
|
void twa_graph::purge_dead_states()
|
|
{
|
|
unsigned num_states = g_.num_states();
|
|
if (num_states == 0)
|
|
return;
|
|
|
|
std::vector<unsigned> useful(num_states, 0);
|
|
|
|
// Make a DFS to compute a topological order.
|
|
std::vector<unsigned> order;
|
|
order.reserve(num_states);
|
|
std::vector<std::pair<unsigned, unsigned>> todo; // state, trans
|
|
useful[init_number_] = 1;
|
|
todo.emplace_back(init_number_, g_.state_storage(init_number_).succ);
|
|
do
|
|
{
|
|
unsigned src;
|
|
unsigned tid;
|
|
std::tie(src, tid) = todo.back();
|
|
if (tid == 0U)
|
|
{
|
|
todo.pop_back();
|
|
order.push_back(src);
|
|
continue;
|
|
}
|
|
auto& t = g_.trans_storage(tid);
|
|
todo.back().second = t.next_succ;
|
|
unsigned dst = t.dst;
|
|
if (useful[dst] != 1)
|
|
{
|
|
todo.emplace_back(dst, g_.state_storage(dst).succ);
|
|
useful[dst] = 1;
|
|
}
|
|
}
|
|
while (!todo.empty());
|
|
|
|
// Process states in topological order
|
|
for (auto s: order)
|
|
{
|
|
auto t = g_.out_iteraser(s);
|
|
bool useless = true;
|
|
while (t)
|
|
{
|
|
// Erase any transition to a useless state.
|
|
if (!useful[t->dst])
|
|
{
|
|
t.erase();
|
|
continue;
|
|
}
|
|
// if we have a transition to a useful state, then the
|
|
// state is useful.
|
|
useless = false;
|
|
++t;
|
|
}
|
|
if (useless)
|
|
useful[s] = 0;
|
|
}
|
|
|
|
// Make sure the initial state is useful (even if it has been
|
|
// marked as useless by the previous loop because it has no
|
|
// successor).
|
|
useful[init_number_] = 1;
|
|
|
|
// Now renumber each used state.
|
|
unsigned current = 0;
|
|
for (unsigned s = 0; s < num_states; ++s)
|
|
if (useful[s])
|
|
useful[s] = current++;
|
|
else
|
|
useful[s] = -1U;
|
|
if (current == num_states)
|
|
return; // No useless state.
|
|
init_number_ = useful[init_number_];
|
|
g_.defrag_states(std::move(useful), current);
|
|
}
|
|
}
|