scc_info: introduce scc_and_mark_filter

* spot/twaalgos/sccinfo.hh, spot/twaalgos/sccinfo.cc: Here.
* spot/twaalgos/genem.cc: Use it.
* python/spot/impl.i, python/spot/__init__.py: Add bindings.
* tests/python/genem.py: Test it.
* NEWS: Mention it.
This commit is contained in:
Alexandre Duret-Lutz 2019-03-30 11:03:03 +01:00
parent 0d9c81a6d9
commit 55db24e00e
7 changed files with 256 additions and 48 deletions

View file

@ -57,36 +57,16 @@ namespace spot
twa_run_ptr run,
acc_cond::mark_t tocut))
{
struct filter_data_t {
const scc_info& lower_si;
unsigned lower_scc;
acc_cond::mark_t cut_sets;
}
data = {si, scc, tocut};
scc_info::edge_filter filter =
[](const twa_graph::edge_storage_t& e, unsigned dst,
void* filter_data) -> scc_info::edge_filter_choice
{
auto& data = *reinterpret_cast<filter_data_t*>(filter_data);
if (data.lower_si.scc_of(dst) != data.lower_scc)
return scc_info::edge_filter_choice::ignore;
if (data.cut_sets & e.acc)
return scc_info::edge_filter_choice::cut;
return scc_info::edge_filter_choice::keep;
};
// We want to remove tocut from the acceptance condition right
// now, because hopefully this will convert the acceptance
// condition into a Fin-less one, and then we do not have to
// recurse it.
acc_cond::mark_t sets = si.acc_sets_of(scc) - tocut;
auto& autacc = si.get_aut()->acc();
acc_cond acc = autacc.restrict_to(sets);
acc_cond acc = autacc.restrict_to(si.acc_sets_of(scc) - tocut);
acc = acc.remove(si.common_sets_of(scc), false);
temporary_acc_set tmp(si.get_aut(), acc);
scc_info upper_si(si.get_aut(), si.one_state_of(scc), filter, &data,
scc_info_options::STOP_ON_ACC);
scc_and_mark_filter filt(si, scc, tocut);
filt.override_acceptance(acc);
scc_info upper_si(filt, scc_info_options::STOP_ON_ACC);
const int accepting_scc = upper_si.one_accepting_scc();
if (accepting_scc >= 0)

View file

@ -75,6 +75,12 @@ namespace spot
};
}
scc_info::scc_info(scc_and_mark_filter& filt, scc_info_options options)
: scc_info(filt.get_aut(), filt.start_state(),
filt.get_filter(), &filt, options)
{
}
scc_info::scc_info(const_twa_graph_ptr aut,
unsigned initial_state,
edge_filter filter,
@ -716,6 +722,19 @@ namespace spot
unsigned dst)
{
cur[src] = seen[src] = true;
// if (filter_)
// {
// twa_graph::edge_storage_t e;
// e.cond = cond;
// e.src = src;
// e.dst = dst;
// if (filter_(e, dst, filter_data_)
// != edge_filter_choice::keep)
// {
// cond = bddfalse;
// return;
// }
// }
if (scc_of(dst) != scc
|| (m & sets)
|| (seen[dst] && !cur[dst]))

View file

@ -350,6 +350,8 @@ namespace spot
| static_cast<ut>(right));
}
class SPOT_API scc_and_mark_filter;
/// \ingroup twa_misc
/// \brief Compute an SCC map and gather assorted information.
///
@ -449,11 +451,31 @@ namespace spot
}
/// @}
/// @{
/// \brief Create an scc_info map from some filter.
///
/// This is usually used to prevent some edges from being
/// considered as part of cycles, and can additionally restrict
/// to exploration to some SCC discovered by another SCC.
scc_info(scc_and_mark_filter& filt,
scc_info_options options = scc_info_options::ALL);
/// @}
const_twa_graph_ptr get_aut() const
{
return aut_;
}
scc_info_options get_options() const
{
return options_;
}
const void* get_filter_data() const
{
return filter_data_;
}
unsigned scc_count() const
{
return node_.size();
@ -687,6 +709,111 @@ namespace spot
};
/// \brief Create a filter for SCC and marks.
///
/// An scc_and_mark_filter can be passed to scc_info to explore only
/// a specific SCC of the original automaton, and to prevent some
/// acceptance sets from being considered as part of SCCs.
class SPOT_API scc_and_mark_filter
{
protected:
const scc_info* lower_si_;
unsigned lower_scc_;
acc_cond::mark_t cut_sets_;
const_twa_graph_ptr aut_;
acc_cond old_acc_;
bool restore_old_acc_ = false;
static scc_info::edge_filter_choice
filter_scc_and_mark_(const twa_graph::edge_storage_t& e,
unsigned dst, void* data)
{
auto& d = *reinterpret_cast<scc_and_mark_filter*>(data);
if (d.lower_si_->scc_of(dst) != d.lower_scc_)
return scc_info::edge_filter_choice::ignore;
if (d.cut_sets_ & e.acc)
return scc_info::edge_filter_choice::cut;
return scc_info::edge_filter_choice::keep;
};
static scc_info::edge_filter_choice
filter_mark_(const twa_graph::edge_storage_t& e, unsigned, void* data)
{
auto& d = *reinterpret_cast<scc_and_mark_filter*>(data);
if (d.cut_sets_ & e.acc)
return scc_info::edge_filter_choice::cut;
return scc_info::edge_filter_choice::keep;
};
public:
/// \brief Specify how to restrict scc_info to some SCC and acceptance sets
///
/// \param lower_si the original scc_info that specifies the SCC
/// \param lower_scc the SCC number in lower_si
/// \param cut_sets the acceptance sets that should not be part of SCCs.
scc_and_mark_filter(const scc_info& lower_si,
unsigned lower_scc,
acc_cond::mark_t cut_sets)
: lower_si_(&lower_si), lower_scc_(lower_scc), cut_sets_(cut_sets),
aut_(lower_si_->get_aut()), old_acc_(aut_->get_acceptance())
{
const void* data = lower_si.get_filter_data();
if (data)
{
auto& d = *reinterpret_cast<const scc_and_mark_filter*>(data);
cut_sets_ |= d.cut_sets_;
}
}
/// \brief Specify how to restrict scc_info to some acceptance sets
///
/// \param aut the automaton to filter
/// \param cut_sets the acceptance sets that should not be part of SCCs.
scc_and_mark_filter(const const_twa_graph_ptr& aut,
acc_cond::mark_t cut_sets)
: lower_si_(nullptr), cut_sets_(cut_sets), aut_(aut),
old_acc_(aut_->get_acceptance())
{
}
~scc_and_mark_filter()
{
restore_acceptance();
}
void override_acceptance(const acc_cond& new_acc)
{
std::const_pointer_cast<twa_graph>(aut_)->set_acceptance(new_acc);
restore_old_acc_ = true;
}
void restore_acceptance()
{
if (!restore_old_acc_)
return;
std::const_pointer_cast<twa_graph>(aut_)->set_acceptance(old_acc_);
restore_old_acc_ = false;
}
const_twa_graph_ptr get_aut() const
{
return aut_;
}
unsigned start_state() const
{
if (lower_si_)
return lower_si_->one_state_of(lower_scc_);
return aut_->get_init_state_number();
}
scc_info::edge_filter get_filter()
{
return lower_si_ ? filter_scc_and_mark_ : filter_mark_;
}
};
/// \brief Dump the SCC graph of \a aut on \a out.
///
/// If \a sccinfo is not given, it will be computed.