Adding option to solve parity games globally
Parity games have been solved semi-locally so far. We deduced a strategy for the reachable part of the arena This lead to some inconsistencies when not all state were rachable. Now you can chose to solve parity games truely globally. * spot/twaalgos/game.cc, spot/twaalgos/game.hh: Here * tests/python/games.ipynb: Test
This commit is contained in:
parent
146942953a
commit
e7e23d5ffc
3 changed files with 1258 additions and 60 deletions
|
|
@ -149,12 +149,38 @@ namespace spot
|
|||
{
|
||||
public:
|
||||
|
||||
bool solve(const twa_graph_ptr& arena)
|
||||
bool solve(const twa_graph_ptr& arena, bool solve_globally)
|
||||
{
|
||||
// todo check if reordering states according to scc is worth it
|
||||
set_up(arena);
|
||||
// Start recursive zielonka in a bottom-up fashion on each scc
|
||||
subgame_info_t subgame_info;
|
||||
while (true)
|
||||
{
|
||||
// If we solve globally,
|
||||
auto maybe_useful = [&](unsigned scc_idx){
|
||||
if (info_->is_useful_scc(scc_idx))
|
||||
return true;
|
||||
if (!solve_globally)
|
||||
return false;
|
||||
// Check if we have an out-edge to a winning state
|
||||
// in another scc
|
||||
return std::any_of(
|
||||
info_->states_of(scc_idx).begin(),
|
||||
info_->states_of(scc_idx).end(),
|
||||
[&](unsigned s){
|
||||
return std::any_of(
|
||||
arena->out(s).begin(),
|
||||
arena->out(s).end(),
|
||||
[&](const auto& e){
|
||||
assert ((subgame_[e.dst] == unseen_mark)
|
||||
|| (info_->scc_of(e.dst) != scc_idx));
|
||||
return (info_->scc_of(e.dst) != scc_idx)
|
||||
&& w_.winner(e.dst);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
for (c_scc_idx_ = 0; c_scc_idx_ < info_->scc_count(); ++c_scc_idx_)
|
||||
{
|
||||
// Testing
|
||||
|
|
@ -169,7 +195,7 @@ namespace spot
|
|||
return true;
|
||||
}());
|
||||
// Useless SCCs are winning for player 0.
|
||||
if (!info_->is_useful_scc(c_scc_idx_))
|
||||
if (!maybe_useful(c_scc_idx_))
|
||||
{
|
||||
// This scc also gets its own subgame
|
||||
++rd_;
|
||||
|
|
@ -207,15 +233,49 @@ namespace spot
|
|||
}
|
||||
}
|
||||
}
|
||||
// Every state needs a winner
|
||||
assert(std::all_of(w_.has_winner_.cbegin(), w_.has_winner_.cend(),
|
||||
[](bool b)
|
||||
{ return b; }));
|
||||
if (!solve_globally)
|
||||
break;
|
||||
|
||||
// Update the scc_info and continue
|
||||
unsigned new_init
|
||||
= std::distance(subgame_.begin(),
|
||||
std::find(subgame_.begin(), subgame_.end(),
|
||||
unseen_mark));
|
||||
if (new_init == arena->num_states())
|
||||
break; // All states have been solved
|
||||
// Compute new sccs
|
||||
scc_info::edge_filter ef
|
||||
= [](const twa_graph::edge_storage_t&,
|
||||
unsigned dst, void* subgame){
|
||||
const auto& sg = *static_cast<std::vector<unsigned>*>(subgame);
|
||||
return sg[dst] == unseen_mark ?
|
||||
scc_info::edge_filter_choice::keep :
|
||||
scc_info::edge_filter_choice::ignore;
|
||||
};
|
||||
info_ = std::make_unique<scc_info>(arena, new_init, ef, &subgame_);
|
||||
}
|
||||
// Every state needs a winner (solve_globally)
|
||||
// Or only those reachable
|
||||
assert((solve_globally
|
||||
&& std::all_of(w_.has_winner_.cbegin(), w_.has_winner_.cend(),
|
||||
[](bool b) { return b; }))
|
||||
|| (!solve_globally
|
||||
&& [&](){
|
||||
for (unsigned s = 0; s < arena->num_states(); ++s)
|
||||
{
|
||||
if ((info_->scc_of(s) != -1u)
|
||||
&& !w_.has_winner_.at(s))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}()));
|
||||
// Only the states owned by the winner need a strategy
|
||||
assert([&]()
|
||||
{
|
||||
for (unsigned v = 0; v < arena_->num_states(); ++v)
|
||||
{
|
||||
if (!solve_globally && (info_->scc_of(v) == -1u))
|
||||
continue;
|
||||
if (((*owner_ptr_)[v] == w_.winner(v))
|
||||
&& ((s_[v] <= 0) || (s_[v] > arena_->num_edges())))
|
||||
return false;
|
||||
|
|
@ -817,10 +877,10 @@ namespace spot
|
|||
} // anonymous
|
||||
|
||||
|
||||
bool solve_parity_game(const twa_graph_ptr& arena)
|
||||
bool solve_parity_game(const twa_graph_ptr& arena, bool solve_globally)
|
||||
{
|
||||
parity_game pg;
|
||||
return pg.solve(arena);
|
||||
return pg.solve(arena, solve_globally);
|
||||
}
|
||||
|
||||
bool solve_game(const twa_graph_ptr& arena)
|
||||
|
|
|
|||
|
|
@ -70,13 +70,19 @@ namespace spot
|
|||
/// This computes the winning strategy and winning region using
|
||||
/// Zielonka's recursive algorithm. \cite zielonka.98.tcs
|
||||
///
|
||||
/// By default only a 'local' strategy is computed:
|
||||
/// Only the part of the arena reachable from the init state is considered.
|
||||
/// If you want to compute a strategy for ALL states, set
|
||||
/// \a solve_globally to true
|
||||
///
|
||||
/// Also includes some inspiration from Oink.
|
||||
/// \cite vandijk.18.tacas
|
||||
///
|
||||
/// Returns the player winning in the initial state, and sets
|
||||
/// the state-winner and strategy named properties.
|
||||
SPOT_API
|
||||
bool solve_parity_game(const twa_graph_ptr& arena);
|
||||
bool solve_parity_game(const twa_graph_ptr& arena,
|
||||
bool solve_globally = false);
|
||||
|
||||
/// \ingroup games
|
||||
/// \brief Solve a safety game.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue