mCRL2
Loading...
Searching...
No Matches
RecursiveSolver.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2013 University of Twente
2// Copyright (c) 2009-2013 Michael Weber <michaelw@cs.utwente.nl>
3// Copyright (c) 2009-2013 Maks Verver <maksverver@geocities.com>
4// Copyright (c) 2009-2013 Eindhoven University of Technology
5//
6// Distributed under the Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9
11#include "mcrl2/pg/DenseSet.h"
13
20static std::vector<verti> get_complement(verti V, const DenseSet<verti> &s)
21{
22 std::vector<verti> res;
23 verti n = V - s.size();
24 res.reserve(n);
25 DenseSet<verti>::const_iterator it = s.begin(), end = s.end();
26 verti v = 0;
27 while (it != end)
28 {
29 verti w = *it;
30 while (v < w) res.push_back(v++);
31 ++v;
32 ++it;
33 }
34 while (v < V) res.push_back(v++);
35 assert(n == (verti)res.size());
36 return res;
37}
38
45{
46 int d = game.d();
47 int q = 0;
48 while (q < d && game.cardinality(q) == 0) ++q;
49 int p = q + 1;
50 while (p < d && game.cardinality(p) == 0) p += 2;
51 return p < d ? p : d;
52}
53
55 : ParityGameSolver(game)
56{
57}
58
60{
61}
62
64{
68 Substrategy substrat(strategy);
69 if (!solve(game, substrat)) strategy.clear();
70 return strategy;
71}
72
73/* Implementation note: the recursive solver might use either a DenseSet or
74 a std::set to store vertex sets (which are passed to make_attractor_set).
75 The former is faster when the size of these sets is large, but requires O(V)
76 time and memory to initialize, which is costly when these sets are small.
77
78 It seems that the benefit of faster lookups during attractor set computation
79 usually tips the balance in favor of the DenseSet.
80
81 Note that hash sets cannot readily be used because get_complement() expects
82 iterators to produce the set contents in-order.
83*/
84
86{
87 if (aborted()) return false;
88
89 std::size_t prio;
90 while ((prio = first_inversion(game)) < game.d())
91 {
92 mCRL2log(mcrl2::log::debug) <<"prio=" << prio << std::endl;
93
94 const StaticGraph &graph = game.graph();
95 const verti V = graph.V();
96 std::vector<verti> unsolved;
97
98 // Compute attractor set of minimum priority vertices:
99 {
100 ParityGame::Player player = (ParityGame::Player)((prio - 1)%2);
101 //std::set<verti> min_prio_attr;
102 DenseSet<verti> min_prio_attr(0, V);
103 for (verti v = 0; v < V; ++v)
104 {
105 if (game.priority(v) < prio) min_prio_attr.insert(v);
106 }
107 mCRL2log(mcrl2::log::debug) <<"|min_prio|=" << min_prio_attr.size() << std::endl;
108 assert(!min_prio_attr.empty());
109 make_attractor_set_2(game, player, min_prio_attr, strat);
110 mCRL2log(mcrl2::log::debug) << "|min_prio_attr|=" << min_prio_attr.size() << std::endl;
111 if (min_prio_attr.size() == V) break;
112 get_complement(V, min_prio_attr).swap(unsolved);
113 }
114
115 // Solve vertices not in the minimum priority attractor set:
116 {
117 ParityGame subgame;
118 subgame.make_subgame(game, unsolved.begin(), unsolved.end(),
120 Substrategy substrat(strat, unsolved);
121 if (!solve(subgame, substrat)) return false;
122
123 // Compute attractor set of all vertices won by the opponent:
125 //std::set<verti> lost_attr;
126 DenseSet<verti> lost_attr(0, V);
127 for ( std::vector<verti>::const_iterator it = unsolved.begin();
128 it != unsolved.end(); ++it )
129 {
130 if (strat.winner(*it, game.player(*it)) == opponent)
131 {
132 lost_attr.insert(*it);
133 }
134 }
135 mCRL2log(mcrl2::log::debug) << "|lost|=" << lost_attr.size() << std::endl;
136 if (lost_attr.empty()) break;
137 make_attractor_set_2(game, opponent, lost_attr, strat);
138 mCRL2log(mcrl2::log::debug) << "|lost_attr|=" << lost_attr.size() << std::endl;
139 get_complement(V, lost_attr).swap(unsolved);
140 }
141
142 // Repeat with subgame of which vertices won by odd have been removed:
143 {
144 ParityGame subgame;
145 subgame.make_subgame(game, unsolved.begin(), unsolved.end(),
147 Substrategy substrat(strat, unsolved);
148 strat.swap(substrat);
149 game.swap(subgame);
150 }
151 }
152
153 // If we get here, then the opponent's winning set was empty; the strategy
154 // for most vertices has already been initialized, except for those with
155 // minimum priority. Since the whole game is won by the current player, it
156 // suffices to pick an arbitrary successor for these vertices:
157 const StaticGraph &graph = game.graph();
158 const verti V = graph.V();
160 {
161 for (verti v = 0; v < V; ++v)
162 {
163 if (game.priority(v) < prio)
164 {
165 if (game.player(v) == game.priority(v)%2)
166 {
167 strat[v] = *graph.succ_begin(v);
168 }
169 else
170 {
171 strat[v] = NO_VERTEX;
172 }
173 }
174 }
175 }
176 else
177 {
178 // NOTE: this assumes the graph is a proper game graph!
179 // If there are min. priority vertices without any successors, we won't
180 // be able to find them this way!
181 for (verti w = 0; w < V; ++w)
182 {
183 for (StaticGraph::const_iterator it = graph.pred_begin(w);
184 it != graph.pred_end(w); ++it)
185 {
186 const verti v = *it;
187
188 if (game.priority(v) < prio)
189 {
190 if (game.player(v) == game.priority(v)%2)
191 {
192 strat[v] = w;
193 }
194 else
195 {
196 strat[v] = NO_VERTEX;
197 }
198 }
199 }
200 }
201 }
202 return true;
203}
204
206 const verti *vertex_map, verti vertex_map_size )
207{
208 (void)vertex_map; // unused
209 (void)vertex_map_size; // unused
210
211 return new RecursiveSolver(game);
212}
std::size_t verti
type used to number vertices
Definition Graph.h:24
#define NO_VERTEX
Definition Graph.h:27
player_t
Definition ParityGame.h:35
player_t opponent(const player_t p)
Definition ParityGame.h:40
static std::vector< verti > get_complement(verti V, const DenseSet< verti > &s)
int first_inversion(const ParityGame &game)
int first_inversion(const ParityGame &game)
void make_attractor_set_2(const ParityGame &game, ParityGame::Player player, SetT &vertices, StrategyT &strategy)
bool aborted()
Returns whether this instance has been aborted.
Definition Abortable.h:25
iterator begin()
Definition DenseSet.h:127
bool empty() const
Definition DenseSet.h:113
std::pair< iterator, bool > insert(const Key &k)
Definition DenseSet.h:171
size_type size() const
Definition DenseSet.h:108
iterator end()
Definition DenseSet.h:134
const ParityGame & game() const
const ParityGame & game_
Game being solved.
priority_t priority(verti v) const
Definition ParityGame.h:259
verti cardinality(int p) const
Definition ParityGame.h:266
priority_t d() const
Definition ParityGame.h:253
void make_subgame(const ParityGame &game, ForwardIterator vertices_begin, ForwardIterator vertices_end, bool proper, StaticGraph::EdgeDirection edge_dir=StaticGraph::EDGE_NONE)
Player player(verti v) const
Definition ParityGame.h:262
void swap(ParityGame &pg)
void assign(const ParityGame &game)
player_t Player
Definition ParityGame.h:87
const StaticGraph & graph() const
Definition ParityGame.h:256
std::vector< verti > Strategy
Definition ParityGame.h:97
ParityGameSolver * create(const ParityGame &game, const verti *vertex_map, verti vertex_map_size)
Returns a new ResuriveSolver instance.
ParityGame::Strategy solve()
RecursiveSolver(const ParityGame &game)
EdgeDirection edge_dir() const
Definition Graph.h:185
const_iterator succ_begin(verti v) const
Definition Graph.h:188
verti V() const
Definition Graph.h:179
const_iterator pred_begin(verti v) const
Definition Graph.h:198
@ EDGE_SUCCESSOR
Definition Graph.h:86
@ EDGE_PREDECESSOR
Definition Graph.h:87
const_iterator pred_end(verti v) const
Definition Graph.h:203
const verti * const_iterator
Definition Graph.h:66
ParityGame::Player winner(verti v, ParityGame::Player p)
Returns the winner for vertex v assuming it is controlled by p.
void swap(Substrategy &other)
Swaps this substrategy ovbect with another.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391