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
|
|
@ -143,6 +143,7 @@
|
||||||
#include <spot/twaalgos/stats.hh>
|
#include <spot/twaalgos/stats.hh>
|
||||||
#include <spot/twaalgos/isdet.hh>
|
#include <spot/twaalgos/isdet.hh>
|
||||||
#include <spot/twaalgos/isunamb.hh>
|
#include <spot/twaalgos/isunamb.hh>
|
||||||
|
#include <spot/twaalgos/isweakscc.hh>
|
||||||
#include <spot/twaalgos/langmap.hh>
|
#include <spot/twaalgos/langmap.hh>
|
||||||
#include <spot/twaalgos/simulation.hh>
|
#include <spot/twaalgos/simulation.hh>
|
||||||
#include <spot/twaalgos/split.hh>
|
#include <spot/twaalgos/split.hh>
|
||||||
|
|
@ -574,6 +575,7 @@ def state_is_accepting(self, src) -> "bool":
|
||||||
%include <spot/twaalgos/stats.hh>
|
%include <spot/twaalgos/stats.hh>
|
||||||
%include <spot/twaalgos/isdet.hh>
|
%include <spot/twaalgos/isdet.hh>
|
||||||
%include <spot/twaalgos/isunamb.hh>
|
%include <spot/twaalgos/isunamb.hh>
|
||||||
|
%include <spot/twaalgos/isweakscc.hh>
|
||||||
%include <spot/twaalgos/simulation.hh>
|
%include <spot/twaalgos/simulation.hh>
|
||||||
%include <spot/twaalgos/postproc.hh>
|
%include <spot/twaalgos/postproc.hh>
|
||||||
%include <spot/twaalgos/product.hh>
|
%include <spot/twaalgos/product.hh>
|
||||||
|
|
|
||||||
|
|
@ -23,20 +23,29 @@
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
[[noreturn]] static void
|
||||||
|
invalid_scc_number(const char* fn)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument(std::string(fn) + "(): invalid SCC number");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
scc_has_rejecting_cycle(scc_info& map, unsigned scc)
|
scc_has_rejecting_cycle(scc_info& map, unsigned scc)
|
||||||
{
|
{
|
||||||
|
if (SPOT_UNLIKELY(scc >= map.scc_count()))
|
||||||
|
invalid_scc_number("scc_has_rejecting_cycle");
|
||||||
auto aut = map.get_aut();
|
auto aut = map.get_aut();
|
||||||
if (!aut->is_existential())
|
|
||||||
throw std::runtime_error
|
|
||||||
("scc_has_rejecting_cycle() does not support alternation");
|
|
||||||
// We check that by cloning the SCC and complementing its
|
// We check that by cloning the SCC and complementing its
|
||||||
// acceptance condition.
|
// acceptance condition.
|
||||||
std::vector<bool> keep(aut->num_states(), false);
|
std::vector<bool> keep(aut->num_states(), false);
|
||||||
auto& states = map.states_of(scc);
|
auto& states = map.states_of(scc);
|
||||||
for (auto s: states)
|
for (auto s: states)
|
||||||
keep[s] = true;
|
keep[s] = true;
|
||||||
auto sccaut = mask_keep_accessible_states(aut, keep, states.front());
|
auto sccaut = mask_keep_accessible_states(aut, keep, states.front(),
|
||||||
|
/* drop_univ_branch = */ true);
|
||||||
sccaut->set_acceptance(sccaut->acc().num_sets(),
|
sccaut->set_acceptance(sccaut->acc().num_sets(),
|
||||||
sccaut->get_acceptance().complement());
|
sccaut->get_acceptance().complement());
|
||||||
return !sccaut->is_empty();
|
return !sccaut->is_empty();
|
||||||
|
|
@ -45,9 +54,8 @@ namespace spot
|
||||||
bool
|
bool
|
||||||
is_inherently_weak_scc(scc_info& map, unsigned scc)
|
is_inherently_weak_scc(scc_info& map, unsigned scc)
|
||||||
{
|
{
|
||||||
if (!map.get_aut()->is_existential())
|
if (SPOT_UNLIKELY(scc >= map.scc_count()))
|
||||||
throw std::runtime_error
|
invalid_scc_number("is_inherently_weak_scc");
|
||||||
("is_inherently_weak_scc() does not support alternation");
|
|
||||||
// Weak SCCs are inherently weak.
|
// Weak SCCs are inherently weak.
|
||||||
if (is_weak_scc(map, scc))
|
if (is_weak_scc(map, scc))
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -60,10 +68,8 @@ namespace spot
|
||||||
bool
|
bool
|
||||||
is_weak_scc(scc_info& map, unsigned scc)
|
is_weak_scc(scc_info& map, unsigned scc)
|
||||||
{
|
{
|
||||||
if (!map.get_aut()->is_existential())
|
if (SPOT_UNLIKELY(scc >= map.scc_count()))
|
||||||
throw std::runtime_error
|
invalid_scc_number("is_weak_scc");
|
||||||
("is_weak_scc() does not support alternation");
|
|
||||||
|
|
||||||
// Rejecting SCCs are weak.
|
// Rejecting SCCs are weak.
|
||||||
if (map.is_rejecting_scc(scc))
|
if (map.is_rejecting_scc(scc))
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -74,10 +80,9 @@ namespace spot
|
||||||
bool
|
bool
|
||||||
is_complete_scc(scc_info& map, unsigned scc)
|
is_complete_scc(scc_info& map, unsigned scc)
|
||||||
{
|
{
|
||||||
|
if (SPOT_UNLIKELY(scc >= map.scc_count()))
|
||||||
|
invalid_scc_number("is_complete_scc");
|
||||||
auto a = map.get_aut();
|
auto a = map.get_aut();
|
||||||
if (!a->is_existential())
|
|
||||||
throw std::runtime_error
|
|
||||||
("is_complete_scc() does not support alternation");
|
|
||||||
for (auto s: map.states_of(scc))
|
for (auto s: map.states_of(scc))
|
||||||
{
|
{
|
||||||
bool has_succ = false;
|
bool has_succ = false;
|
||||||
|
|
@ -85,8 +90,16 @@ namespace spot
|
||||||
for (auto& t: a->out(s))
|
for (auto& t: a->out(s))
|
||||||
{
|
{
|
||||||
has_succ = true;
|
has_succ = true;
|
||||||
if (map.scc_of(t.dst) == scc)
|
bool in = true;
|
||||||
sumall |= t.cond;
|
for (auto d: a->univ_dests(t.dst))
|
||||||
|
if (map.scc_of(d) != scc)
|
||||||
|
{
|
||||||
|
in = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!in)
|
||||||
|
continue;
|
||||||
|
sumall |= t.cond;
|
||||||
if (sumall == bddtrue)
|
if (sumall == bddtrue)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -99,9 +112,8 @@ namespace spot
|
||||||
bool
|
bool
|
||||||
is_terminal_scc(scc_info& map, unsigned scc)
|
is_terminal_scc(scc_info& map, unsigned scc)
|
||||||
{
|
{
|
||||||
if (!map.get_aut()->is_existential())
|
if (SPOT_UNLIKELY(scc >= map.scc_count()))
|
||||||
throw std::runtime_error
|
invalid_scc_number("is_terminal_scc");
|
||||||
("is_terminal_scc() does not support alternation");
|
|
||||||
|
|
||||||
// If all transitions use all acceptance conditions, the SCC is weak.
|
// If all transitions use all acceptance conditions, the SCC is weak.
|
||||||
return (map.is_accepting_scc(scc)
|
return (map.is_accepting_scc(scc)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2012, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2012, 2013, 2014, 2017 Laboratoire de Recherche et
|
||||||
// Développement 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.
|
||||||
|
|
@ -54,7 +54,9 @@ namespace spot
|
||||||
/// \brief Whether the SCC number \a scc in \a map is complete.
|
/// \brief Whether the SCC number \a scc in \a map is complete.
|
||||||
///
|
///
|
||||||
/// An SCC is complete iff for all states and all label there exists
|
/// An SCC is complete iff for all states and all label there exists
|
||||||
/// a transition that stays into this SCC.
|
/// a transition that stays into this SCC. For this function,
|
||||||
|
/// universal transitions are considered in the SCC if all there
|
||||||
|
/// destination are into the SCC.
|
||||||
SPOT_API bool
|
SPOT_API bool
|
||||||
is_complete_scc(scc_info& map, unsigned scc);
|
is_complete_scc(scc_info& map, unsigned scc);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ namespace spot
|
||||||
|
|
||||||
twa_graph_ptr mask_keep_accessible_states(const const_twa_graph_ptr& in,
|
twa_graph_ptr mask_keep_accessible_states(const const_twa_graph_ptr& in,
|
||||||
std::vector<bool>& to_keep,
|
std::vector<bool>& to_keep,
|
||||||
unsigned int init)
|
unsigned int init,
|
||||||
|
bool drop_univ_branches)
|
||||||
{
|
{
|
||||||
if (to_keep.size() < in->num_states())
|
if (to_keep.size() < in->num_states())
|
||||||
to_keep.resize(in->num_states(), false);
|
to_keep.resize(in->num_states(), false);
|
||||||
|
|
@ -83,9 +84,21 @@ namespace spot
|
||||||
acc_cond::mark_t&,
|
acc_cond::mark_t&,
|
||||||
unsigned dst)
|
unsigned dst)
|
||||||
{
|
{
|
||||||
if (!to_keep[src] || !to_keep[dst])
|
if (!to_keep[src])
|
||||||
|
{
|
||||||
|
cond = bddfalse;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool want = false;
|
||||||
|
for (auto d: in->univ_dests(dst))
|
||||||
|
if (to_keep[d])
|
||||||
|
{
|
||||||
|
want = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!want)
|
||||||
cond = bddfalse;
|
cond = bddfalse;
|
||||||
}, init);
|
}, init, drop_univ_branches);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,16 +44,16 @@ namespace spot
|
||||||
/// `aut->get_named_prop<std::vector<unsigned>>("original-states")`
|
/// `aut->get_named_prop<std::vector<unsigned>>("original-states")`
|
||||||
/// to retrieve it.
|
/// to retrieve it.
|
||||||
///
|
///
|
||||||
|
/// If \a drop_univ_branches branch is set, universal branching is replaced
|
||||||
|
/// by existential branching during the copy.
|
||||||
|
///
|
||||||
/// \param init The optional new initial state.
|
/// \param init The optional new initial state.
|
||||||
template<typename Trans>
|
template<typename Trans>
|
||||||
void transform_accessible(const const_twa_graph_ptr& old,
|
void transform_accessible(const const_twa_graph_ptr& old,
|
||||||
twa_graph_ptr& cpy,
|
twa_graph_ptr& cpy,
|
||||||
Trans trans, unsigned int init)
|
Trans trans, unsigned int init,
|
||||||
|
bool drop_univ_branches = false)
|
||||||
{
|
{
|
||||||
if (!old->is_existential())
|
|
||||||
throw std::runtime_error
|
|
||||||
("transform_accessible() does not support alternation");
|
|
||||||
|
|
||||||
std::vector<unsigned> todo;
|
std::vector<unsigned> todo;
|
||||||
std::vector<unsigned> seen(old->num_states(), -1U);
|
std::vector<unsigned> seen(old->num_states(), -1U);
|
||||||
|
|
||||||
|
|
@ -75,7 +75,27 @@ namespace spot
|
||||||
return tmp;
|
return tmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
cpy->set_init_state(new_state(init));
|
// Deal with alternating automata, possibly.
|
||||||
|
std::map<std::vector<unsigned>, unsigned> uniq;
|
||||||
|
auto new_univ_state =
|
||||||
|
[&](unsigned old_state) -> unsigned
|
||||||
|
{
|
||||||
|
if (!old->is_univ_dest(old_state))
|
||||||
|
return new_state(old_state);
|
||||||
|
|
||||||
|
std::vector<unsigned> tmp;
|
||||||
|
for (auto s: old->univ_dests(old_state))
|
||||||
|
tmp.emplace_back(new_state(s));
|
||||||
|
std::sort(tmp.begin(), tmp.end());
|
||||||
|
tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
|
||||||
|
auto p = uniq.emplace(tmp, 0);
|
||||||
|
if (p.second)
|
||||||
|
p.first->second =
|
||||||
|
cpy->get_graph().new_univ_dests(tmp.begin(), tmp.end());
|
||||||
|
return p.first->second;
|
||||||
|
};
|
||||||
|
|
||||||
|
cpy->set_init_state(new_univ_state(init));
|
||||||
if (seen[init] != 0)
|
if (seen[init] != 0)
|
||||||
throw std::runtime_error
|
throw std::runtime_error
|
||||||
("the destination automaton of transform_accessible() should be empty");
|
("the destination automaton of transform_accessible() should be empty");
|
||||||
|
|
@ -93,13 +113,15 @@ namespace spot
|
||||||
bdd cond = t.cond;
|
bdd cond = t.cond;
|
||||||
acc_cond::mark_t acc = t.acc;
|
acc_cond::mark_t acc = t.acc;
|
||||||
trans(t.src, cond, acc, t.dst);
|
trans(t.src, cond, acc, t.dst);
|
||||||
|
if (cond == bddfalse)
|
||||||
if (cond != bddfalse)
|
continue;
|
||||||
cpy->new_edge(new_src, new_state(t.dst),
|
if (drop_univ_branches)
|
||||||
cond, acc);
|
for (unsigned d: old->univ_dests(t.dst))
|
||||||
|
cpy->new_edge(new_src, new_state(d), cond, acc);
|
||||||
|
else
|
||||||
|
cpy->new_edge(new_src, new_univ_state(t.dst), cond, acc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
orig_states->shrink_to_fit();
|
orig_states->shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,9 +208,13 @@ namespace spot
|
||||||
/// will be set to \a init. Only states that are accessible from \a
|
/// will be set to \a init. Only states that are accessible from \a
|
||||||
/// init via states in \a to_keep will be preserved.
|
/// init via states in \a to_keep will be preserved.
|
||||||
///
|
///
|
||||||
|
/// If \a drop_univ_branches branch is set, universal branching is replaced
|
||||||
|
/// by existential branching during the copy.
|
||||||
|
///
|
||||||
/// \see mask_keep_states
|
/// \see mask_keep_states
|
||||||
SPOT_API
|
SPOT_API
|
||||||
twa_graph_ptr mask_keep_accessible_states(const const_twa_graph_ptr& in,
|
twa_graph_ptr mask_keep_accessible_states(const const_twa_graph_ptr& in,
|
||||||
std::vector<bool>& to_keep,
|
std::vector<bool>& to_keep,
|
||||||
unsigned int init);
|
unsigned int init,
|
||||||
|
bool drop_univ_branches = false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -367,15 +367,15 @@ namespace spot
|
||||||
|
|
||||||
void scc_info::determine_unknown_acceptance()
|
void scc_info::determine_unknown_acceptance()
|
||||||
{
|
{
|
||||||
if (!aut_->is_existential())
|
|
||||||
throw std::runtime_error("scc_info::determine_unknown_acceptance() "
|
|
||||||
"does not support alternating automata");
|
|
||||||
std::vector<bool> k;
|
std::vector<bool> k;
|
||||||
unsigned n = scc_count();
|
unsigned n = scc_count();
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
for (unsigned s = 0; s < n; ++s)
|
for (unsigned s = 0; s < n; ++s)
|
||||||
if (!is_rejecting_scc(s) && !is_accepting_scc(s))
|
if (!is_rejecting_scc(s) && !is_accepting_scc(s))
|
||||||
{
|
{
|
||||||
|
if (!aut_->is_existential())
|
||||||
|
throw std::runtime_error("scc_info::determine_unknown_acceptance() "
|
||||||
|
"does not support alternating automata");
|
||||||
auto& node = node_[s];
|
auto& node = node_[s];
|
||||||
if (k.empty())
|
if (k.empty())
|
||||||
k.resize(aut_->num_states());
|
k.resize(aut_->num_states());
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,15 @@ namespace spot
|
||||||
{
|
{
|
||||||
struct keep_all
|
struct keep_all
|
||||||
{
|
{
|
||||||
template <typename Edge>
|
template <typename Iterator>
|
||||||
bool operator()(const Edge&) const noexcept
|
bool operator()(Iterator, Iterator) const noexcept
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Keep only transitions that have at least one destination in the
|
||||||
|
// current SCC.
|
||||||
struct keep_inner_scc
|
struct keep_inner_scc
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
@ -48,10 +50,17 @@ namespace spot
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Edge>
|
template <typename Iterator>
|
||||||
bool operator()(const Edge& ed) const noexcept
|
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,
|
const typename Graph::state_vector,
|
||||||
typename Graph::state_vector>::type
|
typename Graph::state_vector>::type
|
||||||
sv_t;
|
sv_t;
|
||||||
|
typedef const typename Graph::dests_vector_t dv_t;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
state_iterator pos_;
|
state_iterator pos_;
|
||||||
|
|
@ -86,6 +96,8 @@ namespace spot
|
||||||
unsigned t_;
|
unsigned t_;
|
||||||
tv_t* tv_;
|
tv_t* tv_;
|
||||||
sv_t* sv_;
|
sv_t* sv_;
|
||||||
|
dv_t* dv_;
|
||||||
|
|
||||||
Filter filt_;
|
Filter filt_;
|
||||||
|
|
||||||
void inc_state_maybe_()
|
void inc_state_maybe_()
|
||||||
|
|
@ -100,17 +112,28 @@ namespace spot
|
||||||
inc_state_maybe_();
|
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:
|
public:
|
||||||
scc_edge_iterator(state_iterator begin, state_iterator end,
|
scc_edge_iterator(state_iterator begin, state_iterator end,
|
||||||
tv_t* tv, sv_t* sv, Filter filt) noexcept
|
tv_t* tv, sv_t* sv, dv_t* dv, Filter filt) noexcept
|
||||||
: pos_(begin), end_(end), t_(0), tv_(tv), sv_(sv), filt_(filt)
|
: pos_(begin), end_(end), t_(0), tv_(tv), sv_(sv), dv_(dv), filt_(filt)
|
||||||
{
|
{
|
||||||
if (pos_ == end_)
|
if (pos_ == end_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
t_ = (*sv_)[*pos_].succ;
|
t_ = (*sv_)[*pos_].succ;
|
||||||
inc_state_maybe_();
|
inc_state_maybe_();
|
||||||
while (pos_ != end_ && !filt_(**this))
|
while (pos_ != end_ && ignore_current())
|
||||||
inc_();
|
inc_();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +141,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
inc_();
|
inc_();
|
||||||
while (pos_ != end_ && !filt_(**this));
|
while (pos_ != end_ && ignore_current());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,29 +181,31 @@ namespace spot
|
||||||
typedef scc_edge_iterator<Graph, Filter> iter_t;
|
typedef scc_edge_iterator<Graph, Filter> iter_t;
|
||||||
typedef typename iter_t::tv_t tv_t;
|
typedef typename iter_t::tv_t tv_t;
|
||||||
typedef typename iter_t::sv_t sv_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;
|
typedef typename iter_t::state_iterator state_iterator;
|
||||||
private:
|
private:
|
||||||
state_iterator begin_;
|
state_iterator begin_;
|
||||||
state_iterator end_;
|
state_iterator end_;
|
||||||
tv_t* tv_;
|
tv_t* tv_;
|
||||||
sv_t* sv_;
|
sv_t* sv_;
|
||||||
|
dv_t* dv_;
|
||||||
Filter filt_;
|
Filter filt_;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
scc_edges(state_iterator begin, state_iterator end,
|
scc_edges(state_iterator begin, state_iterator end,
|
||||||
tv_t* tv, sv_t* sv, Filter filt) noexcept
|
tv_t* tv, sv_t* sv, dv_t* dv, Filter filt) noexcept
|
||||||
: begin_(begin), end_(end), tv_(tv), sv_(sv), filt_(filt)
|
: begin_(begin), end_(end), tv_(tv), sv_(sv), dv_(dv), filt_(filt)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
iter_t begin() const
|
iter_t begin() const
|
||||||
{
|
{
|
||||||
return {begin_, end_, tv_, sv_, filt_};
|
return {begin_, end_, tv_, sv_, dv_, filt_};
|
||||||
}
|
}
|
||||||
|
|
||||||
iter_t end() const
|
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);
|
auto& states = states_of(scc);
|
||||||
return {states.begin(), states.end(),
|
return {states.begin(), states.end(),
|
||||||
&aut_->edge_vector(), &aut_->states(),
|
&aut_->edge_vector(), &aut_->states(),
|
||||||
|
&aut_->get_graph().dests_vector(),
|
||||||
internal::keep_all()};
|
internal::keep_all()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief A fake container to iterate over all edges between
|
/// \brief A fake container to iterate over all edges between
|
||||||
/// states of an SCC.
|
/// states of an SCC.
|
||||||
///
|
///
|
||||||
/// The difference with edges_of() is that inner_edges_of() ignores
|
/// The difference with edges_of() is that inner_edges_of()
|
||||||
/// edges leaving the SCC are ignored.
|
/// 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>
|
internal::scc_edges<const twa_graph::graph_t, internal::keep_inner_scc>
|
||||||
inner_edges_of(unsigned scc) const
|
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);
|
auto& states = states_of(scc);
|
||||||
return {states.begin(), states.end(),
|
return {states.begin(), states.end(),
|
||||||
&aut_->edge_vector(), &aut_->states(),
|
&aut_->edge_vector(), &aut_->states(),
|
||||||
|
&aut_->get_graph().dests_vector(),
|
||||||
internal::keep_inner_scc(sccof_, scc)};
|
internal::keep_inner_scc(sccof_, scc)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -256,15 +256,25 @@ namespace spot
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
if (pos[1] == 'w')
|
if (pos[1] == 'w')
|
||||||
inherently_weak = true;
|
{
|
||||||
|
inherently_weak = true;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
error(std::string(pos, pos + 2));
|
{
|
||||||
|
error(std::string(pos, pos + 2));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
if (pos[1] == 'W')
|
if (pos[1] == 'W')
|
||||||
non_inherently_weak = true;
|
{
|
||||||
|
non_inherently_weak = true;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
error(std::string(pos, pos + 2));
|
{
|
||||||
|
error(std::string(pos, pos + 2));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
case '\t':
|
case '\t':
|
||||||
|
|
|
||||||
|
|
@ -1840,6 +1840,7 @@ State: 2 "t"
|
||||||
EOF
|
EOF
|
||||||
autfilt --tgba in 2>out && exit 1
|
autfilt --tgba in 2>out && exit 1
|
||||||
grep 'autfilt.*weak.*alternating' out
|
grep 'autfilt.*weak.*alternating' out
|
||||||
|
test '0 2 2 1' = "`autfilt --stats='%[Wiw]c %[w]c %[iw]c %[W]c' in`"
|
||||||
|
|
||||||
cat >in <<EOF
|
cat >in <<EOF
|
||||||
HOA: v1
|
HOA: v1
|
||||||
|
|
@ -1860,3 +1861,4 @@ State: 3 /*{0}*/
|
||||||
EOF
|
EOF
|
||||||
autfilt --tgba in 2>out && exit 1
|
autfilt --tgba in 2>out && exit 1
|
||||||
grep 'autfilt.*weak.*alternating' out
|
grep 'autfilt.*weak.*alternating' out
|
||||||
|
test '2 0 2 2' = "`autfilt --stats='%[Wiw]c %[w]c %[iw]c %[W]c' in`"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue