diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2025-12-28 19:57:48 +0100 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2025-12-28 19:57:48 +0100 |
| commit | d608fb076b1f321133607c85d7e338c3355b3e03 (patch) | |
| tree | edb4a1dcdfc72adcef1c080af18d23288a8ddaa8 /src/solvers | |
| parent | a8bd32086db1942e9c4b092d91bb1a2566adbb06 (diff) | |
| download | nissy-core-d608fb076b1f321133607c85d7e338c3355b3e03.tar.gz nissy-core-d608fb076b1f321133607c85d7e338c3355b3e03.zip | |
H48 prune pipeline
Diffstat (limited to 'src/solvers')
| -rw-r--r-- | src/solvers/h48/solve.h | 518 |
1 files changed, 170 insertions, 348 deletions
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h index 0162852..592edf3 100644 --- a/src/solvers/h48/solve.h +++ b/src/solvers/h48/solve.h | |||
| @@ -25,17 +25,15 @@ typedef struct { | |||
| 25 | solution_settings_t *solution_settings; | 25 | solution_settings_t *solution_settings; |
| 26 | const uint64_t *tmask; | 26 | const uint64_t *tmask; |
| 27 | solution_list_t *solution_list; | 27 | solution_list_t *solution_list; |
| 28 | int8_t lb_normal; | 28 | uint8_t lb_normal; |
| 29 | int8_t lb_inverse; | 29 | uint8_t lb_inverse; |
| 30 | bool use_lb_normal; /* TODO remove? */ | ||
| 31 | bool use_lb_inverse; /* TODO remove? */ | ||
| 32 | uint8_t h; | 30 | uint8_t h; |
| 33 | uint8_t base; | 31 | uint8_t base; |
| 34 | const uint32_t *cocsepdata; | 32 | const uint32_t *cocsepdata; |
| 35 | const unsigned char *h48data; | 33 | const unsigned char *h48data; |
| 36 | const unsigned char *h48data_fallback_eoesep; | 34 | const unsigned char *eoesepdata; |
| 37 | uint64_t movemask_normal; | 35 | uint64_t movemask_normal; // TODO change to uint32_t ? |
| 38 | uint64_t movemask_inverse; | 36 | uint64_t movemask_inverse; // TODO change to uint32_t ? |
| 39 | uint64_t nodes_visited; | 37 | uint64_t nodes_visited; |
| 40 | uint64_t table_fallbacks; | 38 | uint64_t table_fallbacks; |
| 41 | uint64_t table_lookups; | 39 | uint64_t table_lookups; |
| @@ -59,33 +57,25 @@ typedef struct { | |||
| 59 | } dfsarg_solve_h48_maketasks_t; | 57 | } dfsarg_solve_h48_maketasks_t; |
| 60 | 58 | ||
| 61 | typedef struct { | 59 | typedef struct { |
| 62 | uint8_t stop; | ||
| 63 | uint8_t pn; | ||
| 64 | uint8_t pi; | ||
| 65 | uint8_t lookups; | ||
| 66 | uint8_t fallbacks; | ||
| 67 | uint8_t nohalf_normal; | ||
| 68 | uint8_t nohalf_inverse; | ||
| 69 | } solve_h48_prune_return_t; | ||
| 70 | |||
| 71 | typedef struct { | ||
| 72 | cube_t cube; | 60 | cube_t cube; |
| 73 | cube_t inverse; | 61 | cube_t inverse; |
| 74 | const uint32_t *cocsepdata; | 62 | uint64_t coord; |
| 75 | const unsigned char *h48data; | 63 | uint8_t m; |
| 76 | const unsigned char *eoesepdata; | 64 | uint8_t pn; |
| 77 | uint8_t target; | 65 | uint8_t pi; |
| 78 | uint8_t h48base; | 66 | uint8_t stop; |
| 79 | uint8_t h48h; | 67 | } h48_prune_t; |
| 80 | uint8_t lb_inverse; | ||
| 81 | } solve_h48_prune_arg_t; | ||
| 82 | 68 | ||
| 83 | STATIC long long solve_h48_dispatch(oriented_cube_t, const char *, unsigned, | 69 | STATIC long long solve_h48_dispatch(oriented_cube_t, const char *, unsigned, |
| 84 | unsigned, unsigned, unsigned, unsigned, unsigned, unsigned long long, | 70 | unsigned, unsigned, unsigned, unsigned, unsigned, unsigned long long, |
| 85 | const unsigned char *, unsigned, char *, | 71 | const unsigned char *, unsigned, char *, |
| 86 | long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *); | 72 | long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *); |
| 87 | STATIC_INLINE bool solve_h48_stop(dfsarg_solve_h48_t [static 1]); | 73 | STATIC_INLINE void h48_prune_pipeline( |
| 88 | STATIC_INLINE solve_h48_prune_return_t solve_h48_prune(solve_h48_prune_arg_t); | 74 | dfsarg_solve_h48_t [static 1], h48_prune_t [static 18], uint8_t, bool); |
| 75 | STATIC_INLINE uint8_t h48_prune_lookup( | ||
| 76 | uint64_t, cube_t, dfsarg_solve_h48_t [static 1]); | ||
| 77 | STATIC_INLINE void h48_prune_restore(const h48_prune_t [static 1], | ||
| 78 | dfsarg_solve_h48_t [static 1], uint8_t, bool); | ||
| 89 | STATIC int64_t solve_h48_maketasks( | 79 | STATIC int64_t solve_h48_maketasks( |
| 90 | dfsarg_solve_h48_t [static 1], dfsarg_solve_h48_maketasks_t [static 1], | 80 | dfsarg_solve_h48_t [static 1], dfsarg_solve_h48_maketasks_t [static 1], |
| 91 | solve_h48_task_t [static H48_STARTING_CUBES], int [static 1]); | 81 | solve_h48_task_t [static H48_STARTING_CUBES], int [static 1]); |
| @@ -127,176 +117,165 @@ STATIC long long solve_h48_dispatch( | |||
| 127 | poll_status, poll_status_data); | 117 | poll_status, poll_status_data); |
| 128 | } | 118 | } |
| 129 | 119 | ||
| 130 | STATIC_INLINE bool | 120 | STATIC_INLINE uint8_t |
| 131 | solve_h48_stop(dfsarg_solve_h48_t arg[static 1]) | 121 | h48_prune_lookup( |
| 122 | uint64_t coord, | ||
| 123 | cube_t cube, | ||
| 124 | dfsarg_solve_h48_t arg[static 1] | ||
| 125 | ) | ||
| 132 | { | 126 | { |
| 133 | uint32_t data, data_inv; | 127 | uint8_t p, pmin, pe; |
| 134 | int64_t coord; | ||
| 135 | int8_t target, nh, n; | ||
| 136 | uint8_t pval, pval_min, pval_eoesep; | ||
| 137 | |||
| 138 | arg->movemask_normal = arg->movemask_inverse = MM18_ALLMOVES; | ||
| 139 | |||
| 140 | n = arg->solution_moves->nmoves + arg->solution_moves->npremoves; | ||
| 141 | target = arg->target_depth - n; | ||
| 142 | |||
| 143 | /* We'll never get a bound higher than base + 3 */ | ||
| 144 | if (arg->base + 3 <= target) | ||
| 145 | return false; | ||
| 146 | |||
| 147 | /* Preliminary probing using last computed bound, if possible */ | ||
| 148 | if ((arg->use_lb_normal && arg->lb_normal > target) || | ||
| 149 | (arg->use_lb_inverse && arg->lb_inverse > target)) | ||
| 150 | return true; | ||
| 151 | |||
| 152 | /* Get cdata and do preliminary corner probing */ | ||
| 153 | if (get_h48_cdata(arg->cube, arg->cocsepdata, &data) > target || | ||
| 154 | get_h48_cdata(arg->inverse, arg->cocsepdata, &data_inv) > target) | ||
| 155 | return true; | ||
| 156 | 128 | ||
| 157 | /* Inverse probing */ | 129 | p = get_h48_pval_and_min(arg->h48data, coord, &pmin); |
| 158 | 130 | if (p == 0) { | |
| 159 | if (!arg->use_lb_inverse) { | 131 | arg->table_fallbacks++; |
| 160 | arg->table_lookups++; | 132 | pe = get_eoesep_pval_cube(arg->eoesepdata, cube); |
| 161 | arg->use_lb_inverse = true; | 133 | return MAX(pmin, pe); |
| 162 | coord = coord_h48_edges( | 134 | } else { |
| 163 | arg->inverse, COCLASS(data_inv), TTREP(data_inv), arg->h); | 135 | return p + arg->base; |
| 164 | pval = get_h48_pval_and_min(arg->h48data, coord, &pval_min); | 136 | } |
| 137 | } | ||
| 165 | 138 | ||
| 166 | if (pval == 0) { | 139 | STATIC_INLINE void |
| 167 | arg->table_fallbacks++; | 140 | h48_prune_pipeline( |
| 141 | dfsarg_solve_h48_t arg[static 1], | ||
| 142 | h48_prune_t prune[static 18], | ||
| 143 | uint8_t target, | ||
| 144 | bool normal | ||
| 145 | ) | ||
| 146 | { | ||
| 147 | uint32_t cdata; | ||
| 148 | uint8_t m, p; | ||
| 168 | 149 | ||
| 169 | pval_eoesep = get_eoesep_pval_cube( | 150 | /* Stage 0: initialize the neighbors array */ |
| 170 | arg->h48data_fallback_eoesep, arg->inverse); | 151 | memset(prune, 0, 18 * sizeof(h48_prune_t)); |
| 171 | pval = MAX(pval_min, pval_eoesep); | 152 | if (normal) { |
| 172 | } else { | 153 | for (m = 0; m < 18; m++) { |
| 173 | pval += arg->base; | 154 | prune[m].pi = m % 3 == 1 ? arg->lb_inverse : 0; |
| 155 | if (!(arg->movemask_normal & MM_SINGLE(m)) || | ||
| 156 | prune[m].pi > target) { | ||
| 157 | prune[m].stop = 1; | ||
| 158 | continue; | ||
| 159 | } | ||
| 160 | prune[m].cube = move(arg->cube, m); | ||
| 161 | prune[m].inverse = premove(arg->inverse, m); | ||
| 162 | prune[m].m = m; | ||
| 163 | arg->nodes_visited++; | ||
| 164 | } | ||
| 165 | } else { | ||
| 166 | for (m = 0; m < 18; m++) { | ||
| 167 | prune[m].pi = m % 3 == 1 ? arg->lb_normal : 0; | ||
| 168 | if (!(arg->movemask_inverse & MM_SINGLE(m)) || | ||
| 169 | prune[m].pi > target) { | ||
| 170 | prune[m].stop = 1; | ||
| 171 | continue; | ||
| 172 | } | ||
| 173 | prune[m].cube = move(arg->inverse, m); | ||
| 174 | prune[m].inverse = premove(arg->cube, m); | ||
| 175 | prune[m].m = m; | ||
| 176 | arg->nodes_visited++; | ||
| 174 | } | 177 | } |
| 175 | |||
| 176 | arg->lb_inverse = pval; | ||
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | if (arg->lb_inverse > target) | 180 | /* Stage 1: cdata and prefetch inverse */ |
| 180 | return true; | 181 | for (m = 0; m < 18; m++) { |
| 181 | nh = arg->lb_inverse == target; | 182 | if (prune[m].stop) |
| 182 | arg->movemask_normal = nh * MM18_NOHALFTURNS + (1-nh) * MM18_ALLMOVES; | 183 | continue; |
| 183 | |||
| 184 | /* Normal probing */ | ||
| 185 | |||
| 186 | if (!arg->use_lb_normal) { | ||
| 187 | arg->table_lookups++; | ||
| 188 | arg->use_lb_normal = true; | ||
| 189 | coord = coord_h48_edges( | ||
| 190 | arg->cube, COCLASS(data), TTREP(data), arg->h); | ||
| 191 | pval = get_h48_pval_and_min(arg->h48data, coord, &pval_min); | ||
| 192 | |||
| 193 | if (pval == 0) { | ||
| 194 | arg->table_fallbacks++; | ||
| 195 | 184 | ||
| 196 | pval_eoesep = get_eoesep_pval_cube( | 185 | p = get_h48_cdata(prune[m].inverse, arg->cocsepdata, &cdata); |
| 197 | arg->h48data_fallback_eoesep, arg->cube); | 186 | if (p > target) { |
| 198 | pval = MAX(pval_min, pval_eoesep); | 187 | prune[m].stop = 1; |
| 199 | } else { | 188 | continue; |
| 200 | pval += arg->base; | 189 | } |
| 190 | if (prune[m].pi == 0) { | ||
| 191 | prune[m].coord = coord_h48_edges(prune[m].inverse, | ||
| 192 | COCLASS(cdata), TTREP(cdata), arg->h); | ||
| 193 | // TODO prefetch | ||
| 201 | } | 194 | } |
| 202 | |||
| 203 | arg->lb_normal = pval; | ||
| 204 | } | 195 | } |
| 205 | 196 | ||
| 206 | if (arg->lb_normal > target) | 197 | /* Stage 2: get pval from inverse, prefetch normal */ |
| 207 | return true; | 198 | for (m = 0; m < 18; m++) { |
| 208 | nh = arg->lb_normal == target; | 199 | if (prune[m].stop) |
| 209 | arg->movemask_inverse = nh * MM18_NOHALFTURNS + (1-nh) * MM18_ALLMOVES; | 200 | continue; |
| 210 | |||
| 211 | return false; | ||
| 212 | } | ||
| 213 | |||
| 214 | STATIC_INLINE solve_h48_prune_return_t | ||
| 215 | solve_h48_prune(solve_h48_prune_arg_t arg) | ||
| 216 | { | ||
| 217 | solve_h48_prune_return_t ret = {0}; | ||
| 218 | uint64_t c; | ||
| 219 | uint32_t dn, di; | ||
| 220 | uint8_t pmin, pcn, pci, pe; | ||
| 221 | |||
| 222 | /* We'll never get a bound higher than base + 3 */ | ||
| 223 | if (arg.h48base + 3 <= arg.target) | ||
| 224 | goto solve_h48_prune_return_false; | ||
| 225 | 201 | ||
| 226 | /* Use prevously computed bound */ | 202 | if (prune[m].pi == 0) { |
| 227 | ret.pi = arg.lb_inverse; | 203 | arg->table_lookups++; |
| 228 | if (ret.pi > arg.target) | 204 | prune[m].pi = h48_prune_lookup( |
| 229 | goto solve_h48_prune_return_true; | 205 | prune[m].coord, prune[m].inverse, arg); |
| 206 | if (prune[m].pi > target) { | ||
| 207 | prune[m].stop = 1; | ||
| 208 | continue; | ||
| 209 | } | ||
| 210 | } | ||
| 230 | 211 | ||
| 231 | /* Get corner data and do preliminary corner probing */ | 212 | p = get_h48_cdata(prune[m].cube, arg->cocsepdata, &cdata); |
| 232 | pci = get_h48_cdata(arg.inverse, arg.cocsepdata, &di); | 213 | if (p > target) { |
| 233 | if (pci > arg.target) { | 214 | prune[m].stop = 1; |
| 234 | ret.pi = pci; | 215 | continue; |
| 235 | goto solve_h48_prune_return_true; | 216 | } |
| 217 | prune[m].coord = coord_h48_edges( | ||
| 218 | prune[m].cube, COCLASS(cdata), TTREP(cdata), arg->h); | ||
| 219 | // TODO prefetch | ||
| 236 | } | 220 | } |
| 237 | pcn = get_h48_cdata(arg.cube, arg.cocsepdata, &dn); | ||
| 238 | if (pcn > arg.target) | ||
| 239 | goto solve_h48_prune_return_true; | ||
| 240 | 221 | ||
| 241 | /* Inverse probing is done only if previous value can't be used */ | 222 | /* Stage 3: get pval from normal */ |
| 242 | if (arg.lb_inverse == 0) { | 223 | for (m = 0; m < 18; m++) { |
| 243 | ret.lookups++; | 224 | if (prune[m].stop) |
| 244 | c = coord_h48_edges( | 225 | continue; |
| 245 | arg.inverse, COCLASS(di), TTREP(di), arg.h48h); | ||
| 246 | ret.pi = get_h48_pval_and_min(arg.h48data, c, &pmin); | ||
| 247 | 226 | ||
| 248 | if (ret.pi == 0) { | 227 | arg->table_lookups++; |
| 249 | ret.fallbacks++; | 228 | prune[m].pn = h48_prune_lookup( |
| 250 | pe = get_eoesep_pval_cube(arg.eoesepdata, arg.inverse); | 229 | prune[m].coord, prune[m].cube, arg); |
| 251 | ret.pi = MAX(pmin, MAX(pci, pe)); | 230 | prune[m].stop = prune[m].pn > target; |
| 252 | } else { | ||
| 253 | ret.pi += arg.h48base; | ||
| 254 | } | ||
| 255 | } | 231 | } |
| 232 | } | ||
| 256 | 233 | ||
| 257 | if (ret.pi > arg.target) | 234 | STATIC_INLINE void |
| 258 | goto solve_h48_prune_return_true; | 235 | h48_prune_restore( |
| 259 | 236 | const h48_prune_t prune[static 1], | |
| 260 | ret.nohalf_normal = ret.pi == arg.target; | 237 | dfsarg_solve_h48_t arg[static 1], |
| 238 | uint8_t target, | ||
| 239 | bool normal | ||
| 240 | ) | ||
| 241 | { | ||
| 242 | uint8_t nm; | ||
| 261 | 243 | ||
| 262 | /* Normal probing */ | 244 | if (normal) { |
| 263 | ret.lookups++; | 245 | arg->cube = prune->cube; |
| 264 | c = coord_h48_edges(arg.cube, COCLASS(dn), TTREP(dn), arg.h48h); | 246 | arg->inverse = prune->inverse; |
| 265 | ret.pn = get_h48_pval_and_min(arg.h48data, c, &pmin); | 247 | arg->lb_inverse = prune->pi; |
| 248 | arg->lb_normal = prune->pn; | ||
| 266 | 249 | ||
| 267 | if (ret.pn == 0) { | 250 | nm = arg->solution_moves->nmoves; |
| 268 | ret.fallbacks++; | 251 | arg->solution_moves->moves[nm-1] = prune->m; |
| 269 | pe = get_eoesep_pval_cube(arg.eoesepdata, arg.cube); | 252 | arg->movemask_normal = allowedmask[movebase(prune->m)]; |
| 270 | ret.pn = MAX(pmin, MAX(pcn, pe)); | ||
| 271 | } else { | 253 | } else { |
| 272 | ret.pn += arg.h48base; | 254 | arg->cube = prune->inverse; |
| 273 | } | 255 | arg->inverse = prune->cube; |
| 274 | 256 | arg->lb_inverse = prune->pn; | |
| 275 | if (ret.pn > arg.target) | 257 | arg->lb_normal = prune->pi; |
| 276 | goto solve_h48_prune_return_true; | ||
| 277 | 258 | ||
| 278 | ret.nohalf_inverse = ret.pn == arg.target; | 259 | nm = arg->solution_moves->npremoves; |
| 279 | 260 | arg->solution_moves->premoves[nm-1] = prune->m; | |
| 280 | solve_h48_prune_return_false: | 261 | arg->movemask_inverse = allowedmask[movebase(prune->m)]; |
| 281 | ret.stop = false; | 262 | } |
| 282 | return ret; | ||
| 283 | 263 | ||
| 284 | solve_h48_prune_return_true: | 264 | if (arg->lb_inverse == target) |
| 285 | ret.stop = true; | 265 | arg->movemask_normal &= MM18_NOHALFTURNS; |
| 286 | return ret; | 266 | if (arg->lb_normal == target) |
| 267 | arg->movemask_inverse &= MM18_NOHALFTURNS; | ||
| 287 | } | 268 | } |
| 288 | 269 | ||
| 289 | #if 1 | ||
| 290 | |||
| 291 | STATIC int64_t | 270 | STATIC int64_t |
| 292 | solve_h48_dfs(dfsarg_solve_h48_t arg[static 1]) | 271 | solve_h48_dfs(dfsarg_solve_h48_t arg[static 1]) |
| 293 | { | 272 | { |
| 294 | int64_t ret, n; | 273 | int64_t ret, n; |
| 295 | uint8_t m, nm, nn, ni, lbn, lbi; | 274 | uint8_t m, nm, nn, ni, target; |
| 296 | uint64_t mm_normal, mm_inverse; | 275 | uint64_t mm_normal, mm_inverse; |
| 276 | bool normal; | ||
| 297 | cube_t backup_cube, backup_inverse; | 277 | cube_t backup_cube, backup_inverse; |
| 298 | solve_h48_prune_arg_t prune_arg; | 278 | h48_prune_t prune[18]; |
| 299 | solve_h48_prune_return_t prune; | ||
| 300 | 279 | ||
| 301 | nn = arg->solution_moves->nmoves; | 280 | nn = arg->solution_moves->nmoves; |
| 302 | ni = arg->solution_moves->npremoves; | 281 | ni = arg->solution_moves->npremoves; |
| @@ -315,208 +294,52 @@ solve_h48_dfs(dfsarg_solve_h48_t arg[static 1]) | |||
| 315 | arg->solution_list->nsols >= arg->solution_settings->maxsolutions) | 294 | arg->solution_list->nsols >= arg->solution_settings->maxsolutions) |
| 316 | return 0; | 295 | return 0; |
| 317 | 296 | ||
| 297 | ret = 0; | ||
| 298 | target = arg->target_depth - (nm + 1); | ||
| 318 | backup_cube = arg->cube; | 299 | backup_cube = arg->cube; |
| 319 | backup_inverse = arg->inverse; | 300 | backup_inverse = arg->inverse; |
| 320 | lbn = arg->lb_normal; | ||
| 321 | lbi = arg->lb_inverse; | ||
| 322 | mm_normal = arg->movemask_normal; | 301 | mm_normal = arg->movemask_normal; |
| 323 | mm_inverse = arg->movemask_inverse; | 302 | mm_inverse = arg->movemask_inverse; |
| 303 | normal = popcount_u32(mm_normal) <= popcount_u32(mm_inverse); | ||
| 324 | 304 | ||
| 325 | ret = 0; | 305 | h48_prune_pipeline(arg, prune, target, normal); |
| 326 | 306 | ||
| 327 | prune_arg = (solve_h48_prune_arg_t){ | 307 | if (normal) |
| 328 | .cocsepdata = arg->cocsepdata, | ||
| 329 | .h48data = arg->h48data, | ||
| 330 | .eoesepdata = arg->h48data_fallback_eoesep, | ||
| 331 | .target = arg->target_depth - (nm + 1), | ||
| 332 | .h48base = arg->base, | ||
| 333 | .h48h = arg->h, | ||
| 334 | .lb_inverse = 0, | ||
| 335 | }; | ||
| 336 | if (popcount_u32(mm_normal) <= popcount_u32(mm_inverse)) { | ||
| 337 | arg->solution_moves->nmoves++; | 308 | arg->solution_moves->nmoves++; |
| 338 | for (m = 0; m < 18; m++) { | 309 | else |
| 339 | if (!(mm_normal & MM_SINGLE(m))) | ||
| 340 | continue; | ||
| 341 | |||
| 342 | prune_arg.cube = move(backup_cube, m); | ||
| 343 | prune_arg.inverse = premove(backup_inverse, m); | ||
| 344 | prune_arg.lb_inverse = m % 3 == 1 ? lbi : 0; | ||
| 345 | |||
| 346 | prune = solve_h48_prune(prune_arg); | ||
| 347 | |||
| 348 | arg->nodes_visited++; | ||
| 349 | arg->table_lookups += prune.lookups; | ||
| 350 | arg->table_fallbacks += prune.fallbacks; | ||
| 351 | |||
| 352 | if (prune.stop) | ||
| 353 | continue; | ||
| 354 | |||
| 355 | arg->solution_moves->moves[nn] = m; | ||
| 356 | arg->cube = prune_arg.cube; | ||
| 357 | arg->inverse = prune_arg.inverse; | ||
| 358 | arg->lb_inverse = prune.pi; | ||
| 359 | arg->lb_normal = prune.pn; | ||
| 360 | arg->movemask_normal = allowedmask[movebase(m)]; | ||
| 361 | if (prune.nohalf_normal) | ||
| 362 | arg->movemask_normal &= MM18_NOHALFTURNS; | ||
| 363 | arg->movemask_inverse = mm_inverse; | ||
| 364 | if (prune.nohalf_inverse) | ||
| 365 | arg->movemask_inverse &= MM18_NOHALFTURNS; | ||
| 366 | |||
| 367 | n = solve_h48_dfs(arg); | ||
| 368 | |||
| 369 | if (n < 0) | ||
| 370 | return n; | ||
| 371 | ret += n; | ||
| 372 | } | ||
| 373 | arg->solution_moves->nmoves--; | ||
| 374 | } else { | ||
| 375 | arg->solution_moves->npremoves++; | 310 | arg->solution_moves->npremoves++; |
| 376 | for (m = 0; m < 18; m++) { | ||
| 377 | if(!(mm_inverse & MM_SINGLE(m))) | ||
| 378 | continue; | ||
| 379 | |||
| 380 | prune_arg.cube = move(backup_inverse, m); | ||
| 381 | prune_arg.inverse = premove(backup_cube, m); | ||
| 382 | prune_arg.lb_inverse = m % 3 == 1 ? lbn : 0; | ||
| 383 | prune = solve_h48_prune(prune_arg); | ||
| 384 | |||
| 385 | arg->nodes_visited++; | ||
| 386 | arg->table_lookups += prune.lookups; | ||
| 387 | arg->table_fallbacks += prune.fallbacks; | ||
| 388 | |||
| 389 | if (prune.stop) | ||
| 390 | continue; | ||
| 391 | 311 | ||
| 392 | arg->solution_moves->premoves[ni] = m; | 312 | for (m = 0; m < 18; m++) { |
| 393 | arg->inverse = prune_arg.cube; | 313 | if (prune[m].stop) |
| 394 | arg->cube = prune_arg.inverse; | 314 | continue; |
| 395 | arg->lb_normal = prune.pi; | 315 | arg->movemask_normal = mm_normal; |
| 396 | arg->lb_inverse = prune.pn; | 316 | arg->movemask_inverse = mm_inverse; |
| 397 | arg->movemask_normal = mm_normal; | 317 | h48_prune_restore(&prune[m], arg, target, normal); |
| 398 | if (prune.nohalf_inverse) | 318 | n = solve_h48_dfs(arg); |
| 399 | arg->movemask_normal &= MM18_NOHALFTURNS; | 319 | if (n < 0) |
| 400 | arg->movemask_inverse = allowedmask[movebase(m)]; | 320 | return n; |
| 401 | if (prune.nohalf_normal) | 321 | ret += n; |
| 402 | arg->movemask_inverse &= MM18_NOHALFTURNS; | ||
| 403 | |||
| 404 | n = solve_h48_dfs(arg); | ||
| 405 | |||
| 406 | if (n < 0) | ||
| 407 | return n; | ||
| 408 | ret += n; | ||
| 409 | } | ||
| 410 | arg->solution_moves->npremoves--; | ||
| 411 | } | ||
| 412 | |||
| 413 | arg->cube = backup_cube; | ||
| 414 | arg->inverse = backup_inverse; | ||
| 415 | |||
| 416 | return ret; | ||
| 417 | } | ||
| 418 | |||
| 419 | #else | ||
| 420 | |||
| 421 | STATIC int64_t | ||
| 422 | solve_h48_dfs(dfsarg_solve_h48_t arg[static 1]) | ||
| 423 | { | ||
| 424 | int64_t ret, n; | ||
| 425 | uint8_t m, nm, lbn, lbi; | ||
| 426 | uint64_t mm_normal, mm_inverse; | ||
| 427 | bool ulbi, ulbn; | ||
| 428 | cube_t backup_cube, backup_inverse; | ||
| 429 | |||
| 430 | arg->nodes_visited++; | ||
| 431 | |||
| 432 | nm = arg->solution_moves->nmoves + arg->solution_moves->npremoves; | ||
| 433 | if (equal(arg->cube, SOLVED_CUBE)) { | ||
| 434 | if (arg->target_depth != nm) | ||
| 435 | return 0; | ||
| 436 | wrapthread_mutex_lock(arg->solutions_mutex); | ||
| 437 | ret = appendsolution(arg->solution_moves, H48_STARTING_MOVES, | ||
| 438 | arg->tmask, arg->solution_settings, arg->solution_list); | ||
| 439 | wrapthread_mutex_unlock(arg->solutions_mutex); | ||
| 440 | return ret; | ||
| 441 | } | 322 | } |
| 442 | 323 | ||
| 443 | if (solve_h48_stop(arg)) | 324 | if (normal) |
| 444 | return 0; | ||
| 445 | |||
| 446 | if (nm + 1 > arg->target_depth || | ||
| 447 | arg->solution_list->nsols >= arg->solution_settings->maxsolutions) | ||
| 448 | return 0; | ||
| 449 | |||
| 450 | backup_cube = arg->cube; | ||
| 451 | backup_inverse = arg->inverse; | ||
| 452 | lbn = arg->lb_normal; | ||
| 453 | lbi = arg->lb_inverse; | ||
| 454 | ulbn = arg->use_lb_normal; | ||
| 455 | ulbi = arg->use_lb_inverse; | ||
| 456 | |||
| 457 | ret = 0; | ||
| 458 | mm_normal = arg->movemask_normal; | ||
| 459 | if (arg->solution_moves->nmoves > 0) { | ||
| 460 | m = arg->solution_moves->moves[arg->solution_moves->nmoves-1]; | ||
| 461 | mm_normal &= allowedmask[movebase(m)]; | ||
| 462 | } | ||
| 463 | mm_inverse = arg->movemask_inverse; | ||
| 464 | if (arg->solution_moves->npremoves > 0) { | ||
| 465 | m = arg->solution_moves->premoves[arg->solution_moves->npremoves-1]; | ||
| 466 | mm_inverse &= allowedmask[movebase(m)]; | ||
| 467 | } | ||
| 468 | if (popcount_u32(mm_normal) <= popcount_u32(mm_inverse)) { | ||
| 469 | arg->solution_moves->nmoves++; | ||
| 470 | for (m = 0; m < 18; m++) { | ||
| 471 | if (!(mm_normal & MM_SINGLE(m))) | ||
| 472 | continue; | ||
| 473 | arg->solution_moves->moves[ | ||
| 474 | arg->solution_moves->nmoves-1] = m; | ||
| 475 | arg->cube = move(backup_cube, m); | ||
| 476 | arg->inverse = premove(backup_inverse, m); | ||
| 477 | arg->lb_inverse = lbi; | ||
| 478 | arg->use_lb_normal = false; | ||
| 479 | arg->use_lb_inverse = ulbi && m % 3 == 1; | ||
| 480 | n = solve_h48_dfs(arg); | ||
| 481 | if (n < 0) | ||
| 482 | return n; | ||
| 483 | ret += n; | ||
| 484 | } | ||
| 485 | arg->solution_moves->nmoves--; | 325 | arg->solution_moves->nmoves--; |
| 486 | } else { | 326 | else |
| 487 | arg->solution_moves->npremoves++; | ||
| 488 | for (m = 0; m < 18; m++) { | ||
| 489 | if(!(mm_inverse & MM_SINGLE(m))) | ||
| 490 | continue; | ||
| 491 | arg->solution_moves->premoves[ | ||
| 492 | arg->solution_moves->npremoves-1] = m; | ||
| 493 | arg->inverse = move(backup_inverse, m); | ||
| 494 | arg->cube = premove(backup_cube, m); | ||
| 495 | arg->lb_normal = lbn; | ||
| 496 | arg->use_lb_inverse = false; | ||
| 497 | arg->use_lb_normal = ulbn && m % 3 == 1; | ||
| 498 | n = solve_h48_dfs(arg); | ||
| 499 | if (n < 0) | ||
| 500 | return n; | ||
| 501 | ret += n; | ||
| 502 | } | ||
| 503 | arg->solution_moves->npremoves--; | 327 | arg->solution_moves->npremoves--; |
| 504 | } | ||
| 505 | 328 | ||
| 506 | arg->cube = backup_cube; | 329 | arg->cube = backup_cube; |
| 507 | arg->inverse = backup_inverse; | 330 | arg->inverse = backup_inverse; |
| 331 | arg->movemask_normal = mm_normal; | ||
| 332 | arg->movemask_inverse = mm_inverse; | ||
| 508 | 333 | ||
| 509 | return ret; | 334 | return ret; |
| 510 | } | 335 | } |
| 511 | 336 | ||
| 512 | #endif | ||
| 513 | |||
| 514 | STATIC void * | 337 | STATIC void * |
| 515 | solve_h48_runthread(void *arg) | 338 | solve_h48_runthread(void *arg) |
| 516 | { | 339 | { |
| 517 | int i, j; | 340 | int i, j; |
| 518 | uint8_t lastmove; | 341 | uint8_t lastmove; |
| 519 | int64_t nprev; | 342 | int64_t d, f, nprev; |
| 520 | dfsarg_solve_h48_t *dfsarg; | 343 | dfsarg_solve_h48_t *dfsarg; |
| 521 | 344 | ||
| 522 | dfsarg = (dfsarg_solve_h48_t *)arg; | 345 | dfsarg = (dfsarg_solve_h48_t *)arg; |
| @@ -541,8 +364,6 @@ solve_h48_runthread(void *arg) | |||
| 541 | 364 | ||
| 542 | dfsarg->lb_normal = 0; | 365 | dfsarg->lb_normal = 0; |
| 543 | dfsarg->lb_inverse = 0; | 366 | dfsarg->lb_inverse = 0; |
| 544 | dfsarg->use_lb_normal = false; | ||
| 545 | dfsarg->use_lb_inverse = false; | ||
| 546 | dfsarg->movemask_normal = allowedmask[ | 367 | dfsarg->movemask_normal = allowedmask[ |
| 547 | movebase(dfsarg->tasks[i].moves[H48_STARTING_MOVES-1])]; | 368 | movebase(dfsarg->tasks[i].moves[H48_STARTING_MOVES-1])]; |
| 548 | dfsarg->movemask_inverse = MM18_ALLMOVES; | 369 | dfsarg->movemask_inverse = MM18_ALLMOVES; |
| @@ -562,8 +383,9 @@ solve_h48_runthread(void *arg) | |||
| 562 | inspired by Andrew Skalski's vcube. | 383 | inspired by Andrew Skalski's vcube. |
| 563 | */ | 384 | */ |
| 564 | lastmove = dfsarg->tasks[i].moves[H48_STARTING_MOVES-1]; | 385 | lastmove = dfsarg->tasks[i].moves[H48_STARTING_MOVES-1]; |
| 565 | dfsarg->tasks[i].rank = (dfsarg->nodes_visited - nprev) * | 386 | d = (int64_t)dfsarg->nodes_visited - nprev; |
| 566 | (movebase(lastmove) % 2 == 0 ? 47525 : 58206); | 387 | f = movebase(lastmove) % 2 == 0 ? 47525 : 58206; |
| 388 | dfsarg->tasks[i].rank = d * f; | ||
| 567 | nprev = dfsarg->nodes_visited; | 389 | nprev = dfsarg->nodes_visited; |
| 568 | } | 390 | } |
| 569 | 391 | ||
| @@ -745,7 +567,7 @@ solve_h48( | |||
| 745 | .base = info.base, | 567 | .base = info.base, |
| 746 | .cocsepdata = cocsepdata, | 568 | .cocsepdata = cocsepdata, |
| 747 | .h48data = h48data, | 569 | .h48data = h48data, |
| 748 | .h48data_fallback_eoesep = eoesep, | 570 | .eoesepdata = eoesep, |
| 749 | .solution_moves = &solution_moves[i], | 571 | .solution_moves = &solution_moves[i], |
| 750 | .solution_settings = &settings, | 572 | .solution_settings = &settings, |
| 751 | .solution_list = &sollist, | 573 | .solution_list = &sollist, |
