Table generation: transform only edges (cube_avx2 and cube_portable) - implement compose_fast_edges and compose_fast_corners - tests not needed: just base the full transform on the other two - cube_portable: easy for compose_fast to call the other two - cube_avx2: split in (EP+EO+CP) and (CO); compose_edges call (EP+EO+CP), compose_corners calls the full compose (cube_routines) - refactor transform(): use big array of cubes instead of switch - add transform_edges and transform_corners (solve_h48) - uncomment transform_edges() and transform_corners() Solver - write a solver (how many tricks? some, but not all are needed) More utilities for tables (in cube.h) - a "dryrun" function that only tells you the size needed - check hash of generated data Goal: find out which k value is best - temporarily call current table and solver "k4" instead of h48 - write table generation and solver for k2 and k1 - benchmark for different sizes! Refactoring - remove cube type and some low-level utilities from interface, rename cube_fast_t to cube_t - add b64 i/o format, base64 encoded cube, one 6-bit word per piece ## H48 optimal solver (some has already been implemented) First compute co + csep. Use csep as a binary number (2^7 instead of 70, loose a factor of 1.8 but still fits in a few megabytes or less). Use co + csep as an index in a table whose entries have: 6 bits for ttrep, 12 bits for rep, 4 bits for pruning. Optionally, 4 more bits could be used for the base of the pruning table, if we want to have a different base for each corner state; but probably not useful. If the first pruning is enough, or if the base value of the pruning table (see below) is too low, do not compute the full coordinate (which includes epsep + partial EO, 12 different sizes depending on how many edges). Otherwise, transform edges only using ttrep and compute full coordinate. Look up in table. 3 types of table: 1. 4 bits per entry, full pruning table 2. 3 bits with base value (let's try, why not) 3. 2 bits with base value, nxopt style 4. 1 bit per entry, telling only if more or less than mid value Types 2-4 require benchmarks, a lot of them. Inverse probing (no need to compute inverse, compute one at the beginning and keep adding premoves); better do first part of pruning for both normal and inverse and only then search in the full table. If inverse probing gives tight bound, reduce branching factor, optionally switch. Here NISS may be useful. ## Other solvers * nxopt (various sizes, for comparison; also use base value probing and benchmarking) * Coordinate solver for replacing nissy backend (specify in the comments that coordinates return 0 if solved) * simple solver with small table for short solutions ## ARM NEON intrinsics and other architectures * For ARM: use two uint8x16_t (or uint8x16x2_t) and vqtbl* instructions; see https://developer.arm.com/architectures/instruction-sets/intrinsics * Implement also SSE? Why not... ## Optimizations * Moves: don't do full compose for U*, D*, *2 (I removed this because I was using shuffle intructions wrong, should re-do it) * transform edges only for h48 coord calculation * ptable: since it is fully symmetric, do only U or U2 at depth 1 * use threads: how to detect at runtime? what is sane number to default to? pthreads or threads.h? * multisolve with adaptive threading * Trans: don't do full compose, for some trans composing perm is enough. Split out sumco() as a separate function and refactor, optimize. * Use multi-move (up to 4/5 moves at once) * see if vcube's method to flip all corners is better * find a better way for computing the inverse? ## Improvements and other things * Rename to libnissy (prefix public functions with nissy_?) * add centers (and slice moves and rotations) for avx2: centers in the same lane as corners, numbered from 9 to 14 * for CO: move to bits 5 and 6, no need for padding bit * manipulate move sequences (invert, unniss, cleanup, mirror / transform...) * NISS: Add mask to moves (e.g. U | NISS where NISS = 32 or something); adapt readmoves and writemoves. * More I/O formats: reid format nissy ascii art (color = 1 letter? color print?) twizzle binary https://www.experiments.cubing.net/cubing.js/spec/binary/ ## "Front-end" * Write adapter code for other languages: python hare (see blog post 2023-12-01 for ffi) rust, go dart ffi, js java * add also example code (e.g. an optimal solver) in examples/ ## More documentation? * Add documentation comments inside cube.c? * Copy this to cube.c Transformations can be either simple rotations or a rotation composed with a mirroring. A composed rotation + mirror is obtained by applying the corresponding rotation to the solved cube mirrored along the M plane. For example, to apply the transformation RBm (mirrored RB) to a cube C: 1. Apply a mirror along the M plane to the solved cube 2. Rotate the mirrored cube with z' y2 3. Apply the cube C to the transformed solved cube 4. Apply the transformations of step 1a and 1b in reverse ## Future work? * A* on GPU? https://github.com/mwarzynski/uw_parallel_a_star