aboutsummaryrefslogtreecommitdiff
path: root/src/solvers/h48/solve_multithread.h
diff options
context:
space:
mode:
authorenricotenuti <tenutz_27@outlook.it>2024-09-29 12:38:43 +0200
committerenricotenuti <tenutz_27@outlook.it>2024-09-29 12:38:43 +0200
commit8fcfb3a33fe053ed2032d58ecc0b5d640c155931 (patch)
tree52c70a5829e93ad57cfe1101d2afa0693db91d53 /src/solvers/h48/solve_multithread.h
parent105259a58425a9ca1cec1b85339588410ae4fff7 (diff)
downloadnissy-core-8fcfb3a33fe053ed2032d58ecc0b5d640c155931.tar.gz
nissy-core-8fcfb3a33fe053ed2032d58ecc0b5d640c155931.zip
minor changes for PR
Diffstat (limited to 'src/solvers/h48/solve_multithread.h')
-rw-r--r--src/solvers/h48/solve_multithread.h300
1 files changed, 300 insertions, 0 deletions
diff --git a/src/solvers/h48/solve_multithread.h b/src/solvers/h48/solve_multithread.h
new file mode 100644
index 0000000..86171a9
--- /dev/null
+++ b/src/solvers/h48/solve_multithread.h
@@ -0,0 +1,300 @@
1#define MAX_QUEUE_SIZE 244
2#define BFS_DEPTH 2
3
4typedef struct {
5 dfsarg_solveh48_t tasks[MAX_QUEUE_SIZE];
6 int front;
7 int rear;
8 int tasks_count;
9 int active;
10 pthread_mutex_t mutex;
11 pthread_cond_t cond;
12 pthread_cond_t active_cond;
13 atomic_bool terminate;
14} task_queue_t;
15
16STATIC void solve_h48_appendsolution_thread(dfsarg_solveh48_t *, task_queue_t *);
17STATIC void init_queue(task_queue_t *);
18STATIC void submit_task(task_queue_t *, dfsarg_solveh48_t);
19STATIC void copy_queue(task_queue_t *, task_queue_t *, int, _Atomic int64_t *);
20STATIC void *start_thread(void *);
21STATIC int64_t solve_h48_bfs(dfsarg_solveh48_t *, task_queue_t *, int8_t);
22STATIC int64_t solve_h48_single(dfsarg_solveh48_t *, task_queue_t *);
23STATIC int64_t solve_h48_multithread(cube_t, int8_t, int8_t, int8_t, const void *, char *);
24
25STATIC void
26solve_h48_appendsolution_thread(dfsarg_solveh48_t *arg, task_queue_t *tq)
27{
28 pthread_mutex_lock(&tq->mutex);
29 int strl = 0;
30 uint8_t invertedpremoves[MAXLEN];
31 char *solution = *arg->nextsol;
32
33 strl = writemoves(arg->moves, arg->nmoves, *arg->nextsol);
34 *arg->nextsol += strl;
35
36 if (arg->npremoves)
37 {
38 **arg->nextsol = ' ';
39 (*arg->nextsol)++;
40
41 invertmoves(arg->premoves, arg->npremoves, invertedpremoves);
42 strl = writemoves(invertedpremoves, arg->npremoves, *arg->nextsol);
43 *arg->nextsol += strl;
44 }
45 LOG("Solution found: %s\n", solution);
46
47 **arg->nextsol = '\n';
48 (*arg->nextsol)++;
49 (*arg->nsols)++;
50 pthread_mutex_unlock(&tq->mutex);
51}
52
53STATIC void
54init_queue(task_queue_t *queue)
55{
56 queue->front = 0;
57 queue->rear = 0;
58 queue->tasks_count = 0;
59 queue->active = 0;
60 queue->terminate = ATOMIC_VAR_INIT(false);
61 pthread_mutex_init(&queue->mutex, NULL);
62 pthread_cond_init(&queue->cond, NULL);
63 pthread_cond_init(&queue->active_cond, NULL);
64}
65
66STATIC void
67submit_task(task_queue_t *queue, dfsarg_solveh48_t task)
68{
69 pthread_mutex_lock(&queue->mutex);
70 queue->tasks[queue->rear] = task;
71 queue->rear = (queue->rear + 1) % MAX_QUEUE_SIZE;
72 queue->tasks_count++;
73 pthread_cond_broadcast(&queue->cond);
74 pthread_mutex_unlock(&queue->mutex);
75}
76
77STATIC void
78copy_queue(task_queue_t *src, task_queue_t *dest, int depth, _Atomic int64_t *nsols)
79{
80 pthread_mutex_lock(&dest->mutex);
81 for (int i = src->front; i != src->rear; i = (i + 1) % MAX_QUEUE_SIZE)
82 {
83 dest->tasks[i] = src->tasks[i];
84 dest->tasks[i].depth = depth;
85 }
86 dest->front = src->front;
87 dest->rear = src->rear;
88 dest->tasks_count = src->tasks_count;
89 pthread_cond_broadcast(&dest->cond);
90 pthread_mutex_unlock(&dest->mutex);
91}
92
93STATIC void *
94start_thread(void *arg)
95{
96 task_queue_t *queue = (task_queue_t *)arg;
97 while (1) {
98 pthread_mutex_lock(&queue->mutex);
99 while (queue->tasks_count == 0 && !queue->terminate) {
100 pthread_cond_wait(&queue->cond, &queue->mutex);
101 }
102 if (queue->tasks_count == 0 && queue->terminate) {
103 pthread_mutex_unlock(&queue->mutex);
104 break;
105 }
106
107 if (queue->tasks_count > 0) {
108 dfsarg_solveh48_t task = queue->tasks[queue->front];
109 queue->front = (queue->front + 1) % MAX_QUEUE_SIZE;
110 queue->tasks_count--;
111 queue->active++;
112 pthread_mutex_unlock(&queue->mutex);
113
114 solve_h48_single(&task, queue);
115
116 pthread_mutex_lock(&queue->mutex);
117 queue->active--;
118
119 if(queue->tasks_count == 0 && queue->active == 0)
120 pthread_cond_signal(&queue->active_cond);
121 }
122 pthread_mutex_unlock(&queue->mutex);
123 }
124 return NULL;
125}
126
127STATIC int64_t
128solve_h48_bfs(dfsarg_solveh48_t *arg_zero, task_queue_t *tq, int8_t maxmoves)
129{
130 dfsarg_solveh48_t queue[MAX_QUEUE_SIZE];
131 int front = 0, rear = 0;
132 dfsarg_solveh48_t nextarg;
133 int depth = 0;
134 int nodes_at_current_depth = 1;
135 int nodes_at_next_depth = 0;
136 queue[rear++] = *arg_zero;
137
138 dfsarg_solveh48_t task_pool[MAX_QUEUE_SIZE];
139
140 while (front < rear){
141 dfsarg_solveh48_t arg = queue[front++];
142 nodes_at_current_depth--;
143
144 if (*arg.nsols == arg.maxsolutions)
145 return 1;
146
147 if (issolved(arg.cube)){
148 if (arg.nmoves + arg.npremoves >= arg.depth && arg.nmoves + arg.npremoves <= maxmoves)
149 solve_h48_appendsolution(&arg);
150 continue;
151 }
152
153 arg.nissbranch = MM_NORMAL;
154 uint32_t allowed = allowednextmove_h48(arg.moves, arg.nmoves, arg.nissbranch);
155
156 for (uint8_t m = 0; m < 18; m++){
157 if (allowed & (1 << m)){
158 nextarg = arg;
159 nextarg.nmoves = arg.nmoves + 1;
160 nextarg.moves[arg.nmoves] = m;
161 nextarg.cube = move(arg.cube, m);
162 nextarg.inverse = premove(arg.inverse, m);
163
164 if (nextarg.nmoves == BFS_DEPTH){
165 dfsarg_solveh48_t *task = &task_pool[rear % MAX_QUEUE_SIZE];
166 *task = nextarg;
167 submit_task(tq, *task);
168 } else {
169 queue[rear++] = nextarg;
170 nodes_at_next_depth++;
171 }
172 }
173 }
174 if (nodes_at_current_depth == 0){
175 nodes_at_current_depth = nodes_at_next_depth;
176 nodes_at_next_depth = 0;
177 LOG("Found %" PRId64 " solutions, searching at depth %" PRId8 "\n", *nextarg.nsols, depth++);
178 }
179 if (depth == BFS_DEPTH) return 0;
180 }
181 return 1;
182}
183
184STATIC int64_t
185solve_h48_single(dfsarg_solveh48_t *arg, task_queue_t *tq)
186{
187 dfsarg_solveh48_t nextarg;
188 int64_t ret;
189 uint8_t m;
190
191 if (*arg->nsols == arg->maxsolutions)
192 return 0;
193
194 if (solve_h48_stop(arg))
195 return 0;
196
197 if (issolved(arg->cube)){
198 if (arg->nmoves + arg->npremoves != arg->depth)
199 return 0;
200 solve_h48_appendsolution_thread(arg, tq);
201 return 1;
202 }
203
204 nextarg = *arg;
205 ret = 0;
206 uint32_t allowed;
207 if (arg->nissbranch & MM_INVERSE){
208 allowed = allowednextmove_h48(arg->premoves, arg->npremoves, arg->nissbranch);
209 for (m = 0; m < 18; m++){
210 if (allowed & (1 << m)){
211 nextarg.npremoves = arg->npremoves + 1;
212 nextarg.premoves[arg->npremoves] = m;
213 nextarg.inverse = move(arg->inverse, m);
214 nextarg.cube = premove(arg->cube, m);
215 ret += solve_h48_single(&nextarg, tq);
216 }
217 }
218 } else {
219 allowed = allowednextmove_h48(arg->moves, arg->nmoves, arg->nissbranch);
220 for (m = 0; m < 18; m++){
221 if (allowed & (1 << m)){
222 nextarg.nmoves = arg->nmoves + 1;
223 nextarg.moves[arg->nmoves] = m;
224 nextarg.cube = move(arg->cube, m);
225 nextarg.inverse = premove(arg->inverse, m);
226 ret += solve_h48_single(&nextarg, tq);
227 }
228 }
229 }
230 return ret;
231}
232
233STATIC int64_t
234solve_h48_multithread(
235 cube_t cube,
236 int8_t minmoves,
237 int8_t maxmoves,
238 int8_t maxsolutions,
239 const void *data,
240 char *solutions)
241{
242 _Atomic int64_t nsols = 0;
243 int p_depth = 0;
244 dfsarg_solveh48_t arg;
245 tableinfo_t info;
246 pthread_t threads[THREADS];
247
248 if (!readtableinfo_n(data, 2, &info)){
249 LOG("solve_h48: error reading table\n");
250 return 0;
251 }
252
253 arg = (dfsarg_solveh48_t){
254 .cube = cube,
255 .inverse = inverse(cube),
256 .nsols = &nsols,
257 .depth = minmoves,
258 .maxsolutions = maxsolutions,
259 .h = info.h48h,
260 .k = info.bits,
261 .cocsepdata = get_cocsepdata_ptr(data),
262 .h48data = get_h48data_ptr(data),
263 .nextsol = &solutions};
264
265 task_queue_t q;
266 init_queue(&q);
267 if (solve_h48_bfs(&arg, &q, maxmoves))
268 return nsols;
269
270 task_queue_t nq;
271 init_queue(&nq);
272
273 for (int i = 0; i < THREADS; i++){
274 pthread_create(&threads[i], NULL, &start_thread, &nq);
275 }
276
277 nsols = 0;
278 for (p_depth = minmoves > BFS_DEPTH ? minmoves : BFS_DEPTH;
279 p_depth <= maxmoves && nsols < maxsolutions;
280 p_depth++)
281 {
282 LOG("Found %" PRId64 " solutions, searching at depth %" PRId8 "\n", nsols, p_depth);
283 copy_queue(&q, &nq, p_depth, &nsols);
284
285 pthread_mutex_lock(&nq.mutex);
286 while (nq.active > 0 || nq.tasks_count > 0)
287 pthread_cond_wait(&nq.active_cond, &nq.mutex);
288 pthread_mutex_unlock(&nq.mutex);
289 }
290
291 atomic_store(&nq.terminate, true);
292 pthread_cond_broadcast(&nq.cond);
293
294 for (int i = 0; i < THREADS; i++){
295 pthread_join(threads[i], NULL);
296 }
297 **arg.nextsol = '\0';
298 (*arg.nextsol)++;
299 return nsols;
300}

Generated with cgit - Back to sebastiano.tronto.net