-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathecv.hpp
More file actions
230 lines (197 loc) · 7.47 KB
/
ecv.hpp
File metadata and controls
230 lines (197 loc) · 7.47 KB
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/**
* @file ecv.hpp
* @brief Main header of the ecv library
* @author lhm
*/
#ifndef INCLUDE_ECV_HPP
#define INCLUDE_ECV_HPP
// Standard headers
#include <limits>
#include <memory>
#include <string>
#include <vector>
/*!
* \brief Main namespace of the \a ecv library
*/
namespace ecv {
/*!
* \brief State is the representation of an exact cover problem state
*/
typedef std::vector<std::string> State;
/*!
* \brief The LatinSquares class is the DLX implementation of an exact cover problem
* \see https://arxiv.org/pdf/cs/0011047v1.pdf for more informations about
* DLX (dancing links) algorithm.
*
* It basically is just a way of implementing backtracking, recursive, DFS algorithm
* to solve exact cover problems using circular double linked lists.
*/
class DLX
{
protected:
struct Solution
{ ///< A solution is a combinaison of rows
explicit Solution(const std::vector<int>& data) noexcept
: _d{ data }
{}
const std::vector<int> _d;
};
public:
virtual std::vector<Solution> solve(
uint32_t max_solutions = std::numeric_limits<uint32_t>::max()) noexcept;
protected:
/*!
* \brief DLX Create a DLX algorithm
* \param data The data of the adjacency matrix
* \param rows The number of rows in \a data
* \param cols The number of cols in \a data
* \param rowsList The list of row identifiers (usefull to parse problem state from solutions)
* \param primary The number of primary constraints.
* By default, every constraint is primary (meaning it has to be satisfied exactly once)
* Columns past \a primary index will be considered as 'secondary' (meaning the can be left
* unsatisfied)
*/
DLX(const std::vector<bool>& data,
size_t rows,
size_t cols,
const std::vector<int>& rowsList,
int primary = -1)
noexcept;
virtual ~DLX() noexcept = default;
protected:
struct Impl;
std::shared_ptr<Impl> pimpl{ nullptr };
};
/*!
* \brief The GenericProblem class allows to apply DLX algorithm on already formalized problems.
* That is, problems for which the adjacency matrix has already been created.
*/
class GenericProblem : public DLX
{
public:
/*!
* \brief generate Allows to create a generic exact cover problem from raw inputs.
* It can be usefull if you already have (or can easily build) an adjacency matrix.
*
* \param data An adjacency matrix
* \param rows The number of rows in \a data
* \param cols The number of columns in \a data
* \param primary The number of primary (i.e. essentials) constraints
* \return A generic exact cover problem in case of success, nullptr otherwise
*/
static std::unique_ptr<GenericProblem> generate(const std::vector<bool>& data,
size_t rows,
size_t cols,
int primary = -1) noexcept;
protected:
GenericProblem(const std::vector<bool>& data, size_t rows, size_t cols, int primary) noexcept;
};
/*!
* \brief The ConcreteProblem class is the base class for every concrete exact cover problems.
*/
class ConcreteProblem : public DLX
{
public:
/*!
* \brief apply Get the state of the concrete problem when applying a solution to it.
* \param s a solution (given by 'DLX::solve()')
* \return the state of the problem when applying the solution
*/
virtual State apply(const Solution& s) noexcept = 0;
protected:
ConcreteProblem(const std::vector<bool>& data,
size_t rows,
size_t cols,
const std::vector<int>& rowsList,
int primary = -1) noexcept;
virtual ~ConcreteProblem() noexcept = default;
};
/*!
* \brief The LatinSquares class is the implementation of the "latin squares" exact cover
* problem \see https://en.wikipedia.org/wiki/Latin_square for more informations about "latin
* squares"
*/
class LatinSquares : public ConcreteProblem
{
public:
static State make_empty_state(size_t rows = 1, size_t cols = 1) noexcept;
public:
/*!
* \brief generate Generate a data structure corresponding to the "latin squares"
* exact cover problem.
* \param state a String representation of the problem as a grid.
* Use '0' to represent non-constrained cells
* \return A "Latin square" exact cover problem pointer in case of success, nullptr otherwise
*/
static std::unique_ptr<LatinSquares> generate(const State& state = make_empty_state()) noexcept;
State apply(const Solution& s) noexcept override;
virtual ~LatinSquares() noexcept = default;
protected:
LatinSquares(const std::vector<bool>& data,
size_t rows,
size_t cols,
const std::vector<int>& rowsList,
const State& initStata) noexcept;
private:
const State _initState;
};
/*!
* \brief The Sudoku class is the implementation of the "sudoku" exact cover problem
* \see https://en.wikipedia.org/wiki/sudoku for more informations about "sudoku"
*/
class Sudoku : public ConcreteProblem
{
public:
static State make_empty_state() noexcept;
public:
/*!
* \brief generate Generate a data structure corresponding to the "sudoku"
* exact cover problem.
* \param state a String representation of the problem as a grid.
* Use '0' to represent non-constrained cells
* \return A "Sudoku" exact cover problem pointer in case of success, nullptr otherwise
*/
static std::unique_ptr<Sudoku> generate(const State& state = make_empty_state()) noexcept;
State apply(const Solution& s) noexcept override;
virtual ~Sudoku() noexcept = default;
protected:
Sudoku(const std::vector<bool>& data,
size_t rows,
size_t cols,
const std::vector<int>& rowsList,
const State& initStata) noexcept;
private:
const State _initState;
};
/*!
* \brief The NQueens class is the implementation of the "N Queen" exact cover problem, which is a
* generalization of the initial 8-Queen problem (\see
* https://en.wikipedia.org/wiki/Eight_queens_puzzle) for more informations about.
*/
class NQueens : public ConcreteProblem
{
public:
static State make_empty_state(size_t dim = 8) noexcept;
public:
/*!
* \brief generate Generate a data structure corresponding to the "N-Queen" exact cover problem.
* \param state a String representation of the problem as a grid.
* Use '0' to represent non-constrained (i.e. empty) cells, everything else for a cell with a
* Queen.
* \return A "N Queens" exact cover problem pointer in case of success, nullptr otherwise
*/
static std::unique_ptr<NQueens> generate(const State& state = make_empty_state()) noexcept;
State apply(const Solution& s) noexcept override;
virtual ~NQueens() noexcept = default;
protected:
NQueens(const std::vector<bool>& data,
size_t rows,
size_t cols,
const std::vector<int>& rowsList,
const State& initStata,
int primary) noexcept;
private:
const State _initState;
};
} // namespace ecv
#endif // INCLUDE_ECV_HPP