mCRL2
Loading...
Searching...
No Matches
ParityGame_IO.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
10#include "mcrl2/pbes/io.h"
12#include "mcrl2/pg/ParityGame.h"
13
14/* N.B. The PGSolver I/O functions reverse the priorities when reading/writing
15 the game description. This is done to preserve solutions, since PGSolver
16 considers higher values to dominate lower values, while I assume the opposite
17 (i.e. 0 is the `highest` priority) throughout the rest of the code. */
18
19void ParityGame::read_pgsolver( std::istream &is,
21{
22 priority_t max_prio = 0;
23 std::vector<ParityGameVertex> vertices;
25
26 // Read "parity" header line (if present)
27 char ch = 0;
28 while (!isalnum(ch)) is.get(ch);
29 is.putback(ch);
30 if (!isdigit(ch))
31 {
32 std::string parity;
33 verti max_vertex;
34
35 if (!(is >> parity >> max_vertex)) return;
36 if (parity != "parity") return;
37 vertices.reserve(max_vertex + 1);
38
39 // Skip to terminating semicolon
40 while (is.get(ch) && ch != ';') ch = 0;
41 }
42
43 // Read and discard "start" line (if present)
44 while (!isalnum(ch)) is.get(ch);
45 is.putback(ch);
46 if (!isdigit(ch))
47 {
48 std::string start;
49 verti vertex;
50
51 if (!(is >> start >> vertex)) return;
52 if (start != "start") return;
53
54 // Skip to terminating semicolon
55 while (is.get(ch) && ch != ';') ch = 0;
56 }
57
58 // Invalid vertex (used to mark uninitialized vertices)
59 ParityGameVertex invalid = { PLAYER_EVEN, (priority_t)-1 };
60
61 // Read vertex specs
62 while (is)
63 {
64 verti id;
65 int prio_raw, player_raw;
66
67 if (!(is >> id >> prio_raw >> player_raw)) break;
68
69 assert(prio_raw >= 0);
70 assert(prio_raw < 65536);
71 priority_t prio = prio_raw;
72
73 assert(player_raw == 0 || player_raw == 1);
74 player_t player = static_cast<player_t>(player_raw);
75
76 if (prio > max_prio) max_prio = prio;
77 if (id >= vertices.size()) vertices.resize(id + 1, invalid);
78
79 /* FIXME: the PGSolver file format description allows vertices to be
80 defined more than once (in that case, the old vertex should
81 be removed), but we currently don't support that. Instead,
82 just assert that each vertex is initialized once. */
83 assert(vertices[id] == invalid);
84
85 vertices[id].player = player;
86 vertices[id].priority = prio;
87
88 // Read successors
89 do {
90 verti succ;
91 if (!(is >> succ)) break;
92 if (succ >= vertices.size()) vertices.resize(succ + 1, invalid);
93
94 edges.push_back(std::make_pair(id, succ));
95
96 // Skip to separator (comma) or end-of-list (semicolon), while
97 // ignoring the contents of quoted strings.
98 bool quoted = false, escaped = false;
99 while (is.get(ch)) {
100 if (ch == '"' && !escaped) quoted = !quoted;
101 escaped = ch == '\\' && !escaped;
102 if ((ch == ',' || ch == ';') && !quoted) break;
103 }
104
105 } while (is && ch == ',');
106 }
107
108 // Ensure max_prio is even, so max_prio - p preserves parity:
109 if (max_prio%2 == 1) ++max_prio;
110
111 // Look for unused vertex indices:
112 std::vector<verti> vertex_map(vertices.size(), NO_VERTEX);
113 verti used = 0;
114 for (verti v = 0; v < (verti)vertices.size(); ++v)
115 {
116 if (vertices[v] != invalid) {
117 vertices[used] = vertices[v];
118 vertex_map[v] = used++;
119 }
120 }
121 if (used < (verti)vertices.size())
122 {
123 // Remove unused vertices:
124 vertices.erase(vertices.begin() + used, vertices.end());
125
126 // Remap edges to new vertex indices:
127 for ( StaticGraph::edge_list::iterator it = edges.begin();
128 it != edges.end(); ++it )
129 {
130 it->first = vertex_map[it->first];
131 it->second = vertex_map[it->second];
132 assert(it->first != NO_VERTEX && it->second != NO_VERTEX);
133 }
134 }
135
136 // Assign vertex info and recount cardinalities
137 reset((verti)vertices.size(), max_prio + 1);
138 for (std::size_t n = 0; n < vertices.size(); ++n)
139 {
140 assert(vertices[n] != invalid);
141 vertex_[n].player = vertices[n].player;
142 vertex_[n].priority = max_prio - vertices[n].priority;
143 }
144 recalculate_cardinalities(vertices.size());
145 vertices.clear();
146
147 // Assign graph
148 graph_.assign(edges, edge_dir);
149}
150
151void ParityGame::write_pgsolver(std::ostream &os) const
152{
153 // Get max priority and make it even so max_prio - p preserves parity:
154 int max_prio = d();
155 if (max_prio%2 == 1) --max_prio;
156
157 // Write out graph
158 os << "parity " << (long long)graph_.V() - 1 << ";\n";
159 for (verti v = 0; v < graph_.V(); ++v)
160 {
161 os << v << ' ' << (max_prio - priority(v)) << ' ' << player(v);
163 end = graph_.succ_end(v);
164 assert(it < end);
165 os << ' ' << *it++;
166 while (it != end) os << ',' << *it++;
167 os << ";\n";
168 }
169}
170
171void ParityGame::read_pbes( const std::string &file_path, verti *goal_vertex,
173 const std::string &rewrite_strategy )
174{
176 load_pbes(pbes, file_path);
177 assign_pbes(pbes, goal_vertex, edge_dir, rewrite_strategy);
178}
179
182 const std::string &rewrite_strategy)
183{
184 /* NOTE: this code assumes the vertices generated by parity_game_generator
185 are numbered from 2 to num_vertices-1 with no gaps, with 0 and 1
186 representing true and false (respectively) and 2 representing the
187 initial condition. */
188
189 if (goal_vertex) *goal_vertex = 2;
190
191 // Generate min-priority parity game
192 mcrl2::pbes_system::parity_game_generator pgg( pbes, true, true,
193 mcrl2::data::parse_rewrite_strategy(rewrite_strategy) );
194
195 // Build the edge list
197 verti begin = 0, end = 3;
198 for (verti v = begin; v < end; ++v)
199 {
200 std::set<std::size_t> deps = pgg.get_dependencies(v);
201 for ( std::set<std::size_t>::const_iterator it = deps.begin();
202 it != deps.end(); ++it )
203 {
204 verti w = (verti)*it;
205 assert(w >= begin);
206 if (w >= end) end = w + 1;
207 edges.push_back(std::make_pair(v - begin, w - begin));
208 }
209 }
210
211 // Determine maximum prioirity
212 int max_prio = 0;
213 for (verti v = begin; v < end; ++v)
214 {
215 max_prio = std::max(max_prio, (int)pgg.get_priority(v));
216 }
217
218 // Assign vertex info and recount cardinalities
219 reset(end - begin, max_prio + 1);
220 for (verti v = begin; v < end; ++v)
221 {
222 bool and_op = pgg.get_operation(v) ==
224 vertex_[v - begin].player = and_op ? PLAYER_ODD : PLAYER_EVEN;
225 vertex_[v - begin].priority = pgg.get_priority(v);
226 }
227 recalculate_cardinalities(end - begin);
228
229 // Assign graph
230 graph_.assign(edges, edge_dir);
231}
232
233void ParityGame::read_raw(std::istream &is)
234{
235 graph_.read_raw(is);
236 assert(is.good());
237 int d;
238 is.read((char*)&d, sizeof(d));
239 reset(graph_.V(), d);
240 is.read((char*)vertex_, sizeof(ParityGameVertex)*graph_.V());
241 is.read((char*)cardinality_, sizeof(verti)*d);
242}
243
244void ParityGame::write_raw(std::ostream &os) const
245{
246 graph_.write_raw(os);
247 assert(os.good());
248 os.write((const char*)&d_, sizeof(d_));
249 os.write((const char*)vertex_, sizeof(ParityGameVertex)*graph_.V());
250 os.write((const char*)cardinality_, sizeof(verti)*d_);
251}
252
253void ParityGame::write_dot(std::ostream &os) const
254{
255 os << "digraph {\n";
256 for (verti v = 0; v < graph_.V(); ++v)
257 {
258 bool even = player(v) == PLAYER_EVEN;
259 os << v << " ["
260 << "shape=" << (even ? "diamond" : "box") << ", "
261 << "label=\"" << priority(v) << " (" << v << ")\"]\n";
262
264 {
266 it != graph_.succ_end(v); ++it )
267 {
268 os << v << " -> " << *it;
269 // if (*it < v) os << " [color=red]";
270 os << ";\n";
271 }
272 }
273 else
274 {
276 it != graph_.pred_end(v); ++it )
277 {
278 os << *it << " -> " << v << ";\n";
279 }
280 }
281 }
282 os << "}\n";
283}
284
285void ParityGame::write_debug(const Strategy &s, std::ostream &os) const
286{
287 for (verti v = 0; v < graph_.V(); ++v)
288 {
289 os << v << ' ';
290
291 // Print controlling player and vertex priority:
292 char l = ' ', r = ' ';
293 if (player(v) == PLAYER_EVEN) l = '<', r = '>';
294 if (player(v) == PLAYER_ODD) l = '[', r = ']';
295 os << l << priority(v) << r;
296
297 // Print outgoing edges:
298 char sep = ' ';
300 it != graph_.succ_end(v); ++it)
301 {
302 os << sep << *it;
303 sep = ',';
304 }
305
306 // Print strategy (if applicable)
307 if (!s.empty() && s.at(v) != NO_VERTEX) os << " -> " << s.at(v);
308
309 os << '\n';
310 }
311 os << std::flush;
312}
std::size_t verti
type used to number vertices
Definition Graph.h:24
#define NO_VERTEX
Definition Graph.h:27
std::size_t priority_t
Definition ParityGame.h:32
player_t
Definition ParityGame.h:35
@ PLAYER_ODD
Odd (1)
Definition ParityGame.h:36
@ PLAYER_EVEN
Even (0)
Definition ParityGame.h:35
priority_t priority(verti v) const
Definition ParityGame.h:259
priority_t d() const
Definition ParityGame.h:253
Player player(verti v) const
Definition ParityGame.h:262
void reset(verti V, int d)
void write_pgsolver(std::ostream &os) const
StaticGraph graph_
Definition ParityGame.h:318
verti * cardinality_
Definition ParityGame.h:325
void assign_pbes(mcrl2::pbes_system::pbes &pbes, verti *goal_vertex=0, StaticGraph::EdgeDirection edge_dir=StaticGraph::EDGE_BIDIRECTIONAL, const std::string &rewrite_strategy="jitty")
void read_pgsolver(std::istream &is, StaticGraph::EdgeDirection edge_dir=StaticGraph::EDGE_BIDIRECTIONAL)
void write_dot(std::ostream &os) const
void read_raw(std::istream &is)
void write_debug(const Strategy &s=Strategy(), std::ostream &os=std::cerr) const
void write_raw(std::ostream &os) const
void recalculate_cardinalities(verti num_vertices)
ParityGameVertex * vertex_
Definition ParityGame.h:321
void read_pbes(const std::string &file_path, verti *goal_vertex=0, StaticGraph::EdgeDirection edge_dir=StaticGraph::EDGE_BIDIRECTIONAL, const std::string &rewrite_strategy="jitty")
std::vector< verti > Strategy
Definition ParityGame.h:97
std::vector< std::pair< verti, verti > > edge_list
Definition Graph.h:74
const_iterator succ_end(verti v) const
Definition Graph.h:193
EdgeDirection edge_dir() const
Definition Graph.h:185
void read_raw(std::istream &is)
Definition Graph.cpp:474
const_iterator succ_begin(verti v) const
Definition Graph.h:188
void write_raw(std::ostream &os) const
Definition Graph.cpp:457
verti V() const
Definition Graph.h:179
void assign(const StaticGraph &graph)
Definition Graph.cpp:288
const_iterator pred_begin(verti v) const
Definition Graph.h:198
EdgeDirection
Definition Graph.h:84
@ EDGE_SUCCESSOR
Definition Graph.h:86
const_iterator pred_end(verti v) const
Definition Graph.h:203
const verti * const_iterator
Definition Graph.h:66
size_type size() const
Returns the number of arguments of this term.
Definition aterm.h:151
Class for generating a BES from a PBES. This BES can be interpreted as a graph corresponding to a par...
virtual operation_type get_operation(std::size_t index)
Returns the vertex type.
virtual std::size_t get_priority(std::size_t index)
Returns the priority of a vertex. The priority of the first equation is 0 if it is a maximal fixpoint...
virtual std::set< std::size_t > get_dependencies(std::size_t index)
Returns the successors of a vertex in the graph.
parameterized boolean equation system
Definition pbes.h:58
rewrite_strategy parse_rewrite_strategy(const std::string &s)
standard conversion from string to rewrite strategy
A class for generating a parity game from a pbes.
IO routines for boolean equation systems.
player_t player
the vertex owner (i.e. next player to move)
Definition ParityGame.h:62
priority_t priority
the priority of the vertex between 0 and d (exclusive).
Definition ParityGame.h:65