-
Notifications
You must be signed in to change notification settings - Fork 10
/
oink.hpp
176 lines (144 loc) · 5.28 KB
/
oink.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
* Copyright 2017-2018 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OINK_HPP
#define OINK_HPP
#include <iostream>
#include <vector>
#include "oink/error.hpp"
#include "oink/game.hpp"
#include "oink/uintqueue.hpp"
namespace pg {
class Solver;
class Oink
{
public:
/**
* Construct a solver for the given game, sending log output to <out>.
*/
Oink(Game &game, std::ostream &out=std::cout);
virtual ~Oink();
/**
* After configuring Oink, use run() to run the solver.
*/
void run();
/**
* Instruct Oink to use the given solver.
*/
void setSolver(int solverid);
void setSolver(std::string label);
/**
* Instruct Oink to inflate as a preprocessing step.
*/
void setInflate() { inflate = true; renumber = false; compress = false; }
/**
* Instruct Oink to compress as a preprocessing step.
*/
void setCompress() { inflate = false; compress = true; renumber = false; }
/**
* Instruct Oink to renumber as a preprocessing step.
*/
void setRenumber() { inflate = false; compress = false; renumber = true; }
/**
* Instruct Oink whether to remove self-loops as a preprocessing step. (Default true)
*/
void setRemoveLoops(bool val) { removeLoops = val; }
/**
* Instruct Oink whether to solve winner-controlled winning cycles as a preprocessing step. (Default true)
*/
void setRemoveWCWC(bool val) { removeWCWC = val; }
/**
* Instruct Oink whether to solve single parity games. (Default true)
*/
void setSolveSingle(bool val) { solveSingle = val; }
/**
* Instruct Oink whether solve per bottom SCC. (Default false)
*/
void setBottomSCC(bool val) { bottomSCC = val; }
/**
* Set the number of workers for parallel solvers (psi and zielonka).
* -1 for sequential code, 0 for autodetect.
*/
void setWorkers(int count) { workers = count; }
/**
* Set verbosity level (0 = normal, 1 = trace, 2 = debug)
*/
void setTrace(int level) { trace = level; }
/**
* Mark node <node> as won by <winner> with strategy <strategy>.
* (Set <strategy> to -1 for no strategy.)
* After marking nodes, call flush().
*/
void solve(int node, int winner, int strategy);
/**
* After marking nodes as solved using solve(), flush attracts to the solved dominion.
*/
void flush(void);
protected:
/**
* Solve winner-controlled winning cycles.
* Returns number of cycles solved.
*/
int solveTrivialCycles(void);
/**
* Resolve self-loops.
* Returns number of resolved self-loops.
*/
int solveSelfloops(void);
/**
* Solve single parity games.
* Returns true if the game was solved as a single parity game.
*/
bool solveSingleParity(void);
/**
* Find a bottom SCC starting from the first non-disabled node.
* Avoids "disabled" nodes.
* (if nonempty is set, only obtain a non-empty bottom SCC.)
*/
void getBottomSCC(std::vector<int> &scc, bool nonempty=false);
/**
* Find a bottom SCC starting from the given node.
* Avoids "disabled" nodes.
* (if nonempty is set, only obtain a non-empty bottom SCC.)
*/
void getBottomSCC(int start, std::vector<int> &scc, bool nonempty=false);
/**
* Tarjan's SCC algorithm, modified to only compute the bottom SCC and avoid disabled nodes.
*/
void tarjan(int start_node, std::vector<int> &res, bool nonempty);
/**
* Run the solver in a loop until the game is solved.
*/
void solveLoop(void);
friend void _solve_loop(Oink*); // access point from a Lace worker
Game *game; // game being solved
std::ostream &logger; // logger for trace/debug messages
int solver = -1; // which solver to use
int workers = -1; // number of workers, 0 = autodetect, -1 = use non parallel
int trace = 0; // verbosity (0 for normal, 1 for trace, 2 for debug)
bool inflate = false; // inflate the game before solving
bool compress = false; // compress the game before solving
bool renumber = false; // renumber the game before solving (removes gaps)
bool removeLoops = true; // resolve self-loops before solving
bool removeWCWC = true; // solve winner-controlled winning cycles before solving
bool solveSingle = true; // solve games with only 1 parity
bool bottomSCC = false; // solve per bottom SCC
uintqueue todo; // internal queue for solved nodes for flushing
int *outcount; // number of unsolved outgoing edges per node (for fast attraction)
bitset disabled; // which vertices are disabled
friend class pg::Solver; // to allow access to edges
};
}
#endif