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:
parent
0d9c81a6d9
commit
55db24e00e
7 changed files with 256 additions and 48 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]))
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue