aboutsummaryrefslogtreecommitdiff
path: root/src/solvers/h48
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/solvers/h48
parentf25a10e19eca294c4e6a99e4f80ce5cfd11a0e5f (diff)
downloadnissy-core-18c9a8b8905304cf5f8fc15825769046a3144866.tar.gz
nissy-core-18c9a8b8905304cf5f8fc15825769046a3144866.zip
Reorganized folder structure
Diffstat (limited to 'src/solvers/h48')
-rw-r--r--src/solvers/h48/coordinate.h68
-rw-r--r--src/solvers/h48/gendata.h425
-rw-r--r--src/solvers/h48/h48.h4
-rw-r--r--src/solvers/h48/map.h104
-rw-r--r--src/solvers/h48/solve.h242
5 files changed, 843 insertions, 0 deletions
diff --git a/src/solvers/h48/coordinate.h b/src/solvers/h48/coordinate.h
new file mode 100644
index 0000000..47b805d
--- /dev/null
+++ b/src/solvers/h48/coordinate.h
@@ -0,0 +1,68 @@
1#define H48_ESIZE(h) ((_12c4 * _8c4) << (int64_t)(h))
2
3#define COCLASS_MASK (UINT32_C(0xFFFF) << UINT32_C(16))
4#define COCLASS(x) (((x) & COCLASS_MASK) >> UINT32_C(16))
5#define TTREP_MASK (UINT32_C(0xFF) << UINT32_C(8))
6#define TTREP(x) (((x) & TTREP_MASK) >> UINT32_C(8))
7
8_static_inline int64_t coord_h48(cube_t, const uint32_t *, uint8_t);
9_static_inline int64_t coord_h48_edges(cube_t, int64_t, uint8_t, uint8_t);
10_static_inline cube_t invcoord_h48(int64_t, const cube_t *, uint8_t);
11
12_static_inline int64_t
13coord_h48(cube_t c, const uint32_t *cocsepdata, uint8_t h)
14{
15 int64_t cocsep, coclass;
16 uint32_t data;
17 uint8_t ttrep;
18
19 DBG_ASSERT(h <= 11, -1, "coord_h48: h must be between 0 and 11\n");
20
21 cocsep = coord_cocsep(c);
22 data = cocsepdata[cocsep];
23 coclass = (int64_t)COCLASS(data);
24 ttrep = (int64_t)TTREP(data);
25
26 return coord_h48_edges(c, coclass, ttrep, h);
27}
28
29_static_inline int64_t
30coord_h48_edges(cube_t c, int64_t coclass, uint8_t ttrep, uint8_t h)
31{
32 cube_t d;
33 int64_t esep, eo, edges;
34
35 d = transform_edges(c, ttrep);
36 esep = coord_esep(d);
37 eo = coord_eo(d);
38 edges = (esep << 11) + eo;
39
40 return (coclass * H48_ESIZE(11) + edges) >> (11 - (int64_t)h);
41}
42
43/*
44This function does not necessarily return a cube whose coordinate is
45the given value, because it works up to symmetry. This means that the
46returned cube is a transformed cube of one that gives the correct value.
47*/
48_static_inline cube_t
49invcoord_h48(int64_t i, const cube_t *crep, uint8_t h)
50{
51 cube_t ret;
52 int64_t hh, coclass, ee, esep, eo;
53
54 DBG_ASSERT(h <= 11, zero,
55 "invcoord_h48: h must be between 0 and 11\n");
56
57 hh = (int64_t)h;
58 coclass = i / H48_ESIZE(h);
59 ee = i % H48_ESIZE(h);
60 esep = ee >> hh;
61 eo = (ee & ((1 << hh) - 1)) << (11 - hh);
62
63 ret = invcoord_esep(esep);
64 copy_corners(&ret, crep[coclass]);
65 set_eo(&ret, eo);
66
67 return ret;
68}
diff --git a/src/solvers/h48/gendata.h b/src/solvers/h48/gendata.h
new file mode 100644
index 0000000..d6bf85b
--- /dev/null
+++ b/src/solvers/h48/gendata.h
@@ -0,0 +1,425 @@
1#define COCSEP_CLASSES ((size_t)3393)
2#define COCSEP_TABLESIZE ((size_t)_3p7 << (size_t)7)
3#define COCSEP_VISITEDSIZE ((COCSEP_TABLESIZE + (size_t)7) / (size_t)8)
4#define COCSEP_FULLSIZE ((size_t)4 * (COCSEP_TABLESIZE + (size_t)12))
5
6#define ESEP_NOEO (COCSEP_CLASSES * (size_t)_12c4 * (size_t)_8c4)
7#define ESEP_MAX(h) (ESEP_NOEO << (size_t)(h))
8#define ESEP_TABLESIZE(h, k) (ESEP_MAX((h)) / ((size_t)8 / (size_t)(k)))
9
10#define ESEP_IND(i) ((uint32_t)(i) / UINT32_C(8))
11#define ESEP_SHIFT(i) (UINT32_C(4) * ((uint32_t)(i) % UINT32_C(8)))
12#define ESEP_MASK(i) ((_bit_u32(4) - (uint32_t)(1)) << ESEP_SHIFT(i))
13#define VISITED_IND(i) ((uint32_t)(i) / UINT32_C(8))
14#define VISITED_MASK(i) (UINT32_C(1) << ((uint32_t)(i) % UINT32_C(8)))
15
16#define CBOUND_MASK UINT32_C(0xFF)
17#define CBOUND(x) ((x) & CBOUND_MASK)
18
19#define MAXLEN 20
20
21/*
22TODO: This loop over similar h48 coordinates can be improved by only
23transforming edges, but we need to compose transformations (i.e. conjugate
24_t by _ttrep).
25*/
26#define _foreach_h48sim(_cube, _cocsepdata, _selfsim, _h, _action) \
27 int64_t _cocsep = coord_cocsep(_cube); \
28 uint8_t _ttrep = TTREP(_cocsepdata[_cocsep]); \
29 uint8_t _inverse_ttrep = inverse_trans(_ttrep); \
30 int64_t _coclass = COCLASS(_cocsepdata[_cocsep]); \
31 cube_t _rep = transform(_cube, _ttrep); \
32 uint64_t _sim = _selfsim[_coclass]; \
33 for (uint8_t _t = 0; _t < 48 && _sim; _t++, _sim >>= 1) { \
34 if (!(_sim & 1)) continue; \
35 _cube = transform(_rep, _t); \
36 _cube = transform(_cube, _inverse_ttrep); \
37 _action \
38 }
39
40typedef struct {
41 cube_t cube;
42 uint8_t depth;
43 uint8_t maxdepth;
44 uint16_t *n;
45 uint32_t *buf32;
46 uint8_t *visited;
47 uint64_t *selfsim;
48 cube_t *rep;
49} dfsarg_cocsep_t;
50
51/* TODO keep or not? */
52typedef struct {
53 cube_t cube;
54 int8_t nmoves;
55 int8_t depth;
56 uint8_t moves[MAXLEN];
57 uint32_t *cocsepdata;
58 h48map_t *visited;
59} dfsarg_genh48set_t;
60
61typedef struct {
62 uint8_t depth;
63 uint32_t *cocsepdata;
64 uint32_t *buf32;
65 uint64_t *selfsim;
66 int64_t done;
67 cube_t *crep;
68} bfsarg_esep_t;
69
70_static_inline bool get_visited(const uint8_t *, int64_t);
71_static_inline void set_visited(uint8_t *, int64_t);
72_static_inline uint8_t get_esep_pval(const uint32_t *, int64_t);
73_static_inline void set_esep_pval(uint32_t *, int64_t, uint8_t);
74
75_static size_t gendata_cocsep(void *, uint64_t *, cube_t *);
76_static uint32_t gendata_cocsep_dfs(dfsarg_cocsep_t *);
77_static uint64_t gen_h48short(
78 uint8_t, const uint32_t *, const cube_t *, const uint64_t *, h48map_t *);
79_static size_t gendata_h48h0k4(void *, uint8_t);
80_static int64_t gendata_h48h0k4_bfs(bfsarg_esep_t *);
81_static int64_t gendata_h48h0k4_bfs_fromdone(bfsarg_esep_t *);
82_static int64_t gendata_h48h0k4_bfs_fromnew(bfsarg_esep_t *);
83
84_static_inline int8_t get_h48_cdata(cube_t, uint32_t *, uint32_t *);
85_static_inline int8_t get_h48_bound(cube_t, uint32_t, uint8_t, uint32_t *);
86
87/*
88Each element of the cocsep table is a uint32_t used as follows:
89 - Lowest 8-bit block: pruning value
90 - Second-lowest 8-bit block: "ttrep" (transformation to representative)
91 - Top 16-bit block: symcoord value
92After the data as described above, more auxiliary information is appended:
93 - A uint32_t representing the number of symmetry classes
94 - A uint32_t representing the highest value of the pruning table
95 - One uint32_t for each "line" of the pruning table, representing the number
96 of positions having that pruning value.
97*/
98_static size_t
99gendata_cocsep(void *buf, uint64_t *selfsim, cube_t *rep)
100{
101 uint32_t *buf32, *info, cc;
102 uint16_t n;
103 uint8_t i, j, visited[COCSEP_VISITEDSIZE];
104 dfsarg_cocsep_t arg;
105
106 if (buf == NULL)
107 goto gendata_cocsep_return_size;
108
109 buf32 = (uint32_t *)buf;
110 info = buf32 + COCSEP_TABLESIZE;
111 memset(buf32, 0xFF, sizeof(uint32_t) * COCSEP_TABLESIZE);
112 if (selfsim != NULL)
113 memset(selfsim, 0, sizeof(uint64_t) * COCSEP_CLASSES);
114
115 arg = (dfsarg_cocsep_t) {
116 .cube = solved,
117 .n = &n,
118 .buf32 = buf32,
119 .visited = visited,
120 .selfsim = selfsim,
121 .rep = rep
122 };
123 for (i = 0, n = 0, cc = 0; i < 10; i++) {
124 LOG("cocsep: generating depth %" PRIu8 "\n", i);
125 memset(visited, 0, COCSEP_VISITEDSIZE);
126 arg.depth = 0;
127 arg.maxdepth = i;
128 cc = gendata_cocsep_dfs(&arg);
129 info[i+2] = cc;
130 LOG("found %" PRIu32 "\n", cc);
131 }
132
133 info[0] = (uint32_t)n;
134 info[1] = 9; /* Known max pruning value */
135 DBG_ASSERT(n == COCSEP_CLASSES, 0,
136 "cocsep: computed %" PRIu16 " symmetry classes, "
137 "expected %zu\n", n, COCSEP_CLASSES);
138
139 LOG("cocsep data computed\n");
140 LOG("Symmetry classes: %" PRIu32 "\n", info[0]);
141 LOG("Maximum pruning value: %" PRIu32 "\n", info[1]);
142 LOG("Pruning value distribution:\n");
143 for (j = 0; j < 10; j++)
144 LOG("%" PRIu8 ":\t%" PRIu32 "\n", j, info[j+2]);
145
146gendata_cocsep_return_size:
147 return COCSEP_FULLSIZE;
148}
149
150_static uint32_t
151gendata_cocsep_dfs(dfsarg_cocsep_t *arg)
152{
153 uint8_t m;
154 uint32_t cc, class, ttrep, depth, olddepth, tinv;
155 uint64_t t;
156 int64_t i, j;
157 cube_t d;
158 dfsarg_cocsep_t nextarg;
159
160 i = coord_cocsep(arg->cube);
161 olddepth = (uint8_t)(arg->buf32[i] & 0xFF);
162 if (olddepth < arg->depth || get_visited(arg->visited, i))
163 return 0;
164 set_visited(arg->visited, i);
165
166 if (arg->depth == arg->maxdepth) {
167 if ((arg->buf32[i] & 0xFF) != 0xFF)
168 return 0;
169
170 if (arg->rep != NULL)
171 arg->rep[*arg->n] = arg->cube;
172 for (t = 0, cc = 0; t < 48; t++) {
173 d = transform_corners(arg->cube, t);
174 j = coord_cocsep(d);
175 if (i == j && arg->selfsim != NULL)
176 arg->selfsim[*arg->n] |= UINT64_C(1) << t;
177 if (COCLASS(arg->buf32[j]) != UINT32_C(0xFFFF))
178 continue;
179 set_visited(arg->visited, j);
180 tinv = inverse_trans(t);
181 olddepth = arg->buf32[j] & 0xFF;
182 cc += olddepth == 0xFF;
183
184 class = (uint32_t)(*arg->n) << UINT32_C(16);
185 ttrep = (uint32_t)tinv << UINT32_C(8);
186 depth = (uint32_t)arg->depth;
187 arg->buf32[j] = class | ttrep | depth;
188 }
189 (*arg->n)++;
190
191 return cc;
192 }
193
194 memcpy(&nextarg, arg, sizeof(dfsarg_cocsep_t));
195 nextarg.depth++;
196 for (m = 0, cc = 0; m < 18; m++) {
197 nextarg.cube = move(arg->cube, m);
198 cc += gendata_cocsep_dfs(&nextarg);
199 }
200
201 return cc;
202}
203
204_static uint64_t
205gen_h48short(
206 uint8_t n,
207 const uint32_t *cocsepdata,
208 const cube_t *crep,
209 const uint64_t *selfsim,
210 h48map_t *map
211) {
212 uint8_t i, m;
213 int64_t coord;
214 uint64_t j, oldn;
215 kvpair_t kv;
216 cube_t cube, d;
217
218 cube = solvedcube();
219 coord = coord_h48(cube, cocsepdata, 11);
220 h48map_insertmin(map, coord, 0);
221 oldn = 0;
222 LOG("Short h48: generating depth 0\nfound %" PRIu8 "\n", map->n-oldn);
223 for (i = 0; i < n; i++) {
224 LOG("Short h48: generating depth %" PRIu8 "\n", i+1);
225 j = 0;
226 oldn = map->n;
227 for (kv = h48map_nextkvpair(map, &j);
228 j != map->capacity;
229 kv = h48map_nextkvpair(map, &j)
230 ) {
231 if (kv.val != i)
232 continue;
233 cube = invcoord_h48(kv.key, crep, 11);
234 for (m = 0; m < 18; m++) {
235 d = move(cube, m);
236 _foreach_h48sim(d, cocsepdata, selfsim, 11,
237 coord = coord_h48(d, cocsepdata, 11);
238 h48map_insertmin(map, coord, i+1);
239 )
240 }
241 }
242 LOG("found %" PRIu8 "\n", map->n-oldn);
243 }
244
245 return map->n;
246}
247
248/*
249TODO description
250generating fixed table with h=0, k=4
251*/
252_static size_t
253gendata_h48h0k4(void *buf, uint8_t maxdepth)
254{
255 uint32_t j, *buf32, *info, *cocsepdata;
256 bfsarg_esep_t arg;
257 int64_t sc, cc, esep_max;
258 uint64_t selfsim[COCSEP_CLASSES];
259 cube_t crep[COCSEP_CLASSES];
260 size_t cocsepsize, infosize;
261
262 /* TODO: move info at start of tables (all tables!) */
263 infosize = 4 * maxdepth;
264 cocsepsize = gendata_cocsep(buf, selfsim, crep);
265 infosize = 88;
266
267 if (buf == NULL)
268 goto gendata_h48h0k4_return_size;
269
270 esep_max = (int64_t)ESEP_MAX(0);
271 cocsepdata = (uint32_t *)buf;
272 buf32 = cocsepdata + cocsepsize / 4;
273 info = buf32 + (ESEP_TABLESIZE(0, 4) / sizeof(uint32_t));
274 memset(buf32, 0xFF, ESEP_TABLESIZE(0, 4));
275
276 sc = coord_h48(solved, cocsepdata, 0);
277 set_esep_pval(buf32, sc, 0);
278 info[1] = 1;
279 arg = (bfsarg_esep_t) {
280 .cocsepdata = cocsepdata,
281 .buf32 = buf32,
282 .selfsim = selfsim,
283 .crep = crep
284 };
285 for (
286 arg.done = 1, arg.depth = 1, cc = 0;
287 arg.done < esep_max && arg.depth <= maxdepth;
288 arg.depth++
289 ) {
290 LOG("esep: generating depth %" PRIu8 "\n", arg.depth);
291 cc = gendata_h48h0k4_bfs(&arg);
292 arg.done += cc;
293 info[arg.depth+1] = cc;
294 LOG("found %" PRId64 "\n", cc);
295 }
296
297 info[0] = arg.depth-1;
298
299 LOG("h48 pruning table computed\n");
300 LOG("Maximum pruning value: %" PRIu32 "\n", info[0]);
301 LOG("Pruning value distribution:\n");
302 for (j = 0; j <= info[0]; j++)
303 LOG("%" PRIu8 ":\t%" PRIu32 "\n", j, info[j+1]);
304
305gendata_h48h0k4_return_size:
306 return cocsepsize + ESEP_TABLESIZE(0, 4) + infosize;
307}
308
309_static int64_t
310gendata_h48h0k4_bfs(bfsarg_esep_t *arg)
311{
312 const uint8_t breakpoint = 10; /* Hand-picked optimal */
313
314 if (arg->depth < breakpoint)
315 return gendata_h48h0k4_bfs_fromdone(arg);
316 else
317 return gendata_h48h0k4_bfs_fromnew(arg);
318}
319
320_static int64_t
321gendata_h48h0k4_bfs_fromdone(bfsarg_esep_t *arg)
322{
323 uint8_t c, m, x;
324 uint32_t cc;
325 int64_t i, j, k;
326 cube_t cube, moved;
327
328 for (i = 0, cc = 0; i < (int64_t)ESEP_MAX(0); i++) {
329 c = get_esep_pval(arg->buf32, i);
330 if (c != arg->depth - 1)
331 continue;
332 cube = invcoord_h48(i, arg->crep, 0);
333 for (m = 0; m < 18; m++) {
334 moved = move(cube, m);
335 j = coord_h48(moved, arg->cocsepdata, 0);
336 if (get_esep_pval(arg->buf32, j) <= arg->depth)
337 continue;
338 _foreach_h48sim(moved, arg->cocsepdata, arg->selfsim, 0,
339 k = coord_h48(moved, arg->cocsepdata, 0);
340 x = get_esep_pval(arg->buf32, k);
341 set_esep_pval(arg->buf32, k, arg->depth);
342 cc += x != arg->depth;
343 )
344 }
345 }
346
347 return cc;
348}
349
350_static int64_t
351gendata_h48h0k4_bfs_fromnew(bfsarg_esep_t *arg)
352{
353 uint8_t c, m, x;
354 uint32_t cc;
355 int64_t i, j;
356 cube_t cube, moved;
357
358 for (i = 0, cc = 0; i < (int64_t)ESEP_MAX(0); i++) {
359 c = get_esep_pval(arg->buf32, i);
360 if (c != 0xF)
361 continue;
362 cube = invcoord_h48(i, arg->crep, 0);
363 for (m = 0; m < 18; m++) {
364 moved = move(cube, m);
365 j = coord_h48(moved, arg->cocsepdata, 0);
366 x = get_esep_pval(arg->buf32, j);
367 if (x >= arg->depth)
368 continue;
369 _foreach_h48sim(cube, arg->cocsepdata, arg->selfsim, 0,
370 j = coord_h48(cube, arg->cocsepdata, 0);
371 x = get_esep_pval(arg->buf32, j);
372 set_esep_pval(arg->buf32, j, arg->depth);
373 cc += x == 0xF;
374 )
375 break; /* Enough to find one, skip the rest */
376 }
377 }
378
379 return cc;
380}
381
382_static_inline bool
383get_visited(const uint8_t *a, int64_t i)
384{
385 return a[VISITED_IND(i)] & VISITED_MASK(i);
386}
387
388_static_inline void
389set_visited(uint8_t *a, int64_t i)
390{
391 a[VISITED_IND(i)] |= VISITED_MASK(i);
392}
393
394_static_inline uint8_t
395get_esep_pval(const uint32_t *buf32, int64_t i)
396{
397 return (buf32[ESEP_IND(i)] & ESEP_MASK(i)) >> ESEP_SHIFT(i);
398}
399
400_static_inline void
401set_esep_pval(uint32_t *buf32, int64_t i, uint8_t val)
402{
403 buf32[ESEP_IND(i)] =
404 (buf32[ESEP_IND(i)] & (~ESEP_MASK(i))) | (val << ESEP_SHIFT(i));
405}
406
407_static_inline int8_t
408get_h48_cdata(cube_t cube, uint32_t *cocsepdata, uint32_t *cdata)
409{
410 int64_t coord;
411
412 coord = coord_cocsep(cube);
413 *cdata = cocsepdata[coord];
414
415 return CBOUND(*cdata);
416}
417
418_static_inline int8_t
419get_h48_bound(cube_t cube, uint32_t cdata, uint8_t h, uint32_t *h48data)
420{
421 int64_t coord;
422
423 coord = coord_h48_edges(cube, COCLASS(cdata), TTREP(cdata), h);
424 return get_esep_pval(h48data, coord);
425}
diff --git a/src/solvers/h48/h48.h b/src/solvers/h48/h48.h
new file mode 100644
index 0000000..d33ad63
--- /dev/null
+++ b/src/solvers/h48/h48.h
@@ -0,0 +1,4 @@
1#include "coordinate.h"
2#include "map.h"
3#include "gendata.h"
4#include "solve.h"
diff --git a/src/solvers/h48/map.h b/src/solvers/h48/map.h
new file mode 100644
index 0000000..82e5a2c
--- /dev/null
+++ b/src/solvers/h48/map.h
@@ -0,0 +1,104 @@
1#define MAP_UNSET UINT64_C(0xFFFFFFFFFFFFFFFF)
2#define MAP_KEYMASK UINT64_C(0xFFFFFFFFFF)
3#define MAP_KEYSHIFT UINT64_C(40)
4
5typedef struct {
6 uint64_t n;
7 uint64_t capacity;
8 uint64_t randomizer;
9 uint64_t *table;
10} h48map_t;
11
12typedef struct {
13 uint64_t key;
14 uint64_t val;
15} kvpair_t;
16
17_static void h48map_create(h48map_t *, uint64_t, uint64_t);
18_static void h48map_clear(h48map_t *);
19_static void h48map_destroy(h48map_t *);
20_static uint64_t h48map_lookup(h48map_t *, uint64_t);
21_static void h48map_insertmin(h48map_t *, uint64_t, uint64_t);
22_static uint64_t h48map_value(h48map_t *, uint64_t);
23_static kvpair_t h48map_nextkvpair(h48map_t *, uint64_t *);
24
25_static void
26h48map_create(h48map_t *map, uint64_t capacity, uint64_t randomizer)
27{
28 map->capacity = capacity;
29 map->randomizer = randomizer;
30
31 map->table = malloc(map->capacity * sizeof(int64_t));
32 h48map_clear(map);
33}
34
35_static void
36h48map_clear(h48map_t *map)
37{
38 memset(map->table, 0xFF, map->capacity * sizeof(uint64_t));
39 map->n = 0;
40}
41
42_static void
43h48map_destroy(h48map_t *map)
44{
45 free(map->table);
46}
47
48_static_inline uint64_t
49h48map_lookup(h48map_t *map, uint64_t x)
50{
51 uint64_t hash, i;
52
53 hash = ((x % map->capacity) * map->randomizer) % map->capacity;
54 for (i = hash;
55 map->table[i] != MAP_UNSET && (map->table[i] & MAP_KEYMASK) != x;
56 i = (i+1) % map->capacity
57 ) ;
58
59 return i;
60}
61
62_static_inline void
63h48map_insertmin(h48map_t *map, uint64_t key, uint64_t val)
64{
65 uint64_t i, oldval, min;
66
67 i = h48map_lookup(map, key);
68 oldval = map->table[i] >> MAP_KEYSHIFT;
69 min = _min(val, oldval);
70
71 map->n += map->table[i] == MAP_UNSET;
72 map->table[i] = (key & MAP_KEYMASK) | (min << MAP_KEYSHIFT);
73}
74
75_static_inline uint64_t
76h48map_value(h48map_t *map, uint64_t key)
77{
78 return map->table[h48map_lookup(map, key)] >> MAP_KEYSHIFT;
79}
80
81_static kvpair_t
82h48map_nextkvpair(h48map_t *map, uint64_t *p)
83{
84 kvpair_t kv;
85 uint64_t pair;
86
87 kv.key = MAP_UNSET;
88 kv.val = MAP_UNSET;
89
90 DBG_ASSERT(*p < map->capacity, kv,
91 "Error looping over map: given index %" PRIu64 " is out of "
92 "range [0,%" PRIu64 "]", *p, map->capacity);
93
94 for ( ; *p < map->capacity; (*p)++) {
95 if (map->table[*p] != MAP_UNSET) {
96 pair = map->table[(*p)++];
97 kv.key = pair & MAP_KEYMASK;
98 kv.val = pair >> MAP_KEYSHIFT;
99 return kv;
100 }
101 }
102
103 return kv;
104}
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h
new file mode 100644
index 0000000..8531a40
--- /dev/null
+++ b/src/solvers/h48/solve.h
@@ -0,0 +1,242 @@
1typedef struct {
2 cube_t cube;
3 cube_t inverse;
4 int8_t nmoves;
5 int8_t depth;
6 uint8_t moves[MAXLEN];
7 int64_t *nsols;
8 int64_t maxsolutions;
9 uint8_t h;
10 uint32_t *cocsepdata;
11 uint32_t *h48data;
12 char **nextsol;
13} dfsarg_solveh48_t;
14
15typedef struct {
16 cube_t cube;
17 int8_t nmoves;
18 int8_t depth;
19 uint8_t moves[MAXLEN];
20 uint32_t *cocsepdata;
21 uint32_t *h48data;
22 char *s;
23} dfsarg_solveh48stats_t;
24
25_static void solve_h48_appendsolution(dfsarg_solveh48_t *);
26_static_inline bool solve_h48_stop(dfsarg_solveh48_t *);
27_static int64_t solve_h48_dfs(dfsarg_solveh48_t *);
28_static int64_t solve_h48(
29 cube_t, int8_t, int8_t, int8_t, uint8_t, const void *, char *);
30
31_static int64_t solve_h48stats_dfs(dfsarg_solveh48stats_t *);
32_static int64_t solve_h48stats(cube_t, int8_t, const void *, char [static 12]);
33
34_static void
35solve_h48_appendsolution(dfsarg_solveh48_t *arg)
36{
37 int strl;
38
39 strl = writemoves(arg->moves, arg->nmoves, *arg->nextsol);
40 LOG("Solution found: %s\n", *arg->nextsol);
41 *arg->nextsol += strl;
42 **arg->nextsol = '\n';
43 (*arg->nextsol)++;
44 (*arg->nsols)++;
45}
46
47_static_inline bool
48solve_h48_stop(dfsarg_solveh48_t *arg)
49{
50 uint32_t data, data_inv;
51 int8_t bound;
52
53 bound = get_h48_cdata(arg->cube, arg->cocsepdata, &data);
54 if (bound + arg->nmoves > arg->depth)
55 return true;
56
57 bound = get_h48_cdata(arg->inverse, arg->cocsepdata, &data_inv);
58 if (bound + arg->nmoves > arg->depth)
59 return true;
60
61/*
62 bound = get_h48_bound(arg->cube, data, arg->h, arg->h48data);
63LOG("Using pval %" PRId8 "\n", bound);
64 if (bound + arg->nmoves > arg->depth)
65 return true;
66
67 bound = get_h48_bound(arg->inverse, data_inv, arg->h, arg->h48data);
68 if (bound + arg->nmoves > arg->depth)
69 return true;
70*/
71
72 return false;
73}
74
75_static int64_t
76solve_h48_dfs(dfsarg_solveh48_t *arg)
77{
78 dfsarg_solveh48_t nextarg;
79 int64_t ret;
80 uint8_t m;
81
82 if (*arg->nsols == arg->maxsolutions)
83 return 0;
84
85 if (solve_h48_stop(arg))
86 return 0;
87
88 if (issolved(arg->cube)) {
89 if (arg->nmoves != arg->depth)
90 return 0;
91 solve_h48_appendsolution(arg);
92 return 1;
93 }
94
95 /* TODO: avoid copy, change arg and undo changes after recursion */
96 nextarg = *arg;
97 nextarg.nmoves = arg->nmoves + 1;
98 ret = 0;
99 for (m = 0; m < 18; m++) {
100 nextarg.moves[arg->nmoves] = m;
101 if (!allowednextmove(nextarg.moves, nextarg.nmoves)) {
102 /* If a move is not allowed, neither are its 180
103 * and 270 degree variations */
104 m += 2;
105 continue;
106 }
107 nextarg.cube = move(arg->cube, m);
108 nextarg.inverse = inverse(nextarg.cube); /* TODO: use premove */
109 ret += solve_h48_dfs(&nextarg);
110 }
111
112 return ret;
113}
114
115_static int64_t
116solve_h48(
117 cube_t cube,
118 int8_t minmoves,
119 int8_t maxmoves,
120 int8_t maxsolutions,
121 uint8_t h,
122 const void *data,
123 char *solutions
124)
125{
126 int64_t nsols;
127 dfsarg_solveh48_t arg;
128
129 arg = (dfsarg_solveh48_t) {
130 .cube = cube,
131 .inverse = inverse(cube),
132 .nsols = &nsols,
133 .maxsolutions = maxsolutions,
134 .h = h,
135 .cocsepdata = (uint32_t *)data,
136 .h48data = ((uint32_t *)data) + COCSEP_FULLSIZE / 4,
137 .nextsol = &solutions
138 };
139
140 nsols = 0;
141 for (arg.depth = minmoves;
142 arg.depth <= maxmoves && nsols < maxsolutions;
143 arg.depth++)
144 {
145 LOG("Found %" PRId64 " solutions, searching at depth %"
146 PRId8 "\n", nsols, arg.depth);
147 arg.nmoves = 0;
148 solve_h48_dfs(&arg);
149 }
150
151 return nsols;
152}
153
154/*
155The h48stats solver computes how many moves it takes to solve to
156each of the 12 h48 coordinates, one for each value of h from 0 to 11.
157The solutions array is filled with the length of the solutions. The
158solution array is therefore not a printable string.
159*/
160_static int64_t
161solve_h48stats_dfs(dfsarg_solveh48stats_t *arg)
162{
163 const int64_t limit = 11;
164
165 int8_t bound, u;
166 uint8_t m;
167 uint32_t d;
168 int64_t coord, h;
169 dfsarg_solveh48stats_t nextarg;
170
171 /* Check cocsep lower bound (corners only) */
172 bound = get_h48_cdata(arg->cube, arg->cocsepdata, &d);
173 if (bound + arg->nmoves > arg->depth)
174 return 0;
175
176 /* Check h48 lower bound for h=0 (esep, but no eo) */
177 coord = coord_h48_edges(arg->cube, COCLASS(d), TTREP(d), 0);
178 bound = get_esep_pval(arg->h48data, coord);
179 if (bound + arg->nmoves > arg->depth)
180 return 0;
181
182 /* Update all other values, if solved */
183 coord = coord_h48_edges(arg->cube, COCLASS(d), TTREP(d), 11);
184 for (h = 0; h <= limit; h++) {
185 u = coord >> (11-h) == 0 && arg->s[h] == 99;
186 arg->s[h] = u * arg->nmoves + (1-u) * arg->s[h];
187 }
188
189 if (arg->s[limit] != 99)
190 return 0;
191
192 nextarg = *arg;
193 nextarg.nmoves = arg->nmoves + 1;
194 for (m = 0; m < 18; m++) {
195 nextarg.moves[arg->nmoves] = m;
196 if (!allowednextmove(nextarg.moves, nextarg.nmoves)) {
197 /* If a move is not allowed, neither are its 180
198 * and 270 degree variations */
199 m += 2;
200 continue;
201 }
202 nextarg.cube = move(arg->cube, m);
203 solve_h48stats_dfs(&nextarg);
204 }
205
206 return 0;
207}
208
209_static int64_t
210solve_h48stats(
211 cube_t cube,
212 int8_t maxmoves,
213 const void *data,
214 char solutions[static 12]
215)
216{
217 int i;
218 size_t cocsepsize;
219 dfsarg_solveh48stats_t arg;
220
221 cocsepsize = gendata_cocsep(NULL, NULL, NULL);
222
223 arg = (dfsarg_solveh48stats_t) {
224 .cube = cube,
225 .cocsepdata = (uint32_t *)data,
226 .h48data = ((uint32_t *)data) + (cocsepsize/4),
227 .s = solutions
228 };
229
230 for (i = 0; i < 12; i++)
231 solutions[i] = (char)99;
232
233 for (arg.depth = 0;
234 arg.depth <= maxmoves && solutions[11] == 99;
235 arg.depth++)
236 {
237 arg.nmoves = 0;
238 solve_h48stats_dfs(&arg);
239 }
240
241 return 0;
242}

Generated with cgit - Back to sebastiano.tronto.net