aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-09-29 14:12:01 +0200
committerGitHub <noreply@github.com>2024-09-29 14:12:01 +0200
commitbf6e1c3516a4eb0509c12b00d9a1baf6ee119987 (patch)
tree95ab133f9771c4791d5c784f1b3d4822b1dd7d3c
parent774a824a6c80b5af495f4fb99d98758e3b9f6b81 (diff)
parent7a52b4cd50a40e4bce919b6bd51203d0e9867141 (diff)
downloadnissy-core-bf6e1c3516a4eb0509c12b00d9a1baf6ee119987.tar.gz
nissy-core-bf6e1c3516a4eb0509c12b00d9a1baf6ee119987.zip
Merge pull request #3 from enricotenuti/master
Threaded solver
-rw-r--r--.gitignore4
-rw-r--r--src/nissy.c6
-rw-r--r--src/solvers/h48/h48.h1
-rw-r--r--src/solvers/h48/solve.h7
-rw-r--r--src/solvers/h48/solve_multithread.h300
-rw-r--r--tools/300_solve_small/solve_small.c4
6 files changed, 315 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore
index e9a1741..2e79f0a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,14 +1,18 @@
1.DS_Store
1config.mk 2config.mk
2gen 3gen
3debuggen 4debuggen
4flamegraph.html 5flamegraph.html
6utils/.DS_Store
5perf.data 7perf.data
6perf.data.old 8perf.data.old
7run 9run
8tables/* 10tables/*
9test/*/runtest 11test/*/runtest
12test/.DS_Store
10test/run 13test/run
11test/run.DSYM 14test/run.DSYM
15tools/.DS_Store
12run.DSYM 16run.DSYM
13run.core 17run.core
14test/last.* 18test/last.*
diff --git a/src/nissy.c b/src/nissy.c
index e610199..44efb83 100644
--- a/src/nissy.c
+++ b/src/nissy.c
@@ -1,5 +1,6 @@
1#include <inttypes.h> 1#include <inttypes.h>
2#include <pthread.h> 2#include <pthread.h>
3#include <stdatomic.h>
3#include <stdarg.h> 4#include <stdarg.h>
4#include <stdbool.h> 5#include <stdbool.h>
5#include <string.h> 6#include <string.h>
@@ -401,8 +402,9 @@ nissy_solve(
401 LOG("gendata: could not parse options\n"); 402 LOG("gendata: could not parse options\n");
402 ret = -1; 403 ret = -1;
403 } else { 404 } else {
404 ret = solve_h48(c, minmoves, maxmoves, maxsolutions, 405 ret = THREADS > 1 ?
405 data, solutions); 406 solve_h48_multithread(c, minmoves, maxmoves, maxsolutions, data, solutions) :
407 solve_h48(c, minmoves, maxmoves, maxsolutions, data, solutions);
406 } 408 }
407 } else if (!strcmp(solver, "h48stats")) { 409 } else if (!strcmp(solver, "h48stats")) {
408 ret = solve_h48stats(c, maxmoves, data, solutions); 410 ret = solve_h48stats(c, maxmoves, data, solutions);
diff --git a/src/solvers/h48/h48.h b/src/solvers/h48/h48.h
index 18153d1..176ce22 100644
--- a/src/solvers/h48/h48.h
+++ b/src/solvers/h48/h48.h
@@ -4,3 +4,4 @@
4#include "gendata_h48.h" 4#include "gendata_h48.h"
5#include "stats.h" 5#include "stats.h"
6#include "solve.h" 6#include "solve.h"
7#include "solve_multithread.h"
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h
index b67aedc..c2dce91 100644
--- a/src/solvers/h48/solve.h
+++ b/src/solvers/h48/solve.h
@@ -4,7 +4,7 @@ typedef struct {
4 int8_t nmoves; 4 int8_t nmoves;
5 int8_t depth; 5 int8_t depth;
6 uint8_t moves[MAXLEN]; 6 uint8_t moves[MAXLEN];
7 int64_t *nsols; 7 _Atomic int64_t *nsols;
8 int64_t maxsolutions; 8 int64_t maxsolutions;
9 uint8_t h; 9 uint8_t h;
10 uint8_t k; 10 uint8_t k;
@@ -167,7 +167,7 @@ solve_h48(
167 char *solutions 167 char *solutions
168) 168)
169{ 169{
170 int64_t nsols; 170 _Atomic int64_t nsols;
171 dfsarg_solveh48_t arg; 171 dfsarg_solveh48_t arg;
172 tableinfo_t info; 172 tableinfo_t info;
173 173
@@ -199,6 +199,7 @@ solve_h48(
199 arg.npremoves = 0; 199 arg.npremoves = 0;
200 solve_h48_dfs(&arg); 200 solve_h48_dfs(&arg);
201 } 201 }
202 202 **arg.nextsol = '\0';
203 (*arg.nextsol)++;
203 return nsols; 204 return nsols;
204} 205}
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}
diff --git a/tools/300_solve_small/solve_small.c b/tools/300_solve_small/solve_small.c
index 4d07728..d476bce 100644
--- a/tools/300_solve_small/solve_small.c
+++ b/tools/300_solve_small/solve_small.c
@@ -1,5 +1,3 @@
1#include <pthread.h>
2
3#include "../tool.h" 1#include "../tool.h"
4 2
5const char *solver = "h48"; 3const char *solver = "h48";
@@ -10,6 +8,8 @@ char *buf;
10char *scrambles[] = { 8char *scrambles[] = {
11 "R D' R2 D R U2 R' D' R U2 R D R'", /* 12 optimal */ 9 "R D' R2 D R U2 R' D' R U2 R D R'", /* 12 optimal */
12 "RLUD RLUD RLUD", /* 12 optimal */ 10 "RLUD RLUD RLUD", /* 12 optimal */
11 // "R' U' F D2 L2 F R2 U2 R2 B D2 L B2 D' B2 L' R' B D2 B U2 L U2 R' U' F", /* FMC2019 A1 - 16 optimal */
12 // "R' U' F D R F2 D L F D2 F2 L' U R' L2 D' R2 F2 R2 D L2 U2 R' U' F", /* FMC2024 A1 - 19 optimal */
13 NULL 13 NULL
14}; 14};
15 15

Generated with cgit - Back to sebastiano.tronto.net