sccfilter: implement a new version of tgba_digraph
The new version currently supports removal of useless state as well as removal of acceptance sets from non-accepting SCCs (the two versions). It does not yet support simplifation of acceptance sets and removal of suspendable formulae. However the design, using filters that are composed before being applied, should make it easier to implement. * src/tgbaalgos/sccfilter.cc, src/tgbaalgos/sccfilter.hh: Implement the new scc_filter and supporting classes. * src/tgbaalgos/simulation.cc, src/tgbaalgos/simulation.hh: Use it. The simulation now always return a tgba_digraph. * src/tgbatest/sim.test: Adjust.
This commit is contained in:
parent
e299a3d1bf
commit
13673a1421
5 changed files with 224 additions and 73 deletions
|
|
@ -609,50 +609,198 @@ namespace spot
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba_digraph* scc_filter_states(const tgba_digraph* aut, scc_info* given_si)
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace
|
||||||
{
|
{
|
||||||
// Compute scc_info if not supplied.
|
|
||||||
scc_info* si = given_si;
|
|
||||||
if (!si)
|
|
||||||
si = new scc_info(aut);
|
|
||||||
|
|
||||||
// Renumber all useful states.
|
typedef std::tuple<bool, bdd, bdd> filtered_trans;
|
||||||
unsigned in_n = aut->num_states(); // Number of input states.
|
|
||||||
unsigned out_n = 0; // Number of output states.
|
|
||||||
std::vector<unsigned> inout; // Associate old states to new ones.
|
|
||||||
inout.reserve(in_n);
|
|
||||||
for (unsigned i = 0; i < in_n; ++i)
|
|
||||||
if (si->is_useful_state(i))
|
|
||||||
inout.push_back(out_n++);
|
|
||||||
else
|
|
||||||
inout.push_back(-1U);
|
|
||||||
|
|
||||||
// scc_info is not useful anymore.
|
|
||||||
if (!given_si)
|
|
||||||
delete si;
|
|
||||||
|
|
||||||
bdd_dict* bd = aut->get_dict();
|
// SCC filters are objects with two methods:
|
||||||
tgba_digraph* filtered = new tgba_digraph(bd);
|
// state(src) return true iff s should be kept
|
||||||
bd->register_all_variables_of(aut, filtered);
|
// trans(src, dst, cond, acc) returns a triplet
|
||||||
filtered->copy_acceptance_conditions_of(aut);
|
// (keep, cond2, acc2) where keep is a Boolean stating if the
|
||||||
const tgba_digraph::graph_t& ing = aut->get_graph();
|
// transition should be kept, and cond2/acc2
|
||||||
tgba_digraph::graph_t& outg = filtered->get_graph();
|
// give replacement values for cond/acc
|
||||||
outg.new_states(out_n);
|
struct id_filter
|
||||||
for (unsigned isrc = 0; isrc < in_n; ++isrc)
|
{
|
||||||
|
scc_info* si;
|
||||||
|
id_filter(scc_info* si)
|
||||||
|
: si(si)
|
||||||
{
|
{
|
||||||
unsigned osrc = inout[isrc];
|
|
||||||
if (osrc >= out_n)
|
|
||||||
continue;
|
|
||||||
for (auto& t: ing.out(isrc))
|
|
||||||
{
|
|
||||||
unsigned odst = inout[t.dst];
|
|
||||||
if (odst >= out_n)
|
|
||||||
continue;
|
|
||||||
outg.new_transition(osrc, odst, t.cond, t.acc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
filtered->set_init_state(aut->get_init_state_number());
|
|
||||||
return filtered;
|
// Accept all states
|
||||||
|
bool state(unsigned)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept all transitions, unmodified
|
||||||
|
filtered_trans trans(unsigned, unsigned, bdd cond, bdd acc)
|
||||||
|
{
|
||||||
|
return filtered_trans{true, cond, acc};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove useless states.
|
||||||
|
struct state_filter: id_filter
|
||||||
|
{
|
||||||
|
state_filter(scc_info* si)
|
||||||
|
: id_filter(si)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool state(unsigned s)
|
||||||
|
{
|
||||||
|
return si->is_useful_state(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove acceptance conditions from all transitions outside of
|
||||||
|
// non-accepting SCCs.
|
||||||
|
struct acc_filter_all: id_filter
|
||||||
|
{
|
||||||
|
acc_filter_all(scc_info* si)
|
||||||
|
: id_filter(si)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered_trans trans(unsigned src, unsigned dst,
|
||||||
|
bdd cond, bdd acc)
|
||||||
|
{
|
||||||
|
unsigned u = si->scc_of(src);
|
||||||
|
// If the transition is between two SCCs, or in a
|
||||||
|
// non-accepting SCC. Remove the acceptance sets.
|
||||||
|
if (!si->is_accepting_scc(u) || u != si->scc_of(dst))
|
||||||
|
acc = bddfalse;
|
||||||
|
|
||||||
|
return filtered_trans(true, cond, acc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove acceptance conditions from all transitions whose
|
||||||
|
// destination is not an accepting SCCs.
|
||||||
|
struct acc_filter_some: id_filter
|
||||||
|
{
|
||||||
|
acc_filter_some(scc_info* si)
|
||||||
|
: id_filter(si)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered_trans trans(unsigned, unsigned dst,
|
||||||
|
bdd cond, bdd acc)
|
||||||
|
{
|
||||||
|
if (!si->is_accepting_scc(si->scc_of(dst)))
|
||||||
|
acc = bddfalse;
|
||||||
|
return filtered_trans(true, cond, acc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F1, typename F2>
|
||||||
|
struct compose_filters
|
||||||
|
{
|
||||||
|
F1 f1;
|
||||||
|
F2 f2;
|
||||||
|
|
||||||
|
compose_filters(scc_info* si)
|
||||||
|
: f1(si), f2(si)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool state(unsigned s)
|
||||||
|
{
|
||||||
|
return f1.state(s) && f2.state(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered_trans trans(unsigned src, unsigned dst,
|
||||||
|
bdd cond, bdd acc)
|
||||||
|
{
|
||||||
|
auto res = f1.trans(src, dst, cond, acc);
|
||||||
|
if (!std::get<0>(res))
|
||||||
|
return res;
|
||||||
|
return f2.trans(src, dst, std::get<1>(res), std::get<2>(res));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class F>
|
||||||
|
tgba_digraph* scc_filter_apply(const tgba_digraph* aut, scc_info* given_si)
|
||||||
|
{
|
||||||
|
// Compute scc_info if not supplied.
|
||||||
|
scc_info* si = given_si;
|
||||||
|
if (!si)
|
||||||
|
si = new scc_info(aut);
|
||||||
|
|
||||||
|
|
||||||
|
F filter(si);
|
||||||
|
|
||||||
|
// Renumber all useful states.
|
||||||
|
unsigned in_n = aut->num_states(); // Number of input states.
|
||||||
|
unsigned out_n = 0; // Number of output states.
|
||||||
|
std::vector<unsigned> inout; // Associate old states to new ones.
|
||||||
|
inout.reserve(in_n);
|
||||||
|
for (unsigned i = 0; i < in_n; ++i)
|
||||||
|
if (filter.state(i))
|
||||||
|
inout.push_back(out_n++);
|
||||||
|
else
|
||||||
|
inout.push_back(-1U);
|
||||||
|
|
||||||
|
bdd_dict* bd = aut->get_dict();
|
||||||
|
tgba_digraph* filtered = new tgba_digraph(bd);
|
||||||
|
bd->register_all_variables_of(aut, filtered);
|
||||||
|
filtered->copy_acceptance_conditions_of(aut);
|
||||||
|
const tgba_digraph::graph_t& ing = aut->get_graph();
|
||||||
|
tgba_digraph::graph_t& outg = filtered->get_graph();
|
||||||
|
outg.new_states(out_n);
|
||||||
|
for (unsigned isrc = 0; isrc < in_n; ++isrc)
|
||||||
|
{
|
||||||
|
unsigned osrc = inout[isrc];
|
||||||
|
if (osrc >= out_n)
|
||||||
|
continue;
|
||||||
|
for (auto& t: ing.out(isrc))
|
||||||
|
{
|
||||||
|
unsigned odst = inout[t.dst];
|
||||||
|
if (odst >= out_n)
|
||||||
|
continue;
|
||||||
|
bool want;
|
||||||
|
bdd cond;
|
||||||
|
bdd acc;
|
||||||
|
std::tie(want, cond, acc) =
|
||||||
|
filter.trans(isrc, t.dst, t.cond, t.acc);
|
||||||
|
if (want)
|
||||||
|
outg.new_transition(osrc, odst, cond, acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!given_si)
|
||||||
|
delete si;
|
||||||
|
// If the initial state has been filtered out, we don't attempt
|
||||||
|
// to fix it.
|
||||||
|
auto init = inout[aut->get_init_state_number()];
|
||||||
|
if (init < out_n)
|
||||||
|
filtered->set_init_state(init);
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_digraph*
|
||||||
|
scc_filter_states(const tgba_digraph* aut, scc_info* given_si)
|
||||||
|
{
|
||||||
|
return scc_filter_apply<state_filter>(aut, given_si);
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_digraph*
|
||||||
|
scc_filter(const tgba_digraph* aut, bool remove_all_useless,
|
||||||
|
scc_info* given_si)
|
||||||
|
{
|
||||||
|
if (remove_all_useless)
|
||||||
|
return scc_filter_apply<compose_filters<state_filter,
|
||||||
|
acc_filter_all>>(aut, given_si);
|
||||||
|
else
|
||||||
|
return scc_filter_apply<compose_filters<state_filter,
|
||||||
|
acc_filter_some>>(aut, given_si);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,11 +67,17 @@ namespace spot
|
||||||
/// (i.e., transitions leaving accepting states are all marked as
|
/// (i.e., transitions leaving accepting states are all marked as
|
||||||
/// accepting) may destroy this property. Use scc_filter_states()
|
/// accepting) may destroy this property. Use scc_filter_states()
|
||||||
/// instead.
|
/// instead.
|
||||||
|
/// @{
|
||||||
SPOT_API tgba*
|
SPOT_API tgba*
|
||||||
scc_filter(const tgba* aut, bool remove_all_useless = false,
|
scc_filter(const tgba* aut, bool remove_all_useless = false,
|
||||||
scc_map* given_sm = 0, bdd susp = bddtrue,
|
scc_map* given_sm = 0, bdd susp = bddtrue,
|
||||||
bool early_susp = false, bdd ignored = bddtrue);
|
bool early_susp = false, bdd ignored = bddtrue);
|
||||||
|
|
||||||
|
SPOT_API tgba_digraph*
|
||||||
|
scc_filter(const tgba_digraph* aut, bool remove_all_useless = false,
|
||||||
|
scc_info* given_si = 0);
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// \brief Prune unaccepting SCCs.
|
/// \brief Prune unaccepting SCCs.
|
||||||
///
|
///
|
||||||
/// This is an abridged version of scc_filter(), that only remove
|
/// This is an abridged version of scc_filter(), that only remove
|
||||||
|
|
|
||||||
|
|
@ -1309,28 +1309,28 @@ namespace spot
|
||||||
} // End namespace anonymous.
|
} // End namespace anonymous.
|
||||||
|
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
simulation(const tgba* t)
|
simulation(const tgba* t)
|
||||||
{
|
{
|
||||||
direct_simulation<false, false> simul(t);
|
direct_simulation<false, false> simul(t);
|
||||||
return simul.run();
|
return simul.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
simulation_sba(const tgba* t)
|
simulation_sba(const tgba* t)
|
||||||
{
|
{
|
||||||
direct_simulation<false, true> simul(t);
|
direct_simulation<false, true> simul(t);
|
||||||
return simul.run();
|
return simul.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
cosimulation(const tgba* t)
|
cosimulation(const tgba* t)
|
||||||
{
|
{
|
||||||
direct_simulation<true, false> simul(t);
|
direct_simulation<true, false> simul(t);
|
||||||
return simul.run();
|
return simul.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
cosimulation_sba(const tgba* t)
|
cosimulation_sba(const tgba* t)
|
||||||
{
|
{
|
||||||
direct_simulation<true, true> simul(t);
|
direct_simulation<true, true> simul(t);
|
||||||
|
|
@ -1339,21 +1339,19 @@ namespace spot
|
||||||
|
|
||||||
|
|
||||||
template<bool Sba>
|
template<bool Sba>
|
||||||
tgba*
|
tgba_digraph*
|
||||||
iterated_simulations_(const tgba* t)
|
iterated_simulations_(const tgba* t)
|
||||||
{
|
{
|
||||||
tgba* res = const_cast<tgba*> (t);
|
tgba_digraph* res = 0;
|
||||||
automaton_size prev;
|
automaton_size prev;
|
||||||
automaton_size next;
|
automaton_size next;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
prev = next;
|
prev = next;
|
||||||
direct_simulation<false, Sba> simul(res);
|
direct_simulation<false, Sba> simul(res ? res : t);
|
||||||
tgba_digraph* after_simulation = simul.run();
|
tgba_digraph* after_simulation = simul.run();
|
||||||
|
delete res;
|
||||||
if (res != t)
|
|
||||||
delete res;
|
|
||||||
|
|
||||||
if (simul.result_is_deterministic())
|
if (simul.result_is_deterministic())
|
||||||
{
|
{
|
||||||
|
|
@ -1376,53 +1374,51 @@ namespace spot
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
iterated_simulations(const tgba* t)
|
iterated_simulations(const tgba* t)
|
||||||
{
|
{
|
||||||
return iterated_simulations_<false>(t);
|
return iterated_simulations_<false>(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
iterated_simulations_sba(const tgba* t)
|
iterated_simulations_sba(const tgba* t)
|
||||||
{
|
{
|
||||||
return iterated_simulations_<true>(t);
|
return iterated_simulations_<true>(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
dont_care_simulation(const tgba* t, int limit)
|
dont_care_simulation(const tgba* t, int limit)
|
||||||
{
|
{
|
||||||
direct_simulation<false, false> sim(t);
|
direct_simulation<false, false> sim(t);
|
||||||
tgba* tmp = sim.run();
|
tgba_digraph* tmp = sim.run();
|
||||||
|
|
||||||
direct_simulation_dont_care s(tmp);
|
direct_simulation_dont_care s(tmp);
|
||||||
if (limit > 0)
|
if (limit > 0)
|
||||||
s.set_limit(limit);
|
s.set_limit(limit);
|
||||||
|
|
||||||
tgba* res = s.run();
|
tgba_digraph* res = s.run();
|
||||||
delete tmp;
|
delete tmp;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tgba*
|
tgba_digraph*
|
||||||
dont_care_iterated_simulations(const tgba* t, int limit)
|
dont_care_iterated_simulations(const tgba* t, int limit)
|
||||||
{
|
{
|
||||||
tgba* res = const_cast<tgba*> (t);
|
tgba_digraph* res = 0;
|
||||||
automaton_size prev;
|
automaton_size prev;
|
||||||
automaton_size next;
|
automaton_size next;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
prev = next;
|
prev = next;
|
||||||
|
tgba_digraph* after_simulation =
|
||||||
tgba* after_simulation = dont_care_simulation(res, limit);
|
dont_care_simulation(res ? res : t, limit);
|
||||||
|
delete res;
|
||||||
if (res != t)
|
|
||||||
delete res;
|
|
||||||
|
|
||||||
direct_simulation<true, false> cosimul(after_simulation);
|
direct_simulation<true, false> cosimul(after_simulation);
|
||||||
tgba* after_cosimulation = cosimul.run();
|
tgba_digraph* after_cosimulation = cosimul.run();
|
||||||
delete after_simulation;
|
delete after_simulation;
|
||||||
|
|
||||||
next = cosimul.get_stat();
|
next = cosimul.get_stat();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Développement
|
// Copyright (C) 2012, 2013, 2014 Laboratoire de Recherche et
|
||||||
// de l'Epita (LRDE).
|
// Développement de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
# define SPOT_TGBAALGOS_SIMULATION_HH
|
# define SPOT_TGBAALGOS_SIMULATION_HH
|
||||||
|
|
||||||
# include "misc/common.hh"
|
# include "misc/common.hh"
|
||||||
|
# include "tgba/tgbagraph.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -69,8 +70,8 @@ namespace spot
|
||||||
/// \param automaton the automaton to simulate.
|
/// \param automaton the automaton to simulate.
|
||||||
/// \return a new automaton which is at worst a copy of the received
|
/// \return a new automaton which is at worst a copy of the received
|
||||||
/// one
|
/// one
|
||||||
SPOT_API tgba* simulation(const tgba* automaton);
|
SPOT_API tgba_digraph* simulation(const tgba* automaton);
|
||||||
SPOT_API tgba* simulation_sba(const tgba* automaton);
|
SPOT_API tgba_digraph* simulation_sba(const tgba* automaton);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @{
|
/// @{
|
||||||
|
|
@ -120,8 +121,8 @@ namespace spot
|
||||||
/// \param automaton the automaton to simulate.
|
/// \param automaton the automaton to simulate.
|
||||||
/// \return a new automaton which is at worst a copy of the received
|
/// \return a new automaton which is at worst a copy of the received
|
||||||
/// one
|
/// one
|
||||||
SPOT_API tgba* cosimulation(const tgba* automaton);
|
SPOT_API tgba_digraph* cosimulation(const tgba* automaton);
|
||||||
SPOT_API tgba* cosimulation_sba(const tgba* automaton);
|
SPOT_API tgba_digraph* cosimulation_sba(const tgba* automaton);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @{
|
/// @{
|
||||||
|
|
@ -139,15 +140,15 @@ namespace spot
|
||||||
/// \param automaton the automaton to simulate.
|
/// \param automaton the automaton to simulate.
|
||||||
/// \return a new automaton which is at worst a copy of the received
|
/// \return a new automaton which is at worst a copy of the received
|
||||||
/// one
|
/// one
|
||||||
SPOT_API tgba* iterated_simulations(const tgba* automaton);
|
SPOT_API tgba_digraph* iterated_simulations(const tgba* automaton);
|
||||||
SPOT_API tgba* iterated_simulations_sba(const tgba* automaton);
|
SPOT_API tgba_digraph* iterated_simulations_sba(const tgba* automaton);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
SPOT_API tgba*
|
SPOT_API tgba_digraph*
|
||||||
dont_care_simulation(const tgba* t, int limit = -1);
|
dont_care_simulation(const tgba* t, int limit = -1);
|
||||||
|
|
||||||
SPOT_API tgba*
|
SPOT_API tgba_digraph*
|
||||||
dont_care_iterated_simulations(const tgba* t, int limit = -1);
|
dont_care_iterated_simulations(const tgba* t, int limit = -1);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ run 0 ../ltl2tgba -RDCIS -b XXXXGFa > out.tgba
|
||||||
|
|
||||||
cat >expected.tgba <<EOF
|
cat >expected.tgba <<EOF
|
||||||
acc = "a";
|
acc = "a";
|
||||||
"1", "1", "a", "a";
|
"0", "0", "a", "a";
|
||||||
"1", "1", "!a",;
|
"0", "0", "!a",;
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
diff out.tgba expected.tgba
|
diff out.tgba expected.tgba
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue