diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2025-11-23 16:16:31 +0100 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2025-11-24 16:32:11 +0100 |
| commit | 147b0c3c4615c32478a4923242909b8ae5a30d03 (patch) | |
| tree | 5294d9b3655031535085a5163c2c5b5cbe7413b1 /src/solvers/h48 | |
| parent | 78ec0d22d927bc4287aa090469d5ba5f84e8780b (diff) | |
| download | nissy-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')
| -rw-r--r-- | src/solvers/h48/solve.h | 78 |
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 | ||
| 18 | typedef struct { | 19 | typedef 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 | ||
| 60 | STATIC long long solve_h48_dispatch(oriented_cube_t, const char *, unsigned, | 63 | STATIC long long solve_h48_dispatch(oriented_cube_t, const char *, unsigned, |
| @@ -69,7 +72,7 @@ STATIC void *solve_h48_runthread(void *); | |||
| 69 | STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]); | 72 | STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]); |
| 70 | STATIC void solve_h48_log_solutions(solution_list_t [static 1], size_t); | 73 | STATIC void solve_h48_log_solutions(solution_list_t [static 1], size_t); |
| 71 | STATIC int solve_h48_compare_tasks(const void *, const void *); | 74 | STATIC int solve_h48_compare_tasks(const void *, const void *); |
| 72 | STATIC int64_t solve_h48(oriented_cube_t, uint8_t, uint8_t, uint8_t, uint8_t, | 75 | STATIC 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: | |||
| 341 | STATIC int64_t | 345 | STATIC int64_t |
| 342 | solve_h48_maketasks( | 346 | solve_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, |
