aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2023-11-08 16:18:14 +0100
committerSebastiano Tronto <sebastiano@tronto.net>2023-11-08 16:18:14 +0100
commite082001f7c7c8ce0d20aebad4e6d6f22d3bf854c (patch)
tree7a8b9875d067feb6c96f39be4080397f8f1eef2d
parent72c9082c9824c7ffecc97a94083aa350956285e4 (diff)
downloadnissy-core-e082001f7c7c8ce0d20aebad4e6d6f22d3bf854c.tar.gz
nissy-core-e082001f7c7c8ce0d20aebad4e6d6f22d3bf854c.zip
Moved documentation around, improved configure.sh
Diffstat (limited to '')
-rw-r--r--README.md175
-rw-r--r--TODO.txt69
-rwxr-xr-xconfigure.sh3
-rw-r--r--cube.c5
-rw-r--r--cube.h177
-rw-r--r--utils/detect-immintrin.c5
6 files changed, 239 insertions, 195 deletions
diff --git a/README.md b/README.md
index aa5c4f7..4a0157a 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,7 @@
1# Prototype for a new optimal solver 1# Prototype for a new optimal solver
2 2
3Work in progress. There is some documentation at the bottom of this page, 3Work in progress. Everything is in a state of flux and can change without
4but do not believe it. Everything is in a state of flux and can change 4notice.
5without notice.
6 5
7## Building and running tests 6## Building and running tests
8 7
@@ -34,173 +33,3 @@ $ make benchmark
34``` 33```
35 34
36for benchmarks. 35for benchmarks.
37
38## TODO:
39
40### Generic solver
41
42* finish implementation
43* tests: solve full cube (max 7-8 moves?)
44* more tests: eo and other stuff
45* benchmarks
46
47### Add NISS
48
49* Add mask to moves (e.g. U | NISS where NISS = 32 or something)
50* Adapt readmoves and writemoves
51
52### Coordinates
53
54* [done] eo
55* co
56* ep
57* epsep
58* cp
59* cpsep
60* cphtr
61
62What about symcoord?
63
64### Solving
65
66All solving functions take a cube and some parameters as input.
67
68* Depth [uint, <= 20]: all solvers work at fixed depth. The caller
69 implementation can implement an A* search.
70* max [int]: the maximum number of solutions to find. Set to a negative
71 value for all solutions.
72* sol [move_t *]: the array for returning the solutions. The caller
73 should make sure that it can hold at least max * depth values.
74* Table [uint8_t *]: table with all the necessare pre-computed info.
75 The table can be generated with a companion function, but reading
76 from and writing to file is delegated to the caller implementation.
77
78Implement the following solvers:
79* Slow: basic solver without any table.
80* H48: one-bit-per-entry table + fallback, 48 symmetries and so on.
81 See planner.
82* nxopt31: mostly for comparison.
83* other nxopt solvers: make generic and take the type as parameter.
84* Step solver: take a coordinate function and a moveset as a parameter.
85
86### cube.h changes
87
88* better documentation: add parameter names, one-line comment
89 for each function
90* prefix public functions with nissy_ or something similar
91* move() that takes a string (alg) as input
92* Add single moves and transformations to the interface? (performance!)
93
94### Documentation and interface
95
96* inline some documentation as comments in source code
97* README.md (maybe convert to txt?) becomes the reference documentation
98
99### Optimizations
100
101* Trans: don't do full compose, for some trans composing perm is enough.
102 Split out sumco() as a separate function and refactor, optimize.
103* Use multi-move (up to 4/5 moves at once)
104* CO is the worst part of moving, transforming and inverting. Try basing
105 everything on representing the cube without CO and apply it only at the
106 end to check that it is actually solved.
107* see if vcube's method to flip all corners is better
108* find a better way for computing the inverse?
109* Improve avx2 instructions in general
110
111## Internal representation of the cube
112
113The plan (TODO) is to have multiple implementations: some that
114take advantage of advanced CPU instructions (SIMD) and a fallback
115"array" representation that works on any architecture.
116
117### Array representation (fallback)
118
119In this implementation of the cube.h interface, the cube is represented
120by two arrays of 8-bit unsigned integers, one for centers and one for
121corners. The 4 leas-significant digits of each bit determine the piece,
122the other 4 are used for orientation or kept to 0.
123
124Edges:
125 xxxopppp (x = unused, o = orientation, p = piece)
126
127Corners:
128 xooxpppp (x = unused, o = orientation, p = piece)
129
130The two bits for CO are shifted to make it possible to perform mod 3
131operations (sum, inverse) using only addition and bitwise operators.
132See below for details.
133
134The third bit is needed because x+y+1 can exceed 4.
135
136### AVX2
137
138Work in progress
139
140
141## Textual representation of the cube
142
143The functions readcube() and writecube() use different formats to read
144and write a cube to text. Not all formats are supported for both input
145and output.
146
147### H48 - standard format for h48 (read, write)
148
149Each edge is represented by two letters denoting the sides it belongs to
150and one number denoting its orientation (0 oriented, 1 mis-oriented).
151Similarly, each corner is represented by three letters and a number
152(0 oriented, 1 twisted clockwise, 2 twisted counter-clockwise).
153Edge orientation is relative to the F / B axis, corner orientation is
154relative to the U / D axis.
155
156The pieces are ordered such that the solved cube looks like this:
157
158UF0 UB0 DB0 DF0 UR0 UL0 DL0 DR0 FR0 FL0 BL0 BR0
159UFR0 UBL0 DFL0 DBR0 UFL0 UBR0 DFR0 DBL0
160
161Whitespace (including newlines) between pieces is ignored when reading
162the cube, and a single whitespace character is added between pieces
163when writing.
164
165The cube after the moves R'U'F looks like this:
166
167FL1 BR0 DB0 UR1 UF0 UB0 DL0 FR0 UL1 DF1 BL0 DR0
168UBL1 DBR1 UFR2 DFR2 DFL2 UBL2 UFL2 DBL0
169
170### SRC - representation of the object in C code for cube_array (write)
171
172The exact format depends on the internal cube representation (TODO: actually
173this is false, because I need all formats for code generation; also adapating
174tests is hard). It is guaranteed that, if OUT is the output in this format,
175the line
176
177cube_t cube = OUT;
178
179is interpreted correctly by h48.
180
181
182## Transformations
183
184Transformations can be either simple rotations or a rotation composed
185with a mirroring.
186
187Simple rotations are denoted by two letters corresponding to the faces
188to be moved to the U and F positions, respectively. For example FD is
189the rotation that brings the F face on top and the D face on front.
190
191A composed rotation + mirror is obtained by applying the corresponding
192rotation to the solved cube mirrored along the M plane.
193
194For example, to apply the transformation RBm (mirrored RB) to a cube C:
195 1a. Apply a mirror along the M plane to the solved cube
196 1b. Rotate the mirrored cube with z' y2
197 3. Apply the cube C to the transformed solved cube
198 4. Apply the transformations of step 1a and 1b in reverse
199
200The orientation of pieces after a rotation ignores the new position
201of centers. A rotated cube can technically be inconsistent, because
202the parity of the edge permutation has to be adjusted considering the
203parity of the centers, which we ignore.
204
205The utility script mirror.sh transforms a solved, rotated cube to its
206mirrored and rotated version.
diff --git a/TODO.txt b/TODO.txt
new file mode 100644
index 0000000..69d528a
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,69 @@
1### Generic solver
2
3* finish implementation
4* tests: solve full cube (max 7-8 moves?)
5* more tests: eo and other stuff
6* benchmarks
7
8### Coordinates
9
10* [done] eo
11* co
12* ep
13* epsep
14* cp
15* cpsep
16* cphtr
17
18What about symcoord?
19
20### Solving
21
22All solving functions take a cube and some parameters as input.
23
24* Depth [uint, <= 20]: all solvers work at fixed depth. The caller
25 implementation can implement an A* search.
26* max [int]: the maximum number of solutions to find. Set to a negative
27 value for all solutions.
28* sol [move_t *]: the array for returning the solutions. The caller
29 should make sure that it can hold at least max * depth values.
30* Table [uint8_t *]: table with all the necessare pre-computed info.
31 The table can be generated with a companion function, but reading
32 from and writing to file is delegated to the caller implementation.
33
34Implement the following solvers:
35* Slow: basic solver without any table.
36* H48: one-bit-per-entry table + fallback, 48 symmetries and so on.
37 See planner.
38* nxopt31: mostly for comparison.
39* other nxopt solvers: make generic and take the type as parameter.
40* Step solver: take a coordinate function and a moveset as a parameter.
41
42### cube.h changes
43
44* better documentation: add parameter names, one-line comment
45 for each function
46* prefix public functions with nissy_ or something similar
47* move() that takes a string (alg) as input
48* readtrans() should work like readmoves (read multiple, return n)
49* Add single moves and transformations to the interface? (performance!)
50
51### Optimizations
52
53* Trans: don't do full compose, for some trans composing perm is enough.
54 Split out sumco() as a separate function and refactor, optimize.
55* Use multi-move (up to 4/5 moves at once)
56* CO is the worst part of moving, transforming and inverting. Try basing
57 everything on representing the cube without CO and apply it only at the
58 end to check that it is actually solved.
59* see if vcube's method to flip all corners is better
60* find a better way for computing the inverse?
61* Improve avx2 instructions in general
62
63### Improvements and other things
64
65* NISS: Add mask to moves (e.g. U | NISS where NISS = 32 or something);
66 adapt readmoves and writemoves.
67* Consider adding centers and other moves (for avx2: centers in the
68 same lane as corners, numbered from 9 to 14)
69* rename to: libnissy? (also change all references to cube.c in doc)
diff --git a/configure.sh b/configure.sh
index 44774cd..9a790ca 100755
--- a/configure.sh
+++ b/configure.sh
@@ -1,5 +1,8 @@
1#!/bin/sh 1#!/bin/sh
2 2
3cc -mavx2 utils/detect-immintrin.c && detected="AVX2" && rm a.out
4TYPE=${TYPE-"$detected"}
5
3STD="-std=c99" 6STD="-std=c99"
4WFLAGS="-pedantic -Wall -Wextra -Wno-unused-parameter -Wno-unused-function" 7WFLAGS="-pedantic -Wall -Wextra -Wno-unused-parameter -Wno-unused-function"
5[ "$TYPE" = "AVX2" ] && AVX="-mavx2" 8[ "$TYPE" = "AVX2" ] && AVX="-mavx2"
diff --git a/cube.c b/cube.c
index cc38be7..3ba3926 100644
--- a/cube.c
+++ b/cube.c
@@ -94,9 +94,6 @@ Section: constants and strings
94#define BDm 46 94#define BDm 46
95#define BLm 47 95#define BLm 47
96 96
97#define errormove 99U
98#define errortrans 99U
99
100#define _c_ufr 0U 97#define _c_ufr 0U
101#define _c_ubl 1U 98#define _c_ubl 1U
102#define _c_dfl 2U 99#define _c_dfl 2U
@@ -620,7 +617,7 @@ readtrans(char *buf)
620 return t; 617 return t;
621 618
622 DBG_LOG("readtrans error\n"); 619 DBG_LOG("readtrans error\n");
623 return errortrans; 620 return _error;
624} 621}
625 622
626void 623void
diff --git a/cube.h b/cube.h
index 56118c2..3f9b509 100644
--- a/cube.h
+++ b/cube.h
@@ -1,36 +1,177 @@
1/******************************************************************************
2Cube type definition
3
4Each piece is represented by an (unsigned) 8-bit integer. The 4
5least-significant bits determine which piece it is, the other 4 determine
6the orientation.
7
8Edges are numbered as follows (see also cube.c):
9UF=0 UB=1 DB=2 DF=3 UR=4 UL=5 DL=6 DR=7 FR=8 FL=9 BL=10 BR=11
10
11Corners are numbered as follows:
12UFR=0 UBL=1 DFL=2 DBR=3 UFL=4 UBR=5 DFR=6 DBL=7
13
14The orientation of the edges is with respect to F/B, the orientation of
15corners is with respect to U/D.
16
17The permutation of the center pieces is not stored. This means that the
18cube is assumed to be in a fixed orientation.
19
20TODO: encode centers?
21
22The exact cube type structure depends on your system's configuration. If
23you operate on the cube only via the functions provided below, you don't
24need to worry about this.
25******************************************************************************/
26
1#ifdef CUBE_AVX2 27#ifdef CUBE_AVX2
2typedef __m256i cube_t; 28typedef __m256i cube_t;
3#else 29#else
4typedef struct { 30typedef struct {
5 uint8_t c[8]; 31 uint8_t c[8]; /* Corners */
6 uint8_t e[12]; 32 uint8_t e[12]; /* Edges */
7} cube_t; 33} cube_t;
8#endif 34#endif
9 35
10typedef uint8_t move_t; 36/* Returns a copy of the solved cube */
11typedef uint8_t trans_t;
12
13int readmoves(char *, move_t *);
14void writemoves(move_t *, int, char *);
15trans_t readtrans(char *);
16void writetrans(trans_t, char *);
17
18typedef enum {AVX, H48, SRC} format_t;
19cube_t readcube(format_t, char *); /* Supports: H48 */
20void writecube(format_t, cube_t, char *); /* Supports: AVX, H48, SRC */
21
22cube_t solvedcube(void); 37cube_t solvedcube(void);
38
39/* Basic checks on the cube */
23bool issolvable(cube_t); 40bool issolvable(cube_t);
24bool equal(cube_t, cube_t); 41bool equal(cube_t, cube_t);
25bool issolved(cube_t); 42bool issolved(cube_t);
43
44/* Apply the second cube on the first as a move sequence */
45cube_t compose(cube_t, cube_t);
46
47/* Invert the cube */
48cube_t inverse(cube_t);
49
50/* All functions can return an error value, use iserror() to check this */
26bool iserror(cube_t); 51bool iserror(cube_t);
27 52
53/******************************************************************************
54Moves and transformations
55
56Moves and transformations are represented each as an (unsigned) 8 bit integer.
57
58Moves are numbered as follows:
59U=0 U2=1 U'=2 D=3 D2=4 D'=5
60R=6 R2=7 R'=8 L=9 L2=10 L'=11
61F=12 F2=13 F'=14 B=15 B2=16 B'=17
62
63TODO: NISS
64
65TODO: Extend the moveset?
66
67Transformations can be either simple rotations or a rotation composed
68with a mirroring. A composed rotation + mirror is obtained by applying
69the corresponding rotation to the solved cube mirrored along the M plane.
70
71For example, to apply the transformation RBm (mirrored RB) to a cube C:
72 1. Apply a mirror along the M plane to the solved cube
73 2. Rotate the mirrored cube with z' y2
74 3. Apply the cube C to the transformed solved cube
75 4. Apply the transformations of step 1a and 1b in reverse
76
77See cube.c for a full list of transformations.
78******************************************************************************/
79
80typedef uint8_t move_t;
81typedef uint8_t trans_t;
82
83/* Apply a move or a transformation on the cube */
28cube_t move(cube_t, move_t); 84cube_t move(cube_t, move_t);
29cube_t inverse(cube_t);
30cube_t compose(cube_t, cube_t);
31cube_t transform(cube_t, trans_t); 85cube_t transform(cube_t, trans_t);
32 86
33int16_t coord_eo(cube_t); 87/******************************************************************************
88Read / write utilities
89
90Reading and writing is not done directly via stdin / stdout, but via an
91array of char (called buf in the prototypes below).
92
93Multiple representations of the cube as text are supported, although
94not all of them are supported for both reading and writing. See below
95for details. More formats may be supported in the future.
96
97Moves are read using the standard notation. Each move (U, D, R, L, F,
98B) can be followed by a modifier (1, 2, 3, '). Whitespace (spaces, tabs,
99newlines) are ignored. Parantheses and other notation is not supported.
100TODO: parantheses for NISS
101
102For how transformations are read or written, see cube.c.
103******************************************************************************/
104
105/* The different formats for reading or writing the cube */
106typedef enum {
107 H48, /* H48 is a human-readable format.
108 *
109 * Each edge is represented by two letters denoting the sides it
110 * belongs to and one number denoting its orientation (0 oriented,
111 * 1 mis-oriented). Similarly, each corner is represented by three
112 * letters and a number (0 oriented, 1 twisted clockwise, 2
113 * twisted counter-clockwise).
114 *
115 * The solved cube looks like this:
116 *
117 * UF0 UB0 DB0 DF0 UR0 UL0 DL0 DR0 FR0 FL0 BL0 BR0
118 * UFR0 UBL0 DFL0 DBR0 UFL0 UBR0 DFR0 DBL0
119 *
120 * The cube after the moves R'U'F looks like this:
121 *
122 * FL1 BR0 DB0 UR1 UF0 UB0 DL0 FR0 UL1 DF1 BL0 DR0
123 * UBL1 DBR1 UFR2 DFR2 DFL2 UBL2 UFL2 DBL0
124 *
125 * Whitespace (including newlines) between pieces is ignored when
126 * reading the cube. A single whitespace character is added
127 * between pieces when writing.
128 */
129 SRC, /* The SRC format can be used to generate code for internal use.
130 *
131 * In cube.c, a type called cube_array_t is defined and used for
132 * basic, non-performance-critical methods. If OUT is the output
133 * in SRC format, the following line can be used to declare a new
134 * cube object:
135 *
136 * cube_array_t cube = OUT
137 */
138 AVX, /* The AVX format is analogous to SRC, but for the AVX2 internal
139 * representation of the cube.
140 */
141} format_t;
142
143/* Reads a cube from buf in the specified format, and return it.
144 * Supported formats: H48.
145 */
146cube_t readcube(format_t format, char *buf);
147
148/* Write the given cube to buf in the specified format.
149 * Supported formats: H48, SRC, AVX.
150 */
151void writecube(format_t format, cube_t cube, char *buf);
152
153/* Utilities for reading and writing moves */
154int readmoves(char *buf, move_t *moves);
155void writemoves(move_t *moves, int n, char *buf);
156trans_t readtrans(char *buf);
157void writetrans(trans_t trans, char *buf);
158
159/******************************************************************************
160Coordinates
161
162The coordinate functions compute one aspect of the cube (for example,
163the edge orientation) and they return it as an integer. They are used
164for example to build pruning tables for various solving methods.
165******************************************************************************/
166
167int16_t coord_eo(cube_t); /* Edge orientation */
168
169/******************************************************************************
170Solvers
171
172Solvers return -1 in case of error, the number of solutions otherwise
173
174TODO
175******************************************************************************/
34 176
35/* Solvers return -1 in case of error, the number of solutions otherwise */
36int solve_generic(cube_t, int (*)(cube_t), uint8_t, int, move_t *); 177int solve_generic(cube_t, int (*)(cube_t), uint8_t, int, move_t *);
diff --git a/utils/detect-immintrin.c b/utils/detect-immintrin.c
new file mode 100644
index 0000000..20da678
--- /dev/null
+++ b/utils/detect-immintrin.c
@@ -0,0 +1,5 @@
1#include <immintrin.h>
2
3int main() {
4 return 0;
5}

Generated with cgit - Back to sebastiano.tronto.net