aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2023-11-12 14:42:20 +0100
committerSebastiano Tronto <sebastiano@tronto.net>2023-11-12 14:42:20 +0100
commitd0c592bdc3beb12074f085ab085dd90de9b8e643 (patch)
treea7b31fc66c83400c95288edd7550d6b27cccecaa
parent91afd406dca8dee4dfdb84ad025dd390f4e5a70c (diff)
downloadnissy-core-d0c592bdc3beb12074f085ab085dd90de9b8e643.tar.gz
nissy-core-d0c592bdc3beb12074f085ab085dd90de9b8e643.zip
Simple solver: added tests, fixed
-rw-r--r--TODO.txt11
-rw-r--r--cube.c111
-rw-r--r--cube.h5
-rw-r--r--test/060_solve_simple/01_U_U3.in8
-rw-r--r--test/060_solve_simple/01_U_U3.out1
-rw-r--r--test/060_solve_simple/02_MUMU_alloptimal.in8
-rw-r--r--test/060_solve_simple/02_MUMU_alloptimal.out4
-rw-r--r--test/060_solve_simple/solve_simple_tests.c58
8 files changed, 171 insertions, 35 deletions
diff --git a/TODO.txt b/TODO.txt
index f661363..c188558 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -2,12 +2,14 @@
2 2
3See the sections below for details 3See the sections below for details
4 4
5* Tests for simple solver 5* Tests for multisolve
6* Extend cube and moves to include centers 6* More tests for simple solver?
7* Benchmarks?
7* More complex optimal solvers, pruning tables 8* More complex optimal solvers, pruning tables
8* Benchmarks 9* (More) benchmarks
9* Multithreading (build-time option number of threads) 10* Multithreading (build-time option number of threads)
10* Other optimizations 11* Other optimizations
12* Extend cube and moves to include centers
11* NISS 13* NISS
12* Move manipulation utilities 14* Move manipulation utilities
13* Coordinate solvers and other steps 15* Coordinate solvers and other steps
@@ -76,6 +78,8 @@ What about symcoord?
76 78
77### General things 79### General things
78 80
81* Moves: don't do full compose for U*, D*, *2 (I removed this because I
82 was using shuffle intructions wrong, should re-do it)
79* Trans: don't do full compose, for some trans composing perm is enough. 83* Trans: don't do full compose, for some trans composing perm is enough.
80 Split out sumco() as a separate function and refactor, optimize. 84 Split out sumco() as a separate function and refactor, optimize.
81* Use multi-move (up to 4/5 moves at once) 85* Use multi-move (up to 4/5 moves at once)
@@ -113,6 +117,7 @@ What about symcoord?
113* print ptables (or layout data in such a way that can be printed 117* print ptables (or layout data in such a way that can be printed
114 easily, e.g. first bytes are null-terminated strig and can be 118 easily, e.g. first bytes are null-terminated strig and can be
115 printed by user) 119 printed by user)
120* remove writetrans?
116 121
117## "Front-end" 122## "Front-end"
118 123
diff --git a/cube.c b/cube.c
index 3cd4381..0d32627 100644
--- a/cube.c
+++ b/cube.c
@@ -277,7 +277,7 @@ _move_U(cube_fast_t c)
277 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 1, 0, 3, 2, 4, 5 277 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 1, 0, 3, 2, 4, 5
278 ); 278 );
279 279
280 return _mm256_shuffle_epi8(c, m); 280 return compose_fast(c, m);
281} 281}
282 282
283static inline cube_fast_t 283static inline cube_fast_t
@@ -288,7 +288,7 @@ _move_U2(cube_fast_t c)
288 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 4, 5, 3, 2, 0, 1 288 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 4, 5, 3, 2, 0, 1
289 ); 289 );
290 290
291 return _mm256_shuffle_epi8(c, m); 291 return compose_fast(c, m);
292} 292}
293 293
294static inline cube_fast_t 294static inline cube_fast_t
@@ -299,7 +299,7 @@ _move_U3(cube_fast_t c)
299 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 0, 1, 3, 2, 5, 4 299 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 0, 1, 3, 2, 5, 4
300 ); 300 );
301 301
302 return _mm256_shuffle_epi8(c, m); 302 return compose_fast(c, m);
303} 303}
304 304
305static inline cube_fast_t 305static inline cube_fast_t
@@ -310,7 +310,7 @@ _move_D(cube_fast_t c)
310 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 5, 4, 6, 7, 1, 0 310 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 5, 4, 6, 7, 1, 0
311 ); 311 );
312 312
313 return _mm256_shuffle_epi8(c, m); 313 return compose_fast(c, m);
314} 314}
315 315
316static inline cube_fast_t 316static inline cube_fast_t
@@ -321,7 +321,7 @@ _move_D2(cube_fast_t c)
321 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 5, 4, 2, 3, 1, 0 321 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 5, 4, 2, 3, 1, 0
322 ); 322 );
323 323
324 return _mm256_shuffle_epi8(c, m); 324 return compose_fast(c, m);
325} 325}
326 326
327static inline cube_fast_t 327static inline cube_fast_t
@@ -332,7 +332,7 @@ _move_D3(cube_fast_t c)
332 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 4, 7, 6, 1, 0 332 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 4, 7, 6, 1, 0
333 ); 333 );
334 334
335 return _mm256_shuffle_epi8(c, m); 335 return compose_fast(c, m);
336} 336}
337 337
338static inline cube_fast_t 338static inline cube_fast_t
@@ -354,7 +354,7 @@ _move_R2(cube_fast_t c)
354 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 6, 4, 0, 2, 1, 3 354 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 6, 4, 0, 2, 1, 3
355 ); 355 );
356 356
357 return _mm256_shuffle_epi8(c, m); 357 return compose_fast(c, m);
358} 358}
359 359
360static inline cube_fast_t 360static inline cube_fast_t
@@ -387,7 +387,7 @@ _move_L2(cube_fast_t c)
387 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 5, 7, 3, 1, 2, 0 387 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 5, 7, 3, 1, 2, 0
388 ); 388 );
389 389
390 return _mm256_shuffle_epi8(c, m); 390 return compose_fast(c, m);
391} 391}
392 392
393static inline cube_fast_t 393static inline cube_fast_t
@@ -420,7 +420,7 @@ _move_F2(cube_fast_t c)
420 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 5, 6, 3, 0, 1, 2 420 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 5, 6, 3, 0, 1, 2
421 ); 421 );
422 422
423 return _mm256_shuffle_epi8(c, m); 423 return compose_fast(c, m);
424} 424}
425 425
426static inline cube_fast_t 426static inline cube_fast_t
@@ -453,7 +453,7 @@ _move_B2(cube_fast_t c)
453 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 4, 1, 2, 3, 0 453 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 4, 1, 2, 3, 0
454 ); 454 );
455 455
456 return _mm256_shuffle_epi8(c, m); 456 return compose_fast(c, m);
457} 457}
458 458
459static inline cube_fast_t 459static inline cube_fast_t
@@ -1479,13 +1479,13 @@ fasttocube(cube_fast_t c)
1479static inline bool 1479static inline bool
1480equal_fast(cube_fast_t c1, cube_fast_t c2) 1480equal_fast(cube_fast_t c1, cube_fast_t c2)
1481{ 1481{
1482 uint32_t mask; 1482 int32_t mask;
1483 __m256i cmp; 1483 __m256i cmp;
1484 1484
1485 cmp = _mm256_cmpeq_epi8(c1, c2); 1485 cmp = _mm256_cmpeq_epi8(c1, c2);
1486 mask = _mm256_movemask_epi8(cmp); 1486 mask = _mm256_movemask_epi8(cmp);
1487 1487
1488 return mask == 0xffffffffU; 1488 return mask == ~0;
1489} 1489}
1490 1490
1491static inline bool 1491static inline bool
@@ -1511,6 +1511,19 @@ invertco_fast(cube_fast_t c)
1511} 1511}
1512 1512
1513static inline cube_fast_t 1513static inline cube_fast_t
1514cleanaftershuffle(cube_fast_t c)
1515{
1516 __m256i b;
1517
1518 b = _mm256_set_epi8(
1519 ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1520 ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0
1521 );
1522
1523 return _mm256_andnot_si256(b, c);
1524}
1525
1526static inline cube_fast_t
1514inverse_fast(cube_fast_t c) 1527inverse_fast(cube_fast_t c)
1515{ 1528{
1516 /* Method taken from Andrew Skalski's vcube[1]. The addition sequence 1529 /* Method taken from Andrew Skalski's vcube[1]. The addition sequence
@@ -1544,6 +1557,7 @@ inverse_fast(cube_fast_t c)
1544 vo = _mm256_shuffle_epi8(vo, vi); 1557 vo = _mm256_shuffle_epi8(vo, vi);
1545 vp = _mm256_andnot_si256(_mm256_or_si256(_eo_avx2, _co2_avx2), vi); 1558 vp = _mm256_andnot_si256(_mm256_or_si256(_eo_avx2, _co2_avx2), vi);
1546 ret = _mm256_or_si256(vp, vo); 1559 ret = _mm256_or_si256(vp, vo);
1560 ret = cleanaftershuffle(ret);
1547 1561
1548 return invertco_fast(ret); 1562 return invertco_fast(ret);
1549} 1563}
@@ -1557,6 +1571,7 @@ compose_fast(cube_fast_t c1, cube_fast_t c2)
1557 1571
1558 eo2 = _mm256_and_si256(c2, _eo_avx2); 1572 eo2 = _mm256_and_si256(c2, _eo_avx2);
1559 s = _mm256_shuffle_epi8(c1, c2); 1573 s = _mm256_shuffle_epi8(c1, c2);
1574 s = cleanaftershuffle(s);
1560 ed = _mm256_xor_si256(s, eo2); 1575 ed = _mm256_xor_si256(s, eo2);
1561 co1 = _mm256_and_si256(s, _co2_avx2); 1576 co1 = _mm256_and_si256(s, _co2_avx2);
1562 co2 = _mm256_and_si256(c2, _co2_avx2); 1577 co2 = _mm256_and_si256(c2, _co2_avx2);
@@ -2939,6 +2954,8 @@ Some of these routines depend on the efficient functions implemented in the
2939previous sections, while some other operate directly on the cube. 2954previous sections, while some other operate directly on the cube.
2940******************************************************************************/ 2955******************************************************************************/
2941 2956
2957static inline uint8_t movebase(uint8_t);
2958static inline uint8_t moveaxis(uint8_t);
2942static uint8_t readco(char *); 2959static uint8_t readco(char *);
2943static uint8_t readcp(char *); 2960static uint8_t readcp(char *);
2944static uint8_t readeo(char *); 2961static uint8_t readeo(char *);
@@ -2990,6 +3007,18 @@ iserror(cube_t cube)
2990 return equal(cube, zero); 3007 return equal(cube, zero);
2991} 3008}
2992 3009
3010static inline uint8_t
3011movebase(uint8_t move)
3012{
3013 return move / 3;
3014}
3015
3016static inline uint8_t
3017moveaxis(uint8_t move)
3018{
3019 return move / 6;
3020}
3021
2993static uint8_t 3022static uint8_t
2994readco(char *str) 3023readco(char *str)
2995{ 3024{
@@ -3292,6 +3321,9 @@ writemoves(uint8_t *m, int n, char *buf)
3292 b += len; 3321 b += len;
3293 *b = ' '; 3322 *b = ' ';
3294 } 3323 }
3324
3325 if (b != buf)
3326 b--; /* Remove last space */
3295 *b = '\0'; 3327 *b = '\0';
3296 3328
3297 return b - buf; 3329 return b - buf;
@@ -3653,8 +3685,8 @@ typedef struct {
3653 cube_fast_t cube; 3685 cube_fast_t cube;
3654 uint8_t depth; 3686 uint8_t depth;
3655 int64_t maxsols; 3687 int64_t maxsols;
3656 char *sols; 3688 char **nextsol;
3657 int64_t nsols; 3689 int64_t *nsols;
3658 uint8_t nmoves; 3690 uint8_t nmoves;
3659 uint8_t moves[20]; 3691 uint8_t moves[20];
3660 uint8_t (*estimate)(cube_fast_t); 3692 uint8_t (*estimate)(cube_fast_t);
@@ -3671,10 +3703,10 @@ allowednextmove(dfsarg_generic_t arg, uint8_t m)
3671 if (n == 0) 3703 if (n == 0)
3672 return true; 3704 return true;
3673 3705
3674 mbase = m / 3; 3706 mbase = movebase(m);
3675 maxis = mbase / 2; 3707 maxis = moveaxis(m);
3676 l1base = arg.moves[n-1] / 3; 3708 l1base = movebase(arg.moves[n-1]);
3677 l1axis = l1base / 2; 3709 l1axis = moveaxis(arg.moves[n-1]);
3678 3710
3679 if (mbase == l1base || (maxis == l1axis && mbase < l1base)) 3711 if (mbase == l1base || (maxis == l1axis && mbase < l1base))
3680 return false; 3712 return false;
@@ -3682,12 +3714,25 @@ allowednextmove(dfsarg_generic_t arg, uint8_t m)
3682 if (n == 1) 3714 if (n == 1)
3683 return true; 3715 return true;
3684 3716
3685 l2base = arg.moves[n-2] / 3; 3717 l2base = movebase(arg.moves[n-2]);
3686 l2axis = l1base / 2; 3718 l2axis = moveaxis(arg.moves[n-2]);
3687 3719
3688 return l1axis != l2axis || mbase != l2base; 3720 return l1axis != l2axis || mbase != l2base;
3689} 3721}
3690 3722
3723static void
3724solve_generic_appendsolution(dfsarg_generic_t arg)
3725{
3726 int strl;
3727
3728 strl = writemoves(arg.moves, arg.depth, *arg.nextsol);
3729 DBG_LOG("Solution found: %s\n", *arg.nextsol);
3730 *arg.nextsol += strl;
3731 **arg.nextsol = '\n';
3732 (*arg.nextsol)++;
3733 (*arg.nsols)++;
3734}
3735
3691static int 3736static int
3692solve_generic_dfs(dfsarg_generic_t arg) 3737solve_generic_dfs(dfsarg_generic_t arg)
3693{ 3738{
@@ -3697,15 +3742,13 @@ solve_generic_dfs(dfsarg_generic_t arg)
3697 3742
3698 bound = arg.estimate(arg.cube); 3743 bound = arg.estimate(arg.cube);
3699 3744
3700 if (arg.nsols == arg.maxsols || bound + arg.nmoves > arg.depth) 3745 if (*arg.nsols == arg.maxsols || bound + arg.nmoves > arg.depth)
3701 return 0; 3746 return 0;
3702 3747
3703 if (bound == 0) { 3748 if (bound == 0) {
3704 if (arg.nmoves != arg.depth) 3749 if (arg.nmoves != arg.depth)
3705 return 0; 3750 return 0;
3706 arg.sols += writemoves(arg.moves, arg.depth, arg.sols); 3751 solve_generic_appendsolution(arg);
3707 *arg.sols = '\n';
3708 arg.sols++;
3709 return 1; 3752 return 1;
3710 } 3753 }
3711 3754
@@ -3746,6 +3789,13 @@ solve_generic(
3746 return -1; 3789 return -1;
3747 } 3790 }
3748 3791
3792 if (issolved(cube)) {
3793 DBG_LOG("solve: cube is already solved\n");
3794 sols[0] = '\n';
3795 sols[1] = 0;
3796 return 1;
3797 }
3798
3749 DBG_WARN(!strcmp(nisstype, ""), 3799 DBG_WARN(!strcmp(nisstype, ""),
3750 "solve: NISS not implemented yet, 'nisstype' ignored\n"); 3800 "solve: NISS not implemented yet, 'nisstype' ignored\n");
3751 3801
@@ -3782,8 +3832,8 @@ solve_generic(
3782 arg = (dfsarg_generic_t) { 3832 arg = (dfsarg_generic_t) {
3783 .cube = cubetofast(cube), 3833 .cube = cubetofast(cube),
3784 .maxsols = maxsols, 3834 .maxsols = maxsols,
3785 .sols = sols, 3835 .nextsol = &sols,
3786 .nsols = 0, 3836 .nsols = &ret,
3787 .nmoves = 0, 3837 .nmoves = 0,
3788 .moves = {0}, 3838 .moves = {0},
3789 .estimate = estimate, 3839 .estimate = estimate,
@@ -3793,12 +3843,11 @@ solve_generic(
3793 first = -1; 3843 first = -1;
3794 for (arg.depth = minmoves; arg.depth <= maxmoves; arg.depth++) { 3844 for (arg.depth = minmoves; arg.depth <= maxmoves; arg.depth++) {
3795 tmp = solve_generic_dfs(arg); 3845 tmp = solve_generic_dfs(arg);
3796 ret += tmp;
3797 if (tmp != 0) 3846 if (tmp != 0)
3798 first = arg.depth; 3847 first = arg.depth;
3799 3848
3800 DBG_LOG("Found %" PRId64 " solutions at depth %" PRIu8 "\n", 3849 DBG_LOG("Found %" PRId64 " solution%s at depth %" PRIu8 "\n",
3801 tmp, arg.depth); 3850 tmp, tmp == 1 ? "" : "s", arg.depth);
3802 3851
3803 if (ret >= maxsols) 3852 if (ret >= maxsols)
3804 break; 3853 break;
@@ -3864,7 +3913,7 @@ solve(
3864 DBG_WARN(data == NULL, 3913 DBG_WARN(data == NULL,
3865 "solve: 'data' not implemented yet, ignoring\n"); 3914 "solve: 'data' not implemented yet, ignoring\n");
3866 3915
3867 if (!strcmp(solver, "simple")) { 3916 if (!strcmp(solver, "optimal") || !strcmp(solver, "simple")) {
3868 return solve_simple( 3917 return solve_simple(
3869 cube, 3918 cube,
3870 minmoves, 3919 minmoves,
@@ -3874,7 +3923,7 @@ solve(
3874 solutions 3923 solutions
3875 ); 3924 );
3876 } else { 3925 } else {
3877 DBG_LOG("solve: unknown solver\n"); 3926 DBG_LOG("solve: unknown solver '%s'\n", solver);
3878 return -1; 3927 return -1;
3879 } 3928 }
3880 3929
diff --git a/cube.h b/cube.h
index 0a39d12..3f2495d 100644
--- a/cube.h
+++ b/cube.h
@@ -120,7 +120,10 @@ could.
120 120
121int64_t solve( 121int64_t solve(
122 cube_t cube, /* The cube to solve. Must be solvable. */ 122 cube_t cube, /* The cube to solve. Must be solvable. */
123 char *solver, /* The solver. Supported solvers: TODO. */ 123 char *solver, /* Supported solvers:
124 * "optimal" - currently the same as "simple"
125 * "simple" - a simple, slow solver using no tables
126 */
124 char *options, /* Some solvers accept extra options, 127 char *options, /* Some solvers accept extra options,
125 * like "!filter". 128 * like "!filter".
126 */ 129 */
diff --git a/test/060_solve_simple/01_U_U3.in b/test/060_solve_simple/01_U_U3.in
new file mode 100644
index 0000000..c0f7930
--- /dev/null
+++ b/test/060_solve_simple/01_U_U3.in
@@ -0,0 +1,8 @@
1UR0 UL0 DB0 DF0 UB0 UF0 DL0 DR0 FR0 FL0 BL0 BR0 UBR0 UFL0 DFL0 DBR0 UFR0 UBL0 DFR0 DBL0
2simple
3
4normal
50
63
73
8-1
diff --git a/test/060_solve_simple/01_U_U3.out b/test/060_solve_simple/01_U_U3.out
new file mode 100644
index 0000000..ca934b4
--- /dev/null
+++ b/test/060_solve_simple/01_U_U3.out
@@ -0,0 +1 @@
U'
diff --git a/test/060_solve_simple/02_MUMU_alloptimal.in b/test/060_solve_simple/02_MUMU_alloptimal.in
new file mode 100644
index 0000000..f97c95f
--- /dev/null
+++ b/test/060_solve_simple/02_MUMU_alloptimal.in
@@ -0,0 +1,8 @@
1UB0 DF0 DB0 UF0 UR0 UL0 DL0 DR0 FR0 FL0 BL0 BR0 UFR0 UBL0 DFL0 DBR0 UFL0 UBR0 DFR0 DBL0
2simple
3
4normal
50
6-1
710
80
diff --git a/test/060_solve_simple/02_MUMU_alloptimal.out b/test/060_solve_simple/02_MUMU_alloptimal.out
new file mode 100644
index 0000000..06cd521
--- /dev/null
+++ b/test/060_solve_simple/02_MUMU_alloptimal.out
@@ -0,0 +1,4 @@
1U2 R' L F2 R L'
2R U2 R' L F2 L'
3R L' U2 R' L F2
4L' U2 R' L F2 R
diff --git a/test/060_solve_simple/solve_simple_tests.c b/test/060_solve_simple/solve_simple_tests.c
new file mode 100644
index 0000000..14a1674
--- /dev/null
+++ b/test/060_solve_simple/solve_simple_tests.c
@@ -0,0 +1,58 @@
1#include <stdbool.h>
2#include <stdint.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#ifdef CUBE_AVX2
8#include <immintrin.h>
9#endif
10
11#include "../../cube.h"
12
13#define S 10000
14
15int main() {
16 char cubestr[S], solverstr[S], optionsstr[S], nisstypestr[S];
17 char minmovesstr[S], maxmovesstr[S], maxsolsstr[S], optimalstr[S];
18 char solutionsstr[S];
19 cube_t cube;
20 int64_t maxsols;
21 int8_t minmoves, maxmoves, optimal;
22
23 fgets(cubestr, S, stdin);
24 fgets(solverstr, S, stdin);
25 fgets(optionsstr, S, stdin);
26 fgets(nisstypestr, S, stdin);
27 fgets(minmovesstr, S, stdin);
28 fgets(maxmovesstr, S, stdin);
29 fgets(maxsolsstr, S, stdin);
30 fgets(optimalstr, S, stdin);
31
32 solverstr[strcspn(solverstr, "\n")] = 0;
33 optionsstr[strcspn(optionsstr, "\n")] = 0;
34 nisstypestr[strcspn(nisstypestr, "\n")] = 0;
35
36 cube = readcube("H48", cubestr);
37 minmoves = atoi(minmovesstr);
38 maxmoves = atoi(maxmovesstr);
39 maxsols = atoi(maxsolsstr);
40 optimal = atoi(optimalstr);
41
42 solve(
43 cube,
44 solverstr,
45 optionsstr,
46 nisstypestr,
47 minmoves,
48 maxmoves,
49 maxsols,
50 optimal,
51 NULL,
52 solutionsstr
53 );
54
55 printf("%s", solutionsstr);
56
57 return 0;
58}

Generated with cgit - Back to sebastiano.tronto.net