aboutsummaryrefslogtreecommitdiff
path: root/src/solve_h48.h
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-08-18 14:26:45 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2024-08-18 14:26:45 +0200
commit18c9a8b8905304cf5f8fc15825769046a3144866 (patch)
treea7807bb32b0a5d9ded7d3cedccc598f64a9b00fe /src/solve_h48.h
parentf25a10e19eca294c4e6a99e4f80ce5cfd11a0e5f (diff)
downloadnissy-core-18c9a8b8905304cf5f8fc15825769046a3144866.tar.gz
nissy-core-18c9a8b8905304cf5f8fc15825769046a3144866.zip
Reorganized folder structure
Diffstat (limited to 'src/solve_h48.h')
-rw-r--r--src/solve_h48.h839
1 files changed, 0 insertions, 839 deletions
diff --git a/src/solve_h48.h b/src/solve_h48.h
deleted file mode 100644
index 1701268..0000000
--- a/src/solve_h48.h
+++ /dev/null
@@ -1,839 +0,0 @@
1#define MAP_UNSET UINT64_C(0xFFFFFFFFFFFFFFFF)
2#define MAP_KEYMASK UINT64_C(0xFFFFFFFFFF)
3#define MAP_KEYSHIFT UINT64_C(40)
4
5#define COCSEP_CLASSES ((size_t)3393)
6#define COCSEP_TABLESIZE ((size_t)_3p7 << (size_t)7)
7#define COCSEP_VISITEDSIZE ((COCSEP_TABLESIZE + (size_t)7) / (size_t)8)
8#define COCSEP_FULLSIZE ((size_t)4 * (COCSEP_TABLESIZE + (size_t)12))
9
10#define ESEP_NOEO (COCSEP_CLASSES * (size_t)_12c4 * (size_t)_8c4)
11#define ESEP_MAX(h) (ESEP_NOEO << (size_t)(h))
12#define ESEP_TABLESIZE(h, k) (ESEP_MAX((h)) / ((size_t)8 / (size_t)(k)))
13
14#define COCLASS_MASK (UINT32_C(0xFFFF) << UINT32_C(16))
15#define COCLASS(x) (((x) & COCLASS_MASK) >> UINT32_C(16))
16#define TTREP_MASK (UINT32_C(0xFF) << UINT32_C(8))
17#define TTREP(x) (((x) & TTREP_MASK) >> UINT32_C(8))
18#define CBOUND_MASK UINT32_C(0xFF)
19#define CBOUND(x) ((x) & CBOUND_MASK)
20#define H48_ESIZE(h) ((_12c4 * _8c4) << (int64_t)(h))
21
22#define ESEP_IND(i) ((uint32_t)(i) / UINT32_C(8))
23#define ESEP_SHIFT(i) (UINT32_C(4) * ((uint32_t)(i) % UINT32_C(8)))
24#define ESEP_MASK(i) ((_bit_u32(4) - (uint32_t)(1)) << ESEP_SHIFT(i))
25#define VISITED_IND(i) ((uint32_t)(i) / UINT32_C(8))
26#define VISITED_MASK(i) (UINT32_C(1) << ((uint32_t)(i) % UINT32_C(8)))
27
28#define MAX_SOLUTION_LENGTH 20
29
30/*
31TODO: This loop other similar h48 coordinates can be improved by only
32transforming edges, but we need to compose transformations (i.e. conjugate
33_t by _ttrep).
34*/
35#define _foreach_h48sim(_cube, _cocsepdata, _selfsim, _h, _action) \
36 int64_t _cocsep = coord_cocsep(_cube); \
37 uint8_t _ttrep = TTREP(_cocsepdata[_cocsep]); \
38 uint8_t _inverse_ttrep = inverse_trans(_ttrep); \
39 int64_t _coclass = COCLASS(_cocsepdata[_cocsep]); \
40 cube_t _rep = transform(_cube, _ttrep); \
41 uint64_t _sim = _selfsim[_coclass]; \
42 for (uint8_t _t = 0; _t < 48 && _sim; _t++, _sim >>= 1) { \
43 if (!(_sim & 1)) continue; \
44 _cube = transform(_rep, _t); \
45 _cube = transform(_cube, _inverse_ttrep); \
46 _action \
47 }
48
49typedef struct {
50 uint64_t n;
51 uint64_t capacity;
52 uint64_t randomizer;
53 uint64_t *table;
54} h48map_t;
55
56typedef struct {
57 uint64_t key;
58 uint64_t val;
59} kvpair_t;
60
61typedef struct {
62 cube_t cube;
63 uint8_t depth;
64 uint8_t maxdepth;
65 uint16_t *n;
66 uint32_t *buf32;
67 uint8_t *visited;
68 uint64_t *selfsim;
69 cube_t *rep;
70} dfsarg_cocsep_t;
71
72/* TODO keep or not? */
73typedef struct {
74 cube_t cube;
75 int8_t nmoves;
76 int8_t depth;
77 uint8_t moves[MAX_SOLUTION_LENGTH];
78 uint32_t *cocsepdata;
79 h48map_t *visited;
80} dfsarg_genh48set_t;
81
82typedef struct {
83 uint8_t depth;
84 uint32_t *cocsepdata;
85 uint32_t *buf32;
86 uint64_t *selfsim;
87 int64_t done;
88 cube_t *crep;
89} bfsarg_esep_t;
90
91typedef struct {
92 cube_t cube;
93 cube_t inverse;
94 int8_t nmoves;
95 int8_t depth;
96 uint8_t moves[MAX_SOLUTION_LENGTH];
97 int64_t *nsols;
98 int64_t maxsolutions;
99 uint8_t h;
100 uint32_t *cocsepdata;
101 uint32_t *h48data;
102 char **nextsol;
103} dfsarg_solveh48_t;
104
105typedef struct {
106 cube_t cube;
107 int8_t nmoves;
108 int8_t depth;
109 uint8_t moves[MAX_SOLUTION_LENGTH];
110 uint32_t *cocsepdata;
111 uint32_t *h48data;
112 char *s;
113} dfsarg_solveh48stats_t;
114
115_static void h48map_create(h48map_t *, uint64_t, uint64_t);
116_static void h48map_clear(h48map_t *);
117_static void h48map_destroy(h48map_t *);
118_static uint64_t h48map_lookup(h48map_t *, uint64_t);
119_static void h48map_insertmin(h48map_t *, uint64_t, uint64_t);
120_static uint64_t h48map_value(h48map_t *, uint64_t);
121_static kvpair_t h48map_nextkvpair(h48map_t *, uint64_t *);
122
123_static_inline int64_t coord_h48(cube_t, const uint32_t *, uint8_t);
124_static_inline int64_t coord_h48_edges(cube_t, int64_t, uint8_t, uint8_t);
125_static_inline cube_t invcoord_h48(int64_t, const cube_t *, uint8_t);
126
127_static_inline bool get_visited(const uint8_t *, int64_t);
128_static_inline void set_visited(uint8_t *, int64_t);
129_static_inline uint8_t get_esep_pval(const uint32_t *, int64_t);
130_static_inline void set_esep_pval(uint32_t *, int64_t, uint8_t);
131
132_static size_t gendata_cocsep(void *, uint64_t *, cube_t *);
133_static uint32_t gendata_cocsep_dfs(dfsarg_cocsep_t *);
134_static uint64_t gen_h48short(
135 uint8_t, const uint32_t *, const cube_t *, const uint64_t *, h48map_t *);
136_static size_t gendata_h48h0k4(void *, uint8_t);
137_static int64_t gendata_h48h0k4_bfs(bfsarg_esep_t *);
138_static int64_t gendata_h48h0k4_bfs_fromdone(bfsarg_esep_t *);
139_static int64_t gendata_h48h0k4_bfs_fromnew(bfsarg_esep_t *);
140
141_static void solve_h48_appendsolution(dfsarg_solveh48_t *);
142_static_inline int8_t get_h48_cdata(cube_t, uint32_t *, uint32_t *);
143_static_inline int8_t get_h48_bound(cube_t, uint32_t, uint8_t, uint32_t *);
144_static_inline bool solve_h48_stop(dfsarg_solveh48_t *);
145_static int64_t solve_h48_dfs(dfsarg_solveh48_t *);
146_static int64_t solve_h48(
147 cube_t, int8_t, int8_t, int8_t, uint8_t, const void *, char *);
148
149_static int64_t solve_h48stats_dfs(dfsarg_solveh48stats_t *);
150_static int64_t solve_h48stats(cube_t, int8_t, const void *, char [static 12]);
151
152_static void
153h48map_create(h48map_t *map, uint64_t capacity, uint64_t randomizer)
154{
155 map->capacity = capacity;
156 map->randomizer = randomizer;
157
158 map->table = malloc(map->capacity * sizeof(int64_t));
159 h48map_clear(map);
160}
161
162_static void
163h48map_clear(h48map_t *map)
164{
165 memset(map->table, 0xFF, map->capacity * sizeof(uint64_t));
166 map->n = 0;
167}
168
169_static void
170h48map_destroy(h48map_t *map)
171{
172 free(map->table);
173}
174
175_static_inline uint64_t
176h48map_lookup(h48map_t *map, uint64_t x)
177{
178 uint64_t hash, i;
179
180 hash = ((x % map->capacity) * map->randomizer) % map->capacity;
181 for (i = hash;
182 map->table[i] != MAP_UNSET && (map->table[i] & MAP_KEYMASK) != x;
183 i = (i+1) % map->capacity
184 ) ;
185
186 return i;
187}
188
189_static_inline void
190h48map_insertmin(h48map_t *map, uint64_t key, uint64_t val)
191{
192 uint64_t i, oldval, min;
193
194 i = h48map_lookup(map, key);
195 oldval = map->table[i] >> MAP_KEYSHIFT;
196 min = _min(val, oldval);
197
198 map->n += map->table[i] == MAP_UNSET;
199 map->table[i] = (key & MAP_KEYMASK) | (min << MAP_KEYSHIFT);
200}
201
202_static_inline uint64_t
203h48map_value(h48map_t *map, uint64_t key)
204{
205 return map->table[h48map_lookup(map, key)] >> MAP_KEYSHIFT;
206}
207
208_static kvpair_t
209h48map_nextkvpair(h48map_t *map, uint64_t *p)
210{
211 kvpair_t kv;
212 uint64_t pair;
213
214 kv.key = MAP_UNSET;
215 kv.val = MAP_UNSET;
216
217 DBG_ASSERT(*p < map->capacity, kv,
218 "Error looping over map: given index %" PRIu64 " is out of "
219 "range [0,%" PRIu64 "]", *p, map->capacity);
220
221 for ( ; *p < map->capacity; (*p)++) {
222 if (map->table[*p] != MAP_UNSET) {
223 pair = map->table[(*p)++];
224 kv.key = pair & MAP_KEYMASK;
225 kv.val = pair >> MAP_KEYSHIFT;
226 return kv;
227 }
228 }
229
230 return kv;
231}
232
233_static_inline int64_t
234coord_h48(cube_t c, const uint32_t *cocsepdata, uint8_t h)
235{
236 int64_t cocsep, coclass;
237 uint32_t data;
238 uint8_t ttrep;
239
240 DBG_ASSERT(h <= 11, -1, "coord_h48: h must be between 0 and 11\n");
241
242 cocsep = coord_cocsep(c);
243 data = cocsepdata[cocsep];
244 coclass = (int64_t)COCLASS(data);
245 ttrep = (int64_t)TTREP(data);
246
247 return coord_h48_edges(c, coclass, ttrep, h);
248}
249
250_static_inline int64_t
251coord_h48_edges(cube_t c, int64_t coclass, uint8_t ttrep, uint8_t h)
252{
253 cube_t d;
254 int64_t esep, eo, edges;
255
256 d = transform_edges(c, ttrep);
257 esep = coord_esep(d);
258 eo = coord_eo(d);
259 edges = (esep << 11) + eo;
260
261 return (coclass * H48_ESIZE(11) + edges) >> (11 - (int64_t)h);
262}
263
264/*
265This function does not necessarily return a cube whose coordinate is
266the given value, because it works up to symmetry. This means that the
267returned cube is a transformed cube of one that gives the correct value.
268*/
269_static_inline cube_t
270invcoord_h48(int64_t i, const cube_t *crep, uint8_t h)
271{
272 cube_t ret;
273 int64_t hh, coclass, ee, esep, eo;
274
275 DBG_ASSERT(h <= 11, zero,
276 "invcoord_h48: h must be between 0 and 11\n");
277
278 hh = (int64_t)h;
279 coclass = i / H48_ESIZE(h);
280 ee = i % H48_ESIZE(h);
281 esep = ee >> hh;
282 eo = (ee & ((1 << hh) - 1)) << (11 - hh);
283
284 ret = invcoord_esep(esep);
285 copy_corners(&ret, crep[coclass]);
286 set_eo(&ret, eo);
287
288 return ret;
289}
290
291/*
292Each element of the cocsep table is a uint32_t used as follows:
293 - Lowest 8-bit block: pruning value
294 - Second-lowest 8-bit block: "ttrep" (transformation to representative)
295 - Top 16-bit block: symcoord value
296After the data as described above, more auxiliary information is appended:
297 - A uint32_t representing the number of symmetry classes
298 - A uint32_t representing the highest value of the pruning table
299 - One uint32_t for each "line" of the pruning table, representing the number
300 of positions having that pruning value.
301*/
302_static size_t
303gendata_cocsep(void *buf, uint64_t *selfsim, cube_t *rep)
304{
305 uint32_t *buf32, *info, cc;
306 uint16_t n;
307 uint8_t i, j, visited[COCSEP_VISITEDSIZE];
308 dfsarg_cocsep_t arg;
309
310 if (buf == NULL)
311 goto gendata_cocsep_return_size;
312
313 buf32 = (uint32_t *)buf;
314 info = buf32 + COCSEP_TABLESIZE;
315 memset(buf32, 0xFF, sizeof(uint32_t) * COCSEP_TABLESIZE);
316 if (selfsim != NULL)
317 memset(selfsim, 0, sizeof(uint64_t) * COCSEP_CLASSES);
318
319 arg = (dfsarg_cocsep_t) {
320 .cube = solved,
321 .n = &n,
322 .buf32 = buf32,
323 .visited = visited,
324 .selfsim = selfsim,
325 .rep = rep
326 };
327 for (i = 0, n = 0, cc = 0; i < 10; i++) {
328 LOG("cocsep: generating depth %" PRIu8 "\n", i);
329 memset(visited, 0, COCSEP_VISITEDSIZE);
330 arg.depth = 0;
331 arg.maxdepth = i;
332 cc = gendata_cocsep_dfs(&arg);
333 info[i+2] = cc;
334 LOG("found %" PRIu32 "\n", cc);
335 }
336
337 info[0] = (uint32_t)n;
338 info[1] = 9; /* Known max pruning value */
339 DBG_ASSERT(n == COCSEP_CLASSES, 0,
340 "cocsep: computed %" PRIu16 " symmetry classes, "
341 "expected %zu\n", n, COCSEP_CLASSES);
342
343 LOG("cocsep data computed\n");
344 LOG("Symmetry classes: %" PRIu32 "\n", info[0]);
345 LOG("Maximum pruning value: %" PRIu32 "\n", info[1]);
346 LOG("Pruning value distribution:\n");
347 for (j = 0; j < 10; j++)
348 LOG("%" PRIu8 ":\t%" PRIu32 "\n", j, info[j+2]);
349
350gendata_cocsep_return_size:
351 return COCSEP_FULLSIZE;
352}
353
354_static uint32_t
355gendata_cocsep_dfs(dfsarg_cocsep_t *arg)
356{
357 uint8_t m;
358 uint32_t cc, class, ttrep, depth, olddepth, tinv;
359 uint64_t t;
360 int64_t i, j;
361 cube_t d;
362 dfsarg_cocsep_t nextarg;
363
364 i = coord_cocsep(arg->cube);
365 olddepth = (uint8_t)(arg->buf32[i] & 0xFF);
366 if (olddepth < arg->depth || get_visited(arg->visited, i))
367 return 0;
368 set_visited(arg->visited, i);
369
370 if (arg->depth == arg->maxdepth) {
371 if ((arg->buf32[i] & 0xFF) != 0xFF)
372 return 0;
373
374 if (arg->rep != NULL)
375 arg->rep[*arg->n] = arg->cube;
376 for (t = 0, cc = 0; t < 48; t++) {
377 d = transform_corners(arg->cube, t);
378 j = coord_cocsep(d);
379 if (i == j && arg->selfsim != NULL)
380 arg->selfsim[*arg->n] |= UINT64_C(1) << t;
381 if (COCLASS(arg->buf32[j]) != UINT32_C(0xFFFF))
382 continue;
383 set_visited(arg->visited, j);
384 tinv = inverse_trans(t);
385 olddepth = arg->buf32[j] & 0xFF;
386 cc += olddepth == 0xFF;
387
388 class = (uint32_t)(*arg->n) << UINT32_C(16);
389 ttrep = (uint32_t)tinv << UINT32_C(8);
390 depth = (uint32_t)arg->depth;
391 arg->buf32[j] = class | ttrep | depth;
392 }
393 (*arg->n)++;
394
395 return cc;
396 }
397
398 memcpy(&nextarg, arg, sizeof(dfsarg_cocsep_t));
399 nextarg.depth++;
400 for (m = 0, cc = 0; m < 18; m++) {
401 nextarg.cube = move(arg->cube, m);
402 cc += gendata_cocsep_dfs(&nextarg);
403 }
404
405 return cc;
406}
407
408_static uint64_t
409gen_h48short(
410 uint8_t n,
411 const uint32_t *cocsepdata,
412 const cube_t *crep,
413 const uint64_t *selfsim,
414 h48map_t *map
415) {
416 uint8_t i, m;
417 int64_t coord;
418 uint64_t j, oldn;
419 kvpair_t kv;
420 cube_t cube, d;
421
422 cube = solvedcube();
423 coord = coord_h48(cube, cocsepdata, 11);
424 h48map_insertmin(map, coord, 0);
425 oldn = 0;
426 LOG("Short h48: generating depth 0\nfound %" PRIu8 "\n", map->n-oldn);
427 for (i = 0; i < n; i++) {
428 LOG("Short h48: generating depth %" PRIu8 "\n", i+1);
429 j = 0;
430 oldn = map->n;
431 for (kv = h48map_nextkvpair(map, &j);
432 j != map->capacity;
433 kv = h48map_nextkvpair(map, &j)
434 ) {
435 if (kv.val != i)
436 continue;
437 cube = invcoord_h48(kv.key, crep, 11);
438 for (m = 0; m < 18; m++) {
439 d = move(cube, m);
440 _foreach_h48sim(d, cocsepdata, selfsim, 11,
441 coord = coord_h48(d, cocsepdata, 11);
442 h48map_insertmin(map, coord, i+1);
443 )
444 }
445 }
446 LOG("found %" PRIu8 "\n", map->n-oldn);
447 }
448
449 return map->n;
450}
451
452/*
453TODO description
454generating fixed table with h=0, k=4
455*/
456_static size_t
457gendata_h48h0k4(void *buf, uint8_t maxdepth)
458{
459 uint32_t j, *buf32, *info, *cocsepdata;
460 bfsarg_esep_t arg;
461 int64_t sc, cc, esep_max;
462 uint64_t selfsim[COCSEP_CLASSES];
463 cube_t crep[COCSEP_CLASSES];
464 size_t cocsepsize, infosize;
465
466 /* TODO: move info at start of tables (all tables!) */
467 infosize = 4 * maxdepth;
468 cocsepsize = gendata_cocsep(buf, selfsim, crep);
469 infosize = 88;
470
471 if (buf == NULL)
472 goto gendata_h48h0k4_return_size;
473
474 esep_max = (int64_t)ESEP_MAX(0);
475 cocsepdata = (uint32_t *)buf;
476 buf32 = cocsepdata + cocsepsize / 4;
477 info = buf32 + (ESEP_TABLESIZE(0, 4) / sizeof(uint32_t));
478 memset(buf32, 0xFF, ESEP_TABLESIZE(0, 4));
479
480 sc = coord_h48(solved, cocsepdata, 0);
481 set_esep_pval(buf32, sc, 0);
482 info[1] = 1;
483 arg = (bfsarg_esep_t) {
484 .cocsepdata = cocsepdata,
485 .buf32 = buf32,
486 .selfsim = selfsim,
487 .crep = crep
488 };
489 for (
490 arg.done = 1, arg.depth = 1, cc = 0;
491 arg.done < esep_max && arg.depth <= maxdepth;
492 arg.depth++
493 ) {
494 LOG("esep: generating depth %" PRIu8 "\n", arg.depth);
495 cc = gendata_h48h0k4_bfs(&arg);
496 arg.done += cc;
497 info[arg.depth+1] = cc;
498 LOG("found %" PRId64 "\n", cc);
499 }
500
501 info[0] = arg.depth-1;
502
503 LOG("h48 pruning table computed\n");
504 LOG("Maximum pruning value: %" PRIu32 "\n", info[0]);
505 LOG("Pruning value distribution:\n");
506 for (j = 0; j <= info[0]; j++)
507 LOG("%" PRIu8 ":\t%" PRIu32 "\n", j, info[j+1]);
508
509gendata_h48h0k4_return_size:
510 return cocsepsize + ESEP_TABLESIZE(0, 4) + infosize;
511}
512
513_static int64_t
514gendata_h48h0k4_bfs(bfsarg_esep_t *arg)
515{
516 const uint8_t breakpoint = 10; /* Hand-picked optimal */
517
518 if (arg->depth < breakpoint)
519 return gendata_h48h0k4_bfs_fromdone(arg);
520 else
521 return gendata_h48h0k4_bfs_fromnew(arg);
522}
523
524_static int64_t
525gendata_h48h0k4_bfs_fromdone(bfsarg_esep_t *arg)
526{
527 uint8_t c, m, x;
528 uint32_t cc;
529 int64_t i, j, k;
530 cube_t cube, moved;
531
532 for (i = 0, cc = 0; i < (int64_t)ESEP_MAX(0); i++) {
533 c = get_esep_pval(arg->buf32, i);
534 if (c != arg->depth - 1)
535 continue;
536 cube = invcoord_h48(i, arg->crep, 0);
537 for (m = 0; m < 18; m++) {
538 moved = move(cube, m);
539 j = coord_h48(moved, arg->cocsepdata, 0);
540 if (get_esep_pval(arg->buf32, j) <= arg->depth)
541 continue;
542 _foreach_h48sim(moved, arg->cocsepdata, arg->selfsim, 0,
543 k = coord_h48(moved, arg->cocsepdata, 0);
544 x = get_esep_pval(arg->buf32, k);
545 set_esep_pval(arg->buf32, k, arg->depth);
546 cc += x != arg->depth;
547 )
548 }
549 }
550
551 return cc;
552}
553
554_static int64_t
555gendata_h48h0k4_bfs_fromnew(bfsarg_esep_t *arg)
556{
557 uint8_t c, m, x;
558 uint32_t cc;
559 int64_t i, j;
560 cube_t cube, moved;
561
562 for (i = 0, cc = 0; i < (int64_t)ESEP_MAX(0); i++) {
563 c = get_esep_pval(arg->buf32, i);
564 if (c != 0xF)
565 continue;
566 cube = invcoord_h48(i, arg->crep, 0);
567 for (m = 0; m < 18; m++) {
568 moved = move(cube, m);
569 j = coord_h48(moved, arg->cocsepdata, 0);
570 x = get_esep_pval(arg->buf32, j);
571 if (x >= arg->depth)
572 continue;
573 _foreach_h48sim(cube, arg->cocsepdata, arg->selfsim, 0,
574 j = coord_h48(cube, arg->cocsepdata, 0);
575 x = get_esep_pval(arg->buf32, j);
576 set_esep_pval(arg->buf32, j, arg->depth);
577 cc += x == 0xF;
578 )
579 break; /* Enough to find one, skip the rest */
580 }
581 }
582
583 return cc;
584}
585
586_static_inline bool
587get_visited(const uint8_t *a, int64_t i)
588{
589 return a[VISITED_IND(i)] & VISITED_MASK(i);
590}
591
592_static_inline void
593set_visited(uint8_t *a, int64_t i)
594{
595 a[VISITED_IND(i)] |= VISITED_MASK(i);
596}
597
598_static_inline uint8_t
599get_esep_pval(const uint32_t *buf32, int64_t i)
600{
601 return (buf32[ESEP_IND(i)] & ESEP_MASK(i)) >> ESEP_SHIFT(i);
602}
603
604_static_inline void
605set_esep_pval(uint32_t *buf32, int64_t i, uint8_t val)
606{
607 buf32[ESEP_IND(i)] =
608 (buf32[ESEP_IND(i)] & (~ESEP_MASK(i))) | (val << ESEP_SHIFT(i));
609}
610
611_static void
612solve_h48_appendsolution(dfsarg_solveh48_t *arg)
613{
614 int strl;
615
616 strl = writemoves(arg->moves, arg->nmoves, *arg->nextsol);
617 LOG("Solution found: %s\n", *arg->nextsol);
618 *arg->nextsol += strl;
619 **arg->nextsol = '\n';
620 (*arg->nextsol)++;
621 (*arg->nsols)++;
622}
623
624_static_inline int8_t
625get_h48_cdata(cube_t cube, uint32_t *cocsepdata, uint32_t *cdata)
626{
627 int64_t coord;
628
629 coord = coord_cocsep(cube);
630 *cdata = cocsepdata[coord];
631
632 return CBOUND(*cdata);
633}
634
635_static_inline int8_t
636get_h48_bound(cube_t cube, uint32_t cdata, uint8_t h, uint32_t *h48data)
637{
638 int64_t coord;
639
640 coord = coord_h48_edges(cube, COCLASS(cdata), TTREP(cdata), h);
641 return get_esep_pval(h48data, coord);
642}
643
644_static_inline bool
645solve_h48_stop(dfsarg_solveh48_t *arg)
646{
647 uint32_t data, data_inv;
648 int8_t bound;
649
650 bound = get_h48_cdata(arg->cube, arg->cocsepdata, &data);
651 if (bound + arg->nmoves > arg->depth)
652 return true;
653
654 bound = get_h48_cdata(arg->inverse, arg->cocsepdata, &data_inv);
655 if (bound + arg->nmoves > arg->depth)
656 return true;
657
658/*
659 bound = get_h48_bound(arg->cube, data, arg->h, arg->h48data);
660LOG("Using pval %" PRId8 "\n", bound);
661 if (bound + arg->nmoves > arg->depth)
662 return true;
663
664 bound = get_h48_bound(arg->inverse, data_inv, arg->h, arg->h48data);
665 if (bound + arg->nmoves > arg->depth)
666 return true;
667*/
668
669 return false;
670}
671
672_static int64_t
673solve_h48_dfs(dfsarg_solveh48_t *arg)
674{
675 dfsarg_solveh48_t nextarg;
676 int64_t ret;
677 uint8_t m;
678
679 if (*arg->nsols == arg->maxsolutions)
680 return 0;
681
682 if (solve_h48_stop(arg))
683 return 0;
684
685 if (issolved(arg->cube)) {
686 if (arg->nmoves != arg->depth)
687 return 0;
688 solve_h48_appendsolution(arg);
689 return 1;
690 }
691
692 /* TODO: avoid copy, change arg and undo changes after recursion */
693 nextarg = *arg;
694 nextarg.nmoves = arg->nmoves + 1;
695 ret = 0;
696 for (m = 0; m < 18; m++) {
697 nextarg.moves[arg->nmoves] = m;
698 if (!allowednextmove(nextarg.moves, nextarg.nmoves)) {
699 /* If a move is not allowed, neither are its 180
700 * and 270 degree variations */
701 m += 2;
702 continue;
703 }
704 nextarg.cube = move(arg->cube, m);
705 nextarg.inverse = inverse(nextarg.cube); /* TODO: use premove */
706 ret += solve_h48_dfs(&nextarg);
707 }
708
709 return ret;
710}
711
712_static int64_t
713solve_h48(
714 cube_t cube,
715 int8_t minmoves,
716 int8_t maxmoves,
717 int8_t maxsolutions,
718 uint8_t h,
719 const void *data,
720 char *solutions
721)
722{
723 int64_t nsols;
724 dfsarg_solveh48_t arg;
725
726 arg = (dfsarg_solveh48_t) {
727 .cube = cube,
728 .inverse = inverse(cube),
729 .nsols = &nsols,
730 .maxsolutions = maxsolutions,
731 .h = h,
732 .cocsepdata = (uint32_t *)data,
733 .h48data = ((uint32_t *)data) + COCSEP_FULLSIZE / 4,
734 .nextsol = &solutions
735 };
736
737 nsols = 0;
738 for (arg.depth = minmoves;
739 arg.depth <= maxmoves && nsols < maxsolutions;
740 arg.depth++)
741 {
742 LOG("Found %" PRId64 " solutions, searching at depth %"
743 PRId8 "\n", nsols, arg.depth);
744 arg.nmoves = 0;
745 solve_h48_dfs(&arg);
746 }
747
748 return nsols;
749}
750
751/*
752The h48stats solver computes how many moves it takes to solve to
753each of the 12 h48 coordinates, one for each value of h from 0 to 11.
754The solutions array is filled with the length of the solutions. The
755solution array is therefore not a printable string.
756*/
757_static int64_t
758solve_h48stats_dfs(dfsarg_solveh48stats_t *arg)
759{
760 const int64_t limit = 11;
761
762 int8_t bound, u;
763 uint8_t m;
764 uint32_t d;
765 int64_t coord, h;
766 dfsarg_solveh48stats_t nextarg;
767
768 /* Check cocsep lower bound (corners only) */
769 bound = get_h48_cdata(arg->cube, arg->cocsepdata, &d);
770 if (bound + arg->nmoves > arg->depth)
771 return 0;
772
773 /* Check h48 lower bound for h=0 (esep, but no eo) */
774 coord = coord_h48_edges(arg->cube, COCLASS(d), TTREP(d), 0);
775 bound = get_esep_pval(arg->h48data, coord);
776 if (bound + arg->nmoves > arg->depth)
777 return 0;
778
779 /* Update all other values, if solved */
780 coord = coord_h48_edges(arg->cube, COCLASS(d), TTREP(d), 11);
781 for (h = 0; h <= limit; h++) {
782 u = coord >> (11-h) == 0 && arg->s[h] == 99;
783 arg->s[h] = u * arg->nmoves + (1-u) * arg->s[h];
784 }
785
786 if (arg->s[limit] != 99)
787 return 0;
788
789 nextarg = *arg;
790 nextarg.nmoves = arg->nmoves + 1;
791 for (m = 0; m < 18; m++) {
792 nextarg.moves[arg->nmoves] = m;
793 if (!allowednextmove(nextarg.moves, nextarg.nmoves)) {
794 /* If a move is not allowed, neither are its 180
795 * and 270 degree variations */
796 m += 2;
797 continue;
798 }
799 nextarg.cube = move(arg->cube, m);
800 solve_h48stats_dfs(&nextarg);
801 }
802
803 return 0;
804}
805
806_static int64_t
807solve_h48stats(
808 cube_t cube,
809 int8_t maxmoves,
810 const void *data,
811 char solutions[static 12]
812)
813{
814 int i;
815 size_t cocsepsize;
816 dfsarg_solveh48stats_t arg;
817
818 cocsepsize = gendata_cocsep(NULL, NULL, NULL);
819
820 arg = (dfsarg_solveh48stats_t) {
821 .cube = cube,
822 .cocsepdata = (uint32_t *)data,
823 .h48data = ((uint32_t *)data) + (cocsepsize/4),
824 .s = solutions
825 };
826
827 for (i = 0; i < 12; i++)
828 solutions[i] = (char)99;
829
830 for (arg.depth = 0;
831 arg.depth <= maxmoves && solutions[11] == 99;
832 arg.depth++)
833 {
834 arg.nmoves = 0;
835 solve_h48stats_dfs(&arg);
836 }
837
838 return 0;
839}

Generated with cgit - Back to sebastiano.tronto.net