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 '')
-rw-r--r--src/solvers/h48/gendata.h (renamed from src/solve_h48.h)426
1 files changed, 6 insertions, 420 deletions
diff --git a/src/solve_h48.h b/src/solvers/h48/gendata.h
index 1701268..d6bf85b 100644
--- a/src/solve_h48.h
+++ b/src/solvers/h48/gendata.h
@@ -1,7 +1,3 @@
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) 1#define COCSEP_CLASSES ((size_t)3393)
6#define COCSEP_TABLESIZE ((size_t)_3p7 << (size_t)7) 2#define COCSEP_TABLESIZE ((size_t)_3p7 << (size_t)7)
7#define COCSEP_VISITEDSIZE ((COCSEP_TABLESIZE + (size_t)7) / (size_t)8) 3#define COCSEP_VISITEDSIZE ((COCSEP_TABLESIZE + (size_t)7) / (size_t)8)
@@ -11,24 +7,19 @@
11#define ESEP_MAX(h) (ESEP_NOEO << (size_t)(h)) 7#define ESEP_MAX(h) (ESEP_NOEO << (size_t)(h))
12#define ESEP_TABLESIZE(h, k) (ESEP_MAX((h)) / ((size_t)8 / (size_t)(k))) 8#define ESEP_TABLESIZE(h, k) (ESEP_MAX((h)) / ((size_t)8 / (size_t)(k)))
13 9
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)) 10#define ESEP_IND(i) ((uint32_t)(i) / UINT32_C(8))
23#define ESEP_SHIFT(i) (UINT32_C(4) * ((uint32_t)(i) % UINT32_C(8))) 11#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)) 12#define ESEP_MASK(i) ((_bit_u32(4) - (uint32_t)(1)) << ESEP_SHIFT(i))
25#define VISITED_IND(i) ((uint32_t)(i) / UINT32_C(8)) 13#define VISITED_IND(i) ((uint32_t)(i) / UINT32_C(8))
26#define VISITED_MASK(i) (UINT32_C(1) << ((uint32_t)(i) % UINT32_C(8))) 14#define VISITED_MASK(i) (UINT32_C(1) << ((uint32_t)(i) % UINT32_C(8)))
27 15
28#define MAX_SOLUTION_LENGTH 20 16#define CBOUND_MASK UINT32_C(0xFF)
17#define CBOUND(x) ((x) & CBOUND_MASK)
18
19#define MAXLEN 20
29 20
30/* 21/*
31TODO: This loop other similar h48 coordinates can be improved by only 22TODO: This loop over similar h48 coordinates can be improved by only
32transforming edges, but we need to compose transformations (i.e. conjugate 23transforming edges, but we need to compose transformations (i.e. conjugate
33_t by _ttrep). 24_t by _ttrep).
34*/ 25*/
@@ -47,18 +38,6 @@ _t by _ttrep).
47 } 38 }
48 39
49typedef struct { 40typedef 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; 41 cube_t cube;
63 uint8_t depth; 42 uint8_t depth;
64 uint8_t maxdepth; 43 uint8_t maxdepth;
@@ -74,7 +53,7 @@ typedef struct {
74 cube_t cube; 53 cube_t cube;
75 int8_t nmoves; 54 int8_t nmoves;
76 int8_t depth; 55 int8_t depth;
77 uint8_t moves[MAX_SOLUTION_LENGTH]; 56 uint8_t moves[MAXLEN];
78 uint32_t *cocsepdata; 57 uint32_t *cocsepdata;
79 h48map_t *visited; 58 h48map_t *visited;
80} dfsarg_genh48set_t; 59} dfsarg_genh48set_t;
@@ -88,42 +67,6 @@ typedef struct {
88 cube_t *crep; 67 cube_t *crep;
89} bfsarg_esep_t; 68} bfsarg_esep_t;
90 69
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); 70_static_inline bool get_visited(const uint8_t *, int64_t);
128_static_inline void set_visited(uint8_t *, int64_t); 71_static_inline void set_visited(uint8_t *, int64_t);
129_static_inline uint8_t get_esep_pval(const uint32_t *, int64_t); 72_static_inline uint8_t get_esep_pval(const uint32_t *, int64_t);
@@ -138,155 +81,8 @@ _static int64_t gendata_h48h0k4_bfs(bfsarg_esep_t *);
138_static int64_t gendata_h48h0k4_bfs_fromdone(bfsarg_esep_t *); 81_static int64_t gendata_h48h0k4_bfs_fromdone(bfsarg_esep_t *);
139_static int64_t gendata_h48h0k4_bfs_fromnew(bfsarg_esep_t *); 82_static int64_t gendata_h48h0k4_bfs_fromnew(bfsarg_esep_t *);
140 83
141_static void solve_h48_appendsolution(dfsarg_solveh48_t *);
142_static_inline int8_t get_h48_cdata(cube_t, uint32_t *, uint32_t *); 84_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 *); 85_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 86
291/* 87/*
292Each element of the cocsep table is a uint32_t used as follows: 88Each element of the cocsep table is a uint32_t used as follows:
@@ -608,19 +404,6 @@ set_esep_pval(uint32_t *buf32, int64_t i, uint8_t val)
608 (buf32[ESEP_IND(i)] & (~ESEP_MASK(i))) | (val << ESEP_SHIFT(i)); 404 (buf32[ESEP_IND(i)] & (~ESEP_MASK(i))) | (val << ESEP_SHIFT(i));
609} 405}
610 406
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 407_static_inline int8_t
625get_h48_cdata(cube_t cube, uint32_t *cocsepdata, uint32_t *cdata) 408get_h48_cdata(cube_t cube, uint32_t *cocsepdata, uint32_t *cdata)
626{ 409{
@@ -640,200 +423,3 @@ get_h48_bound(cube_t cube, uint32_t cdata, uint8_t h, uint32_t *h48data)
640 coord = coord_h48_edges(cube, COCLASS(cdata), TTREP(cdata), h); 423 coord = coord_h48_edges(cube, COCLASS(cdata), TTREP(cdata), h);
641 return get_esep_pval(h48data, coord); 424 return get_esep_pval(h48data, coord);
642} 425}
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