aboutsummaryrefslogtreecommitdiff
path: root/src/solve.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/solve.c')
-rw-r--r--src/solve.c538
1 files changed, 458 insertions, 80 deletions
diff --git a/src/solve.c b/src/solve.c
index 2d0c94d..d4c0f18 100644
--- a/src/solve.c
+++ b/src/solve.c
@@ -1,122 +1,500 @@
1#define SOLVE_C
2
3#include "solve.h" 1#include "solve.h"
4 2
5void 3/* Local functions ***********************************************************/
6dfs(DfsArg *arg, Solver *solver, Threader *threader) 4
5static bool allowed_next(Move move, DfsArg *arg);
6static bool cancel_niss(DfsArg *arg);
7static void copy_dfsarg(DfsArg *src, DfsArg *dst);
8static void dfs(DfsArg *arg);
9static void dfs_branch(DfsArg *arg);
10static bool dfs_check_solved(DfsArg *arg);
11static bool dfs_switch(DfsArg *arg);
12static void dfs_niss(DfsArg *arg);
13static bool dfs_stop(DfsArg *arg);
14static void * instance_thread(void *arg);
15static void invert_branch(DfsArg *arg);
16static void multidfs(Cube c, Trans t, Step *s, SolveOptions *opts,
17 AlgList *sols, int d);
18static bool niss_makes_sense(DfsArg *arg);
19static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols);
20
21/* Local functions ***********************************************************/
22
23static bool
24allowed_next(Move m, DfsArg *arg)
25{
26 bool bad, allowed, order;
27 uint64_t mbit;
28
29 mbit = ((uint64_t)1) << m;
30 bad = mbit & arg->badmoves;
31 allowed = mbit & arg->step->moveset->mask[arg->last2][arg->last1];
32 order = !commute(arg->last1, m) || arg->last1 < m;
33
34 return allowed && !bad && order;
35}
36
37static bool
38cancel_niss(DfsArg *arg)
39{
40 Moveset *ms;
41 Move i1, i2;
42 bool p, p1, p2, q, q1, q2;
43
44 if (arg->last1inv == NULLMOVE)
45 return false;
46
47 ms = arg->step->moveset;
48 i1 = inverse_move(arg->last1inv);
49 i2 = inverse_move(arg->last2inv);
50
51 p1 = !ms->allowed_next(arg->last2, arg->last1, i1);
52 p2 = !ms->allowed_next(arg->last2, i1, arg->last1);
53 p = p1 || (commute(i1, arg->last1) && p2);
54
55 q1 = !ms->allowed_next(arg->last2, arg->last1, i2);
56 q2 = !ms->allowed_next(arg->last2, i2, arg->last1);
57 q = q1 || (commute(i2, arg->last1) && q2);
58
59 return p || (commute(i1, i2) && q);
60}
61
62static void
63copy_dfsarg(DfsArg *src, DfsArg *dst)
64{
65 dst->step = src->step;
66 dst->opts = src->opts;
67 dst->t = src->t;
68 dst->cube = src->cube;
69 dst->inverse = src->inverse;
70 dst->d = src->d;
71 dst->badmoves = src->badmoves;
72 dst->badmovesinv = src->badmovesinv;
73 dst->niss = src->niss;
74 dst->last1 = src->last1;
75 dst->last2 = src->last2;
76 dst->last1inv = src->last1inv;
77 dst->last2inv = src->last2inv;
78 dst->sols = src->sols;
79 dst->sols_mutex = src->sols_mutex;
80 dst->current_alg = src->current_alg;
81
82 copy_estimatedata(src->ed, dst->ed);
83}
84
85static void
86dfs(DfsArg *arg)
87{
88 bool sw = false;
89
90 if (dfs_stop(arg))
91 return;
92
93 if (dfs_check_solved(arg))
94 return;
95
96 if (arg->step->final && (sw = dfs_switch(arg)))
97 invert_branch(arg);
98 dfs_branch(arg);
99
100 if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg))
101 dfs_niss(arg);
102
103 if (sw)
104 invert_branch(arg);
105}
106
107static void
108dfs_branch(DfsArg *arg)
7{ 109{
8 int i; 110 int i;
9 DfsArg newarg;
10 Alg *sol;
11 Move m; 111 Move m;
112 DfsArg *newarg;
12 113
13 if (arg->current_alg->len > arg->d) 114 newarg = malloc(sizeof(DfsArg));
14 return; 115 newarg->ed = malloc(sizeof(EstimateData));
15 116
16 if (solver->is_solved(solver->param, arg->cubedata)) { 117 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) {
17/* TODO: the "all" option should be re-implemented as setting 118 m = arg->step->moveset->sorted_moves[i];
18validate to null */ 119 if (allowed_next(m, arg)) {
120 copy_dfsarg(arg, newarg);
121 newarg->last2 = arg->last1;
122 newarg->last1 = m;
123 newarg->cube = apply_move(m, arg->cube);
124 append_move(arg->current_alg, m, newarg->niss);
19 125
20/* TODO: we also have to check if cancel with NISS; 126 dfs(newarg);
21we can't because we have no access to the s->final field
22this should be done by the step's validator? */
23 sol = solver->validate_solution(solver->param,arg->current_alg);
24 bool accepted = sol != NULL;
25 bool too_short = arg->current_alg->len != arg->d;
26 127
27 if (accepted && !too_short) { 128 arg->current_alg->len--;
28/* TODO: arg->t got lost in refactoring */
29/* transform_alg(inverse_trans(arg->t), sol);*/
30 if (arg->opts->verbose)
31 print_alg(sol, false);
32 threader->append_sol(sol, arg->threaddata);
33 } 129 }
34 return;
35 } 130 }
36 131
37 if (arg->current_alg->len == arg->d) 132 free(newarg->ed);
38 return; 133 free(newarg);
134}
135
136static bool
137dfs_check_solved(DfsArg *arg)
138{
139 if (!arg->step->is_done(arg->cube))
140 return false;
141
142 if (arg->current_alg->len == arg->d) {
143 if ((arg->step->is_valid(arg->current_alg) || arg->opts->all)
144 && (!arg->step->final || !cancel_niss(arg))) {
145
146 pthread_mutex_lock(arg->sols_mutex);
147
148 if (arg->sols->len < arg->opts->max_solutions) {
149 append_alg(arg->sols, arg->current_alg);
150
151 transform_alg(
152 inverse_trans(arg->t),
153 arg->sols->last->alg
154 );
155 if (arg->step->final)
156 inplace(unniss, arg->sols->last->alg);
157
158 if (arg->opts->verbose)
159 print_alg(arg->sols->last->alg, false);
160 }
161
162 pthread_mutex_unlock(arg->sols_mutex);
163 }
164 }
165
166 return true;
167}
168
169static void
170dfs_niss(DfsArg *arg)
171{
172 DfsArg *newarg;
173
174 newarg = malloc(sizeof(DfsArg));
175 newarg->ed = malloc(sizeof(EstimateData));
176
177 copy_dfsarg(arg, newarg);
178 swapmove(&(newarg->last1), &(newarg->last1inv));
179 swapmove(&(newarg->last2), &(newarg->last2inv));
180 newarg->niss = !(arg->niss);
181 newarg->cube = inverse_cube(arg->cube);
182
183 dfs(newarg);
184
185 free(newarg->ed);
186 free(newarg);
187}
188
189static bool
190dfs_stop(DfsArg *arg)
191{
192 int lowerbound;
193 bool b;
194
195 lowerbound = arg->step->estimate(arg);
196 if (arg->opts->can_niss && !arg->niss)
197 lowerbound = MIN(1, lowerbound);
198
199 if (arg->current_alg->len + lowerbound > arg->d) {
200 b = true;
201 } else {
202 pthread_mutex_lock(arg->sols_mutex);
203 b = arg->sols->len >= arg->opts->max_solutions;
204 pthread_mutex_unlock(arg->sols_mutex);
205 }
206
207 return b;
208}
209
210static bool
211dfs_switch(DfsArg *arg)
212{
213 int i, bn, bi;
214
215 bn = 0;
216 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++)
217 if (allowed_next(arg->step->moveset->sorted_moves[i], arg))
218 bn++;
219
220 swapmove(&(arg->last1), &(arg->last1inv));
221 swapmove(&(arg->last2), &(arg->last2inv));
222 swapu64(&(arg->badmoves), &(arg->badmovesinv));
223
224 bi = 0;
225 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++)
226 if (allowed_next(arg->step->moveset->sorted_moves[i], arg))
227 bi++;
228
229 swapmove(&(arg->last1), &(arg->last1inv));
230 swapmove(&(arg->last2), &(arg->last2inv));
231 swapu64(&(arg->badmoves), &(arg->badmovesinv));
232
233 return bi < bn;
234}
235
236static void *
237instance_thread(void *arg)
238{
239 bool b;
240 Cube c;
241 ThreadDataSolve *td;
242 AlgListNode *node;
243 DfsArg darg;
244
245 td = (ThreadDataSolve *)arg;
246
247 while (1) {
248 b = false;
249
250 pthread_mutex_lock(td->start_mutex);
251 if ((node = *(td->node)) == NULL)
252 b = true;
253 else
254 *(td->node) = (*(td->node))->next;
255 pthread_mutex_unlock(td->start_mutex);
256
257 if (b)
258 break;
259
260 c = node->alg->inv[0] ?
261 apply_move(node->alg->move[0], inverse_cube(td->cube)) :
262 apply_move(node->alg->move[0], td->cube);
263
264 darg.step = td->step;
265 darg.opts = td->opts;
266 darg.t = td->t;
267 darg.cube = c;
268 darg.d = td->depth;
269 darg.niss = node->alg->inv[0];
270 darg.last1 = node->alg->move[0];
271 darg.last2 = NULLMOVE;
272 darg.last1inv = NULLMOVE;
273 darg.last2inv = NULLMOVE;
274 darg.sols = td->sols;
275 darg.sols_mutex = td->sols_mutex;
276 darg.current_alg = new_alg("");
277 append_move(darg.current_alg, node->alg->move[0],
278 node->alg->inv[0]);
279 darg.ed = malloc(sizeof(EstimateData));
280 reset_estimatedata(darg.ed);
281 darg.badmoves = 0;
282 darg.badmovesinv = 0;
283
284 dfs(&darg);
285
286 free_alg(darg.current_alg);
287 free(darg.ed);
288 }
289
290 return NULL;
291}
292
293static void
294invert_branch(DfsArg *arg)
295{
296 Cube aux;
297
298 aux = arg->cube;
299 arg->cube = is_solved(arg->inverse) ?
300 inverse_cube(arg->cube) : arg->inverse;
301 arg->inverse = aux;
302
303 swapu64(&(arg->badmoves), &(arg->badmovesinv));
304 arg->niss = !(arg->niss);
305 swapmove(&(arg->last1), &(arg->last1inv));
306 swapmove(&(arg->last2), &(arg->last2inv));
307 invert_estimatedata(arg->ed);
308}
309
310static void
311multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d)
312{
313 int i;
314 Alg *alg;
315 AlgList *start;
316 AlgListNode **node;
317 pthread_t t[opts->nthreads];
318 ThreadDataSolve td[opts->nthreads];
319 pthread_mutex_t *start_mutex, *sols_mutex;
39 320
40/* TODO: do not alloc */ 321 node = malloc(sizeof(AlgListNode *));
41 newarg.cubedata = solver->alloc_cubedata(solver->param); 322 start_mutex = malloc(sizeof(pthread_mutex_t));
42 for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { 323 sols_mutex = malloc(sizeof(pthread_mutex_t));
43 m = solver->moveset->sorted_moves[i];
44 if (solver->moveset->can_append(arg->current_alg, m, arg->niss)
45 && compare_last(arg->current_alg, m, arg->niss) >= 0) {
46 append_move(arg->current_alg, m, arg->niss);
47 324
48 solver->copy_cubedata( 325 start = new_alglist();
49 solver->param, arg->cubedata, newarg.cubedata); 326 pthread_mutex_init(start_mutex, NULL);
50 newarg.threaddata = arg->threaddata; 327 pthread_mutex_init(sols_mutex, NULL);
51 newarg.opts = arg->opts;
52 newarg.d = arg->d;
53 newarg.niss = arg->niss;
54 newarg.current_alg = arg->current_alg;
55 if (!solver->move_check_stop(
56 solver->param, &newarg, threader))
57 dfs(&newarg, solver, threader);
58 328
59 remove_last_move(arg->current_alg); 329 for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) {
330 alg = new_alg("");
331 append_move(alg, s->moveset->sorted_moves[i], false);
332 append_alg(start, alg);
333 if (opts->can_niss) {
334 alg->inv[0] = true;
335 append_alg(start, alg);
60 } 336 }
337 free_alg(alg);
61 } 338 }
62 solver->free_cubedata(solver->param, newarg.cubedata); 339 *node = start->first;
63 340
64 if (arg->opts->can_niss && !arg->niss && 341 for (i = 0; i < opts->nthreads; i++) {
65 solver->niss_makes_sense( 342 td[i].thid = i;
66 solver->param, arg->cubedata, arg->current_alg)) { 343 td[i].t = tr;
67 solver->invert_cube(solver->param, arg->cubedata); 344 td[i].cube = c;
68 arg->niss = true; 345 td[i].step = s;
69 dfs(arg, solver, threader); 346 td[i].depth = d;
347 td[i].opts = opts;
348 td[i].start = start;
349 td[i].node = node;
350 td[i].sols = sols;
351 td[i].start_mutex = start_mutex;
352 td[i].sols_mutex = sols_mutex;
353 pthread_create(&t[i], NULL, instance_thread, &td[i]);
70 } 354 }
355
356 for (i = 0; i < opts->nthreads; i++)
357 pthread_join(t[i], NULL);
358
359 free_alglist(start);
360 free(node);
361 free(start_mutex);
362 free(sols_mutex);
363}
364
365static bool
366niss_makes_sense(DfsArg *arg)
367{
368 Cube testcube;
369
370 testcube = apply_move(inverse_move(arg->last1), (Cube){0});
371 return arg->current_alg->len == 0 || !arg->step->is_done(testcube);
71} 372}
72 373
374static bool
375solvestop(int d, int op, SolveOptions *opts, AlgList *sols)
376{
377 bool opt_done, max_moves_exceeded, max_sols_exceeded;
378
379 opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op;
380 max_moves_exceeded = d > opts->max_moves;
381 max_sols_exceeded = sols->len >= opts->max_solutions;
382
383 return opt_done || max_moves_exceeded || max_sols_exceeded;
384}
385
386/* Public functions **********************************************************/
387
73AlgList * 388AlgList *
74solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader) 389solve(Cube cube, Step *step, SolveOptions *opts)
75{ 390{
76 int i, d, optimal; 391 bool ready;
77 bool ready[MAX_SOLVERS], stop, one_ready; 392 int i, d, op, nt;
78 DfsArg arg[MAX_SOLVERS];
79 AlgList *sols; 393 AlgList *sols;
394 Cube c;
395 Trans tt[NTRANS];
396
397 prepare_step(step, opts);
80 398
81 one_ready = false; 399 if (step->detect != NULL) {
82 for (i = 0; solver[i] != NULL; i++) { 400 nt = step->detect(cube, tt);
83 arg[i].cubedata = 401 } else {
84 solver[i]->prepare_cube(solver[i]->param, cube); 402 tt[0] = step->pre_trans;
85 arg[i].opts = opts; 403 ready = step->ready == NULL ||
86 ready[i] = arg[i].cubedata != NULL; 404 step->ready(apply_trans(tt[0], cube));
87 one_ready = one_ready || ready[i]; 405 nt = ready ? 1 : 0;
88 } 406 }
89 407
90 sols = new_alglist(); 408 sols = new_alglist();
91 if (!one_ready) { 409
92 fprintf(stderr, "Cube not ready for solving\n"); 410 if (nt == 0) {
411 fprintf(stderr, "Cube not ready for solving step: ");
412 fprintf(stderr, "%s\n", step->ready_msg);
93 return sols; 413 return sols;
94 } 414 }
95 415
96 optimal = opts->max_moves; 416 if (opts->min_moves == 0) {
97 stop = false; 417 for (i = 0; i < nt; i++) {
98 for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) { 418 c = apply_trans(tt[i], cube);
419 if (step->is_done(c)) {
420 append_alg(sols, new_alg(""));
421 return sols;
422 }
423 }
424 }
425
426 op = -1;
427 for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) {
99 if (opts->verbose) 428 if (opts->verbose)
100 fprintf(stderr, "Searching depth %d\n", d); 429 fprintf(stderr, "Searching depth %d\n", d);
101 430
102 for (i = 0; solver[i] != NULL && !stop; i++) { 431 for (i = 0; i < nt && !solvestop(d, op, opts, sols); i++) {
103 if (!ready[i]) 432 c = apply_trans(tt[i], cube);
104 continue; 433 multidfs(c, tt[i], step, opts, sols, d);
434 if (sols->len > 0 && op == -1)
435 op = d;
436 }
437 }
438
439 return sols;
440}
441
442/* TODO: make more general! */
443Alg *
444solve_2phase(Cube cube, int nthreads)
445{
446 int bestlen, newb;
447 Alg *bestalg, *ret;
448 AlgList *sols1, *sols2;
449 AlgListNode *i;
450 Cube c;
451 SolveOptions opts1, opts2;
105 452
106 arg[i].d = d; 453 opts1.min_moves = 0;
107 threader->dispatch(&arg[i], sols, solver[i], threader); 454 opts1.max_moves = 13;
455 opts1.max_solutions = 20;
456 opts1.nthreads = nthreads;
457 opts1.optimal = 3;
458 opts1.can_niss = false;
459 opts1.verbose = false;
460 opts1.all = true;
108 461
109 if (sols->len > 0) 462 opts2.min_moves = 0;
110 optimal = MIN(optimal, d); 463 opts2.max_moves = 19;
464 opts2.max_solutions = 1;
465 opts2.nthreads = nthreads;
466 opts2.can_niss = false;
467 opts2.verbose = false;
111 468
112 stop = sols->len >= opts->max_solutions; 469 /* We skip step1 if it is solved on any axis */
470 if (drany_HTM.is_done(cube)) {
471 sols1 = new_alglist();
472 append_alg(sols1, new_alg(""));
473 } else {
474 sols1 = solve(cube, &drany_HTM, &opts1);
475 }
476 bestalg = new_alg("");
477 bestlen = 999;
478 for (i = sols1->first; i != NULL; i = i->next) {
479 c = apply_alg(i->alg, cube);
480 sols2 = solve(c, &dranyfin_DR, &opts2);
481
482 if (sols2->len > 0) {
483 newb = i->alg->len + sols2->first->alg->len;
484 if (newb < bestlen) {
485 bestlen = newb;
486 copy_alg(i->alg, bestalg);
487 compose_alg(bestalg, sols2->first->alg);
488 }
113 } 489 }
114 stop = stop || 490
115 (opts->optimal != -1 && d >= opts->optimal + optimal); 491 free_alglist(sols2);
116 } 492 }
117 493
118/* TODO: some cleanup (free cubedata) */ 494 free_alglist(sols1);
119/* TODO: actually, preparation should be done somewhere else */
120 495
121 return sols; 496 ret = cleanup(bestalg);
497 free_alg(bestalg);
498
499 return ret;
122} 500}

Generated with cgit - Back to sebastiano.tronto.net