game: make a propagate_players() function public
* bin/ltlsynt.cc (complete_env): Replace this function by... * spot/misc/game.hh, spot/misc/game.cc (propagate_players): ... this new one, hiding the "state-player" business from ltlsynt. Also do not create a sink states unless necessary. * tests/core/ltlsynt.test: Adjust expected number of states.
This commit is contained in:
parent
41d088ea95
commit
9e8a842975
4 changed files with 75 additions and 50 deletions
|
|
@ -184,55 +184,8 @@ ARGMATCH_VERIFY(solver_args, solver_types);
|
|||
static solver opt_solver = SPLIT_DET;
|
||||
static bool verbose = false;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Ensures that the game is complete for player 0.
|
||||
// Also computes the owner of each state (false for player 0, i.e. env).
|
||||
// Initial state belongs to Player 0 and the game is turn-based.
|
||||
static std::vector<bool>*
|
||||
complete_env(spot::twa_graph_ptr& arena)
|
||||
{
|
||||
unsigned sink_env = arena->new_state();
|
||||
unsigned sink_con = arena->new_state();
|
||||
|
||||
auto um = arena->acc().unsat_mark();
|
||||
if (!um.first)
|
||||
throw std::runtime_error("game winning condition is a tautology");
|
||||
arena->new_edge(sink_con, sink_env, bddtrue, um.second);
|
||||
arena->new_edge(sink_env, sink_con, bddtrue, um.second);
|
||||
|
||||
std::vector<bool> seen(arena->num_states(), false);
|
||||
unsigned init = arena->get_init_state_number();
|
||||
std::vector<unsigned> todo({init});
|
||||
auto owner = new std::vector<bool>(arena->num_states(), false);
|
||||
(*owner)[init] = false;
|
||||
(*owner)[sink_env] = true;
|
||||
while (!todo.empty())
|
||||
{
|
||||
unsigned src = todo.back();
|
||||
todo.pop_back();
|
||||
seen[src] = true;
|
||||
bdd missing = bddtrue;
|
||||
for (const auto& e: arena->out(src))
|
||||
{
|
||||
if (!(*owner)[src])
|
||||
missing -= e.cond;
|
||||
|
||||
if (!seen[e.dst])
|
||||
{
|
||||
(*owner)[e.dst] = !(*owner)[src];
|
||||
todo.push_back(e.dst);
|
||||
}
|
||||
}
|
||||
if (!(*owner)[src] && missing != bddfalse)
|
||||
arena->new_edge(src, sink_con, missing, um.second);
|
||||
}
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
static spot::twa_graph_ptr
|
||||
to_dpa(const spot::twa_graph_ptr& split)
|
||||
{
|
||||
|
|
@ -548,8 +501,7 @@ namespace
|
|||
nb_states_dpa = dpa->num_states();
|
||||
if (want_time)
|
||||
sw.start();
|
||||
auto owner = complete_env(dpa);
|
||||
dpa->set_named_prop("state-player", owner);
|
||||
propagate_players(dpa, false, true);
|
||||
if (want_time)
|
||||
bgame_time = sw.stop();
|
||||
if (verbose)
|
||||
|
|
|
|||
|
|
@ -247,4 +247,61 @@ namespace spot
|
|||
|
||||
solve_rec(arena, owner, states_, m.max_set(), w, s);
|
||||
}
|
||||
|
||||
void propagate_players(spot::twa_graph_ptr& arena,
|
||||
bool first_player, bool complete0)
|
||||
{
|
||||
auto um = arena->acc().unsat_mark();
|
||||
if (!um.first)
|
||||
throw std::runtime_error("game winning condition is a tautology");
|
||||
|
||||
unsigned sink_env = 0;
|
||||
unsigned sink_con = 0;
|
||||
|
||||
std::vector<bool> seen(arena->num_states(), false);
|
||||
unsigned init = arena->get_init_state_number();
|
||||
std::vector<unsigned> todo({init});
|
||||
auto owner = new std::vector<bool>(arena->num_states(), false);
|
||||
(*owner)[init] = first_player;
|
||||
while (!todo.empty())
|
||||
{
|
||||
unsigned src = todo.back();
|
||||
todo.pop_back();
|
||||
seen[src] = true;
|
||||
bdd missing = bddtrue;
|
||||
for (const auto& e: arena->out(src))
|
||||
{
|
||||
bool osrc = (*owner)[src];
|
||||
if (complete0 && !osrc)
|
||||
missing -= e.cond;
|
||||
|
||||
if (!seen[e.dst])
|
||||
{
|
||||
(*owner)[e.dst] = !osrc;
|
||||
todo.push_back(e.dst);
|
||||
}
|
||||
else if ((*owner)[e.dst] == osrc)
|
||||
{
|
||||
delete owner;
|
||||
throw
|
||||
std::runtime_error("propagate_players(): odd cycle detected");
|
||||
}
|
||||
}
|
||||
if (complete0 && !(*owner)[src] && missing != bddfalse)
|
||||
{
|
||||
if (sink_env == 0)
|
||||
{
|
||||
sink_env = arena->new_state();
|
||||
sink_con = arena->new_state();
|
||||
owner->push_back(true);
|
||||
owner->push_back(false);
|
||||
arena->new_edge(sink_con, sink_env, bddtrue, um.second);
|
||||
arena->new_edge(sink_env, sink_con, bddtrue, um.second);
|
||||
}
|
||||
arena->new_edge(src, sink_con, missing, um.second);
|
||||
}
|
||||
}
|
||||
|
||||
arena->set_named_prop("state-player", owner);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,22 @@
|
|||
|
||||
namespace spot
|
||||
{
|
||||
|
||||
/// \brief Transform an automaton into a parity game by propagating
|
||||
/// players
|
||||
///
|
||||
/// This propagate state players, assuming the initial state belong
|
||||
/// to \a first_player, and alternating players on each transitions.
|
||||
/// If an odd cycle is detected, a runtime_exception is raised.
|
||||
///
|
||||
/// If \a complete0 is set, ensure that states of player 0 are
|
||||
/// complete.
|
||||
SPOT_API
|
||||
void propagate_players(spot::twa_graph_ptr& arena,
|
||||
bool first_player = false,
|
||||
bool complete0 = true);
|
||||
|
||||
|
||||
typedef std::unordered_set<unsigned> region_t;
|
||||
typedef std::unordered_map<unsigned, unsigned> strategy_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
set -e
|
||||
|
||||
cat >exp <<EOF
|
||||
parity 18;
|
||||
parity 16;
|
||||
0 1 0 1,2 "INIT";
|
||||
2 1 1 3;
|
||||
3 2 0 4,5;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue