aboutsummaryrefslogtreecommitdiff
path: root/src/solvers/h48/solve.h
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2025-11-23 16:16:31 +0100
committerSebastiano Tronto <sebastiano@tronto.net>2025-11-24 16:32:11 +0100
commit147b0c3c4615c32478a4923242909b8ae5a30d03 (patch)
tree5294d9b3655031535085a5163c2c5b5cbe7413b1 /src/solvers/h48/solve.h
parent78ec0d22d927bc4287aa090469d5ba5f84e8780b (diff)
downloadnissy-core-147b0c3c4615c32478a4923242909b8ae5a30d03.tar.gz
nissy-core-147b0c3c4615c32478a4923242909b8ae5a30d03.zip
Fix duplicate solutions, overflow in maxsols and improve symmetry reduction for H48.
This commit fixes two bugs: - A bug that caused duplicates solutions for symmetric scrambles. - An overflow in the maxsols parameter for the H48 solver, which caused it to find much fewer solutions than existed. Moreover, the H48 solvers has been improved by reducing by symmetry not only from the starting position, but also up to the first 4 moves.
Diffstat (limited to 'src/solvers/h48/solve.h')
-rw-r--r--src/solvers/h48/solve.h78
1 files changed, 41 insertions, 37 deletions
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h
index bf10723..ad66fd4 100644
--- a/src/solvers/h48/solve.h
+++ b/src/solvers/h48/solve.h
@@ -13,6 +13,7 @@ typedef struct {
13 cube_t cube; 13 cube_t cube;
14 uint8_t moves[H48_STARTING_MOVES]; 14 uint8_t moves[H48_STARTING_MOVES];
15 int64_t rank; 15 int64_t rank;
16 uint64_t tmask[H48_STARTING_MOVES];
16} solve_h48_task_t; 17} solve_h48_task_t;
17 18
18typedef struct { 19typedef struct {
@@ -22,6 +23,7 @@ typedef struct {
22 int8_t target_depth; 23 int8_t target_depth;
23 solution_moves_t *solution_moves; 24 solution_moves_t *solution_moves;
24 solution_settings_t *solution_settings; 25 solution_settings_t *solution_settings;
26 const uint64_t *tmask;
25 solution_list_t *solution_list; 27 solution_list_t *solution_list;
26 int8_t lb_normal; 28 int8_t lb_normal;
27 int8_t lb_inverse; 29 int8_t lb_inverse;
@@ -55,6 +57,7 @@ typedef struct {
55 int8_t minmoves; 57 int8_t minmoves;
56 int8_t maxmoves; 58 int8_t maxmoves;
57 int8_t *shortest_sol; 59 int8_t *shortest_sol;
60 uint64_t tmask[H48_STARTING_MOVES];
58} dfsarg_solve_h48_maketasks_t; 61} dfsarg_solve_h48_maketasks_t;
59 62
60STATIC long long solve_h48_dispatch(oriented_cube_t, const char *, unsigned, 63STATIC long long solve_h48_dispatch(oriented_cube_t, const char *, unsigned,
@@ -69,7 +72,7 @@ STATIC void *solve_h48_runthread(void *);
69STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]); 72STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]);
70STATIC void solve_h48_log_solutions(solution_list_t [static 1], size_t); 73STATIC void solve_h48_log_solutions(solution_list_t [static 1], size_t);
71STATIC int solve_h48_compare_tasks(const void *, const void *); 74STATIC int solve_h48_compare_tasks(const void *, const void *);
72STATIC int64_t solve_h48(oriented_cube_t, uint8_t, uint8_t, uint8_t, uint8_t, 75STATIC int64_t solve_h48(oriented_cube_t, uint8_t, uint8_t, uint64_t, uint8_t,
73 uint8_t, uint64_t, const unsigned char *, size_t, char *, 76 uint8_t, uint64_t, const unsigned char *, size_t, char *,
74 long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *); 77 long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *);
75 78
@@ -208,8 +211,8 @@ solve_h48_dfs(dfsarg_solve_h48_t arg[static 1])
208 if (arg->target_depth != nm) 211 if (arg->target_depth != nm)
209 return 0; 212 return 0;
210 wrapthread_mutex_lock(arg->solutions_mutex); 213 wrapthread_mutex_lock(arg->solutions_mutex);
211 ret = appendsolution(arg->solution_moves, 214 ret = appendsolution(arg->solution_moves, H48_STARTING_MOVES,
212 arg->solution_settings, arg->solution_list); 215 arg->tmask, arg->solution_settings, arg->solution_list);
213 wrapthread_mutex_unlock(arg->solutions_mutex); 216 wrapthread_mutex_unlock(arg->solutions_mutex);
214 return ret; 217 return ret;
215 } 218 }
@@ -313,6 +316,7 @@ solve_h48_runthread(void *arg)
313 dfsarg->use_lb_inverse = false; 316 dfsarg->use_lb_inverse = false;
314 dfsarg->movemask_normal = MM18_ALLMOVES; 317 dfsarg->movemask_normal = MM18_ALLMOVES;
315 dfsarg->movemask_inverse = MM18_ALLMOVES; 318 dfsarg->movemask_inverse = MM18_ALLMOVES;
319 dfsarg->tmask = dfsarg->tasks[i].tmask;
316 320
317 solve_h48_dfs(dfsarg); 321 solve_h48_dfs(dfsarg);
318 322
@@ -341,7 +345,7 @@ solve_h48_runthread_end:
341STATIC int64_t 345STATIC int64_t
342solve_h48_maketasks( 346solve_h48_maketasks(
343 dfsarg_solve_h48_t solve_arg[static 1], 347 dfsarg_solve_h48_t solve_arg[static 1],
344 dfsarg_solve_h48_maketasks_t maketasks_arg[static 1], 348 dfsarg_solve_h48_maketasks_t mtarg[static 1],
345 solve_h48_task_t tasks[static H48_STARTING_CUBES], 349 solve_h48_task_t tasks[static H48_STARTING_CUBES],
346 int ntasks[static 1] 350 int ntasks[static 1]
347) 351)
@@ -353,59 +357,60 @@ solve_h48_maketasks(
353 cube_t backup_cube; 357 cube_t backup_cube;
354 solution_moves_t moves; 358 solution_moves_t moves;
355 359
356 if (equal(maketasks_arg->cube, SOLVED_CUBE)) { 360 if (equal(mtarg->cube, SOLVED_CUBE)) {
357 if (maketasks_arg->nmoves > maketasks_arg->maxmoves || 361 if (mtarg->nmoves > mtarg->maxmoves ||
358 maketasks_arg->nmoves < maketasks_arg->minmoves || 362 mtarg->nmoves < mtarg->minmoves ||
359 solutions_done(solve_arg->solution_list, 363 solutions_done(solve_arg->solution_list,
360 solve_arg->solution_settings, maketasks_arg->nmoves)) 364 solve_arg->solution_settings, mtarg->nmoves))
361 return NISSY_OK; 365 return NISSY_OK;
362 366
363 solution_moves_reset(&moves); 367 solution_moves_reset(&moves);
364 moves.nmoves = maketasks_arg->nmoves; 368 moves.nmoves = mtarg->nmoves;
365 memcpy(moves.moves, 369 memcpy(moves.moves, mtarg->moves, mtarg->nmoves);
366 maketasks_arg->moves, maketasks_arg->nmoves);
367 370
368 appret = appendsolution(&moves, solve_arg->solution_settings, 371 appret = appendsolution(&moves, mtarg->nmoves, mtarg->tmask,
369 solve_arg->solution_list); 372 solve_arg->solution_settings, solve_arg->solution_list);
370 return appret < 0 ? appret : NISSY_OK; 373 return appret < 0 ? appret : NISSY_OK;
371 } 374 }
372 375
373 if (maketasks_arg->nmoves == H48_STARTING_MOVES) { 376 if (mtarg->nmoves == H48_STARTING_MOVES) {
374 tasks[*ntasks].cube = maketasks_arg->cube; 377 tasks[*ntasks].cube = mtarg->cube;
375 memcpy(tasks[*ntasks].moves, 378 memcpy(tasks[*ntasks].moves, mtarg->moves,
376 maketasks_arg->moves, H48_STARTING_MOVES); 379 H48_STARTING_MOVES * sizeof(uint8_t));
380 memcpy(tasks[*ntasks].tmask, mtarg->tmask,
381 H48_STARTING_MOVES * sizeof(uint64_t));
377 (*ntasks)++; 382 (*ntasks)++;
378 return NISSY_OK; 383 return NISSY_OK;
379 } 384 }
380 385
381 if (maketasks_arg->nmoves == 0) { 386 if (mtarg->nmoves == 0) {
382 mm = MM18_ALLMOVES; 387 mm = MM18_ALLMOVES;
383 } else { 388 } else {
384 m = maketasks_arg->moves[maketasks_arg->nmoves-1]; 389 m = mtarg->moves[mtarg->nmoves-1];
385 mm = allowedmask[movebase(m)]; 390 mm = allowedmask[movebase(m)];
386 } 391 }
387 392
388 maketasks_arg->nmoves++; 393 mtarg->tmask[mtarg->nmoves] = symmetry_mask(mtarg->cube);
389 backup_cube = maketasks_arg->cube; 394
395 mtarg->nmoves++;
396 backup_cube = mtarg->cube;
390 for (m = 0; m < 18; m++) { 397 for (m = 0; m < 18; m++) {
391 if (!(mm & MM_SINGLE(m))) 398 if (!(mm & MM_SINGLE(m)))
392 continue; 399 continue;
393 maketasks_arg->moves[maketasks_arg->nmoves-1] = m; 400
394 maketasks_arg->cube = move(backup_cube, m); 401 mtarg->moves[mtarg->nmoves-1] = m;
395 r = solve_h48_maketasks( 402 mtarg->cube = move(backup_cube, m);
396 solve_arg, maketasks_arg, tasks, ntasks); 403 r = solve_h48_maketasks(solve_arg, mtarg, tasks, ntasks);
397 if (r < 0) 404 if (r < 0)
398 return r; 405 return r;
399 406
400 /* Avoid symmetry-equivalent moves from the starting cube */ 407 /* Avoid symmetry-equivalent moves from the starting cube */
401 if (maketasks_arg->nmoves == 1) 408 for (t = 0; t < NTRANS; t++)
402 for (t = 0; t < NTRANS; t++) 409 if (mtarg->tmask[mtarg->nmoves-1] & TM_SINGLE(t))
403 if (solve_arg->solution_settings->tmask & 410 mm &= ~MM_SINGLE(transform_move(m, t));
404 TM_SINGLE(t))
405 mm &= ~MM_SINGLE(transform_move(m, t));
406 } 411 }
407 maketasks_arg->nmoves--; 412 mtarg->nmoves--;
408 maketasks_arg->cube = backup_cube; 413 mtarg->cube = backup_cube;
409 414
410 return NISSY_OK; 415 return NISSY_OK;
411} 416}
@@ -441,7 +446,7 @@ solve_h48(
441 oriented_cube_t oc, 446 oriented_cube_t oc,
442 uint8_t minmoves, 447 uint8_t minmoves,
443 uint8_t maxmoves, 448 uint8_t maxmoves,
444 uint8_t maxsolutions, 449 uint64_t maxsolutions,
445 uint8_t optimal, 450 uint8_t optimal,
446 uint8_t threads, 451 uint8_t threads,
447 uint64_t data_size, 452 uint64_t data_size,
@@ -460,7 +465,7 @@ solve_h48(
460 int8_t d; 465 int8_t d;
461 dfsarg_solve_h48_t arg[THREADS]; 466 dfsarg_solve_h48_t arg[THREADS];
462 solve_h48_task_t tasks[H48_STARTING_CUBES]; 467 solve_h48_task_t tasks[H48_STARTING_CUBES];
463 dfsarg_solve_h48_maketasks_t maketasks_arg; 468 dfsarg_solve_h48_maketasks_t mtarg;
464 long double fallback_rate, lookups_per_node; 469 long double fallback_rate, lookups_per_node;
465 uint64_t offset; 470 uint64_t offset;
466 uint64_t nodes_visited, table_lookups, table_fallbacks; 471 uint64_t nodes_visited, table_lookups, table_fallbacks;
@@ -508,7 +513,6 @@ solve_h48(
508 fallback2 = h48data + offset; 513 fallback2 = h48data + offset;
509 514
510 settings = (solution_settings_t) { 515 settings = (solution_settings_t) {
511 .tmask = symmetry_mask(oc.cube),
512 .unniss = true, 516 .unniss = true,
513 .maxmoves = maxmoves, 517 .maxmoves = maxmoves,
514 .maxsolutions = maxsolutions, 518 .maxsolutions = maxsolutions,
@@ -543,14 +547,14 @@ solve_h48(
543 547
544 wrapthread_mutex_init(&solutions_mutex, NULL); 548 wrapthread_mutex_init(&solutions_mutex, NULL);
545 549
546 maketasks_arg = (dfsarg_solve_h48_maketasks_t) { 550 mtarg = (dfsarg_solve_h48_maketasks_t) {
547 .cube = oc.cube, 551 .cube = oc.cube,
548 .nmoves = 0, 552 .nmoves = 0,
549 .minmoves = minmoves, 553 .minmoves = minmoves,
550 .maxmoves = maxmoves, 554 .maxmoves = maxmoves,
551 }; 555 };
552 ntasks = 0; 556 ntasks = 0;
553 solve_h48_maketasks(&arg[0], &maketasks_arg, tasks, &ntasks); 557 solve_h48_maketasks(&arg[0], &mtarg, tasks, &ntasks);
554 if (ntasks < 0) 558 if (ntasks < 0)
555 goto solve_h48_error_solutions_buffer; 559 goto solve_h48_error_solutions_buffer;
556 if (solutions_done(&sollist, &settings, 560 if (solutions_done(&sollist, &settings,

Generated with cgit - Back to sebastiano.tronto.net