is_weak_scc and friend: make them work for alternating automata
* spot/twaalgos/isweakscc.cc, spot/twaalgos/isweakscc.hh, spot/twaalgos/mask.cc, spot/twaalgos/mask.hh: Adjust to work with alternating automata. * spot/twaalgos/sccinfo.cc, spot/twaalgos/sccinfo.hh (determine_unknown_acceptance): Do not complain about not supporting alternating automata if there is not indeterminate acceptance. * spot/twaalgos/stats.cc: Fix a bug were %[iw]c was read as %[iww]c. * tests/core/alternating.test: Test is_inherently_weak_scc() and is_weak_scc(). * python/spot/impl.i: Add missing python bindings for isweakscc.hh.
This commit is contained in:
parent
e041db6101
commit
223b0c6a9e
9 changed files with 154 additions and 61 deletions
|
|
@ -30,13 +30,15 @@ namespace spot
|
|||
{
|
||||
struct keep_all
|
||||
{
|
||||
template <typename Edge>
|
||||
bool operator()(const Edge&) const noexcept
|
||||
template <typename Iterator>
|
||||
bool operator()(Iterator, Iterator) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Keep only transitions that have at least one destination in the
|
||||
// current SCC.
|
||||
struct keep_inner_scc
|
||||
{
|
||||
private:
|
||||
|
|
@ -48,10 +50,17 @@ namespace spot
|
|||
{
|
||||
}
|
||||
|
||||
template <typename Edge>
|
||||
bool operator()(const Edge& ed) const noexcept
|
||||
template <typename Iterator>
|
||||
bool operator()(Iterator begin, Iterator end) const noexcept
|
||||
{
|
||||
return sccof_[ed.dst] == desired_scc_;
|
||||
bool want = false;
|
||||
while (begin != end)
|
||||
if (sccof_[*begin++] == desired_scc_)
|
||||
{
|
||||
want = true;
|
||||
break;
|
||||
}
|
||||
return want;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -79,6 +88,7 @@ namespace spot
|
|||
const typename Graph::state_vector,
|
||||
typename Graph::state_vector>::type
|
||||
sv_t;
|
||||
typedef const typename Graph::dests_vector_t dv_t;
|
||||
protected:
|
||||
|
||||
state_iterator pos_;
|
||||
|
|
@ -86,6 +96,8 @@ namespace spot
|
|||
unsigned t_;
|
||||
tv_t* tv_;
|
||||
sv_t* sv_;
|
||||
dv_t* dv_;
|
||||
|
||||
Filter filt_;
|
||||
|
||||
void inc_state_maybe_()
|
||||
|
|
@ -100,17 +112,28 @@ namespace spot
|
|||
inc_state_maybe_();
|
||||
}
|
||||
|
||||
bool ignore_current()
|
||||
{
|
||||
unsigned dst = (*this)->dst;
|
||||
if ((int)dst >= 0)
|
||||
// Non-universal branching => a single destination.
|
||||
return !filt_(&(*this)->dst, 1 + &(*this)->dst);
|
||||
// Universal branching => multiple destinations.
|
||||
const unsigned* d = dv_->data() + ~dst;
|
||||
return !filt_(d + 1, d + *d + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
scc_edge_iterator(state_iterator begin, state_iterator end,
|
||||
tv_t* tv, sv_t* sv, Filter filt) noexcept
|
||||
: pos_(begin), end_(end), t_(0), tv_(tv), sv_(sv), filt_(filt)
|
||||
tv_t* tv, sv_t* sv, dv_t* dv, Filter filt) noexcept
|
||||
: pos_(begin), end_(end), t_(0), tv_(tv), sv_(sv), dv_(dv), filt_(filt)
|
||||
{
|
||||
if (pos_ == end_)
|
||||
return;
|
||||
|
||||
t_ = (*sv_)[*pos_].succ;
|
||||
inc_state_maybe_();
|
||||
while (pos_ != end_ && !filt_(**this))
|
||||
while (pos_ != end_ && ignore_current())
|
||||
inc_();
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +141,7 @@ namespace spot
|
|||
{
|
||||
do
|
||||
inc_();
|
||||
while (pos_ != end_ && !filt_(**this));
|
||||
while (pos_ != end_ && ignore_current());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -158,29 +181,31 @@ namespace spot
|
|||
typedef scc_edge_iterator<Graph, Filter> iter_t;
|
||||
typedef typename iter_t::tv_t tv_t;
|
||||
typedef typename iter_t::sv_t sv_t;
|
||||
typedef typename iter_t::dv_t dv_t;
|
||||
typedef typename iter_t::state_iterator state_iterator;
|
||||
private:
|
||||
state_iterator begin_;
|
||||
state_iterator end_;
|
||||
tv_t* tv_;
|
||||
sv_t* sv_;
|
||||
dv_t* dv_;
|
||||
Filter filt_;
|
||||
public:
|
||||
|
||||
scc_edges(state_iterator begin, state_iterator end,
|
||||
tv_t* tv, sv_t* sv, Filter filt) noexcept
|
||||
: begin_(begin), end_(end), tv_(tv), sv_(sv), filt_(filt)
|
||||
tv_t* tv, sv_t* sv, dv_t* dv, Filter filt) noexcept
|
||||
: begin_(begin), end_(end), tv_(tv), sv_(sv), dv_(dv), filt_(filt)
|
||||
{
|
||||
}
|
||||
|
||||
iter_t begin() const
|
||||
{
|
||||
return {begin_, end_, tv_, sv_, filt_};
|
||||
return {begin_, end_, tv_, sv_, dv_, filt_};
|
||||
}
|
||||
|
||||
iter_t end() const
|
||||
{
|
||||
return {end_, end_, nullptr, nullptr, filt_};
|
||||
return {end_, end_, nullptr, nullptr, nullptr, filt_};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -408,23 +433,24 @@ namespace spot
|
|||
auto& states = states_of(scc);
|
||||
return {states.begin(), states.end(),
|
||||
&aut_->edge_vector(), &aut_->states(),
|
||||
&aut_->get_graph().dests_vector(),
|
||||
internal::keep_all()};
|
||||
}
|
||||
|
||||
/// \brief A fake container to iterate over all edges between
|
||||
/// states of an SCC.
|
||||
///
|
||||
/// The difference with edges_of() is that inner_edges_of() ignores
|
||||
/// edges leaving the SCC are ignored.
|
||||
/// The difference with edges_of() is that inner_edges_of()
|
||||
/// ignores edges leaving the SCC are ignored. In the case of
|
||||
/// alternating automaton, an edge is considered to be part of the
|
||||
/// SCC of one of its destination is in the SCC.
|
||||
internal::scc_edges<const twa_graph::graph_t, internal::keep_inner_scc>
|
||||
inner_edges_of(unsigned scc) const
|
||||
{
|
||||
if (!aut_->is_existential())
|
||||
throw std::runtime_error
|
||||
("inner_edges_of(): alternating automata are not supported");
|
||||
auto& states = states_of(scc);
|
||||
return {states.begin(), states.end(),
|
||||
&aut_->edge_vector(), &aut_->states(),
|
||||
&aut_->get_graph().dests_vector(),
|
||||
internal::keep_inner_scc(sccof_, scc)};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue