python: add some parity-game bindings

* python/spot/impl.i: Process game.hh.
* spot/misc/game.cc, spot/misc/game.hh: Make the output of
parity_game_solve() a solved_game object for easier manipulation in
Python.
* bin/ltlsynt.cc: Adjust usage.
* tests/python/paritygame.ipynb: New file.
* tests/Makefile.am, doc/org/tut.org: Add it.
* NEWS: Mention these bindings.
This commit is contained in:
Alexandre Duret-Lutz 2020-09-09 15:26:59 +02:00
parent 9e8a842975
commit 760bde093b
8 changed files with 1040 additions and 16 deletions

View file

@ -230,9 +230,11 @@ namespace spot
}
}
void parity_game_solve(const const_twa_graph_ptr& arena,
region_t (&w)[2], strategy_t (&s)[2])
solved_game parity_game_solve(const const_twa_graph_ptr& arena)
{
solved_game result;
result.arena = arena;
const std::vector<bool>* owner =
ensure_parity_game(arena, "parity_game_solve");
@ -245,7 +247,10 @@ namespace spot
for (const auto& e: arena->edges())
m |= e.acc;
solve_rec(arena, owner, states_, m.max_set(), w, s);
solve_rec(arena, owner, states_, m.max_set(),
result.winning_region, result.winning_strategy);
return result;
}
void propagate_players(spot::twa_graph_ptr& arena,
@ -304,4 +309,44 @@ namespace spot
arena->set_named_prop("state-player", owner);
}
twa_graph_ptr
highlight_strategy(twa_graph_ptr& aut, const strategy_t& s,
unsigned color)
{
unsigned ns = aut->num_states();
auto* highlight = aut->get_or_set_named_prop<std::map<unsigned, unsigned>>
("highlight-edges");
for (auto [src, n]: s)
{
if (src >= ns)
throw std::runtime_error
("highlight_strategy(): strategy refers to unexisting states");
unsigned int i = 0;
for (auto& t: aut->out(src))
if (i++ == n)
{
(*highlight)[aut->edge_number(t)] = color;
break;
}
}
return aut;
}
twa_graph_ptr
solved_game::highlight_strategy(unsigned player, unsigned color)
{
auto aut = std::const_pointer_cast<twa_graph>(arena);
auto* highlight = aut->get_or_set_named_prop<std::map<unsigned, unsigned>>
("highlight-states");
unsigned ns = aut->num_states();
for (unsigned i = 0; i < ns; ++i)
if (player_winning_at(player, i))
(*highlight)[i] = color;
return spot::highlight_strategy(aut, winning_strategy[!!player], color);
}
}

View file

@ -50,6 +50,24 @@ namespace spot
typedef std::unordered_set<unsigned> region_t;
typedef std::unordered_map<unsigned, unsigned> strategy_t;
struct SPOT_API solved_game
{
const_twa_graph_ptr arena;
region_t winning_region[2];
strategy_t winning_strategy[2];
/// \brief Highlight the edges of a strategy on the automaton.
twa_graph_ptr highlight_strategy(unsigned player, unsigned color);
bool player_winning_at(unsigned player, unsigned state)
{
auto& w = winning_region[player];
return w.find(state) != w.end();
}
};
/// \brief solve a parity-game
///
/// The arena is a deterministic max odd parity automaton with a
@ -59,10 +77,16 @@ namespace spot
/// game for player 1 using Zielonka's recursive algorithm.
/// \cite zielonka.98.tcs
SPOT_API
void parity_game_solve(const const_twa_graph_ptr& arena,
region_t (&w)[2], strategy_t (&s)[2]);
solved_game parity_game_solve(const const_twa_graph_ptr& arena);
/// \brief Print a max odd parity game using PG-solver syntax
SPOT_API
void pg_print(std::ostream& os, const const_twa_graph_ptr& arena);
/// \brief Highlight the edges of a strategy on an automaton.
SPOT_API
twa_graph_ptr highlight_strategy(twa_graph_ptr& arena,
const strategy_t& s,
unsigned color);
}