nissy-fmc

A Rubik's cube FMC assistant
git clone https://git.tronto.net/nissy-fmc
Download | Log | Files | Refs | README | LICENSE

commit ec669b3179ea8150b15777d66c4365fc2ea7870f
parent 5d536a65d75f7ee452a2164858342937e2332c6d
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Mon, 17 Apr 2023 22:41:49 +0200

merged coord and pruning, separated steps

Diffstat:
Msrc/coord.c | 551++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/coord.h | 197+++++++------------------------------------------------------------------------
Dsrc/pruning.c | 323-------------------------------------------------------------------------------
Dsrc/pruning.h | 42------------------------------------------
Msrc/solve.c | 104++++++++-----------------------------------------------------------------------
Asrc/steps.c | 485+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/steps.h | 36++++++++++++++++++++++++++++++++++++
7 files changed, 811 insertions(+), 927 deletions(-)

diff --git a/src/coord.c b/src/coord.c @@ -2,6 +2,9 @@ #include "coord.h" +#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) +#define ENTRIES_PER_GROUP_COMPACT (4*sizeof(entry_group_t)) + static uint64_t indexers_getind(Indexer **is, Cube *c); static uint64_t indexers_getmax(Indexer **is); static void indexers_makecube(Indexer **is, uint64_t ind, Cube *c); @@ -14,293 +17,15 @@ static bool write_coord_mtable(Coordinate *coord); static bool write_coord_sd(Coordinate *coord); static bool write_coord_ttable(Coordinate *coord); -/* Utility functions *********************************************************/ - -int -factorial(int n) -{ - int i, ret = 1; - - if (n < 0) - return 0; - - for (i = 1; i <= n; i++) - ret *= i; - - return ret; -} - -int -perm_to_index(int *a, int n) -{ - int i, j, c, ret = 0; - - for (i = 0; i < n; i++) { - c = 0; - for (j = i+1; j < n; j++) - c += (a[i] > a[j]) ? 1 : 0; - ret += factorial(n-i-1) * c; - } - - return ret; -} - -void -index_to_perm(int p, int n, int *r) -{ - int *a = malloc(n * sizeof(int)); - int i, j, c; - - for (i = 0; i < n; i++) - a[i] = 0; - - if (p < 0 || p >= factorial(n)) - for (i = 0; i < n; i++) - r[i] = -1; - - for (i = 0; i < n; i++) { - c = 0; - j = 0; - while (c <= p / factorial(n-i-1)) - c += a[j++] ? 0 : 1; - r[i] = j-1; - a[j-1] = 1; - p %= factorial(n-i-1); - } - - free(a); -} - -int -binomial(int n, int k) -{ - if (n < 0 || k < 0 || k > n) - return 0; - - return factorial(n) / (factorial(k) * factorial(n-k)); -} - -int -subset_to_index(int *a, int n, int k) -{ - int i, ret = 0; - - for (i = 0; i < n; i++) { - if (k == n-i) - return ret; - if (a[i]) { - ret += binomial(n-i-1, k); - k--; - } - } - - return ret; -} - -void -index_to_subset(int s, int n, int k, int *r) -{ - int i, j, v; - - for (i = 0; i < n; i++) { - if (k == n-i) { - for (j = i; j < n; j++) - r[j] = 1; - return; - } - - if (k == 0) { - for (j = i; j < n; j++) - r[j] = 0; - return; - } - - v = binomial(n-i-1, k); - if (s >= v) { - r[i] = 1; - k--; - s -= v; - } else { - r[i] = 0; - } - } -} - -int -digit_array_to_int(int *a, int n, int b) -{ - int i, ret = 0, p = 1; - - for (i = 0; i < n; i++, p *= b) - ret += a[i] * p; - - return ret; -} - -void -int_to_digit_array(int a, int b, int n, int *r) -{ - int i; - - for (i = 0; i < n; i++, a /= b) - r[i] = a % b; -} - -void -int_to_sum_zero_array(int x, int b, int n, int *a) -{ - int i, s = 0; - - int_to_digit_array(x, b, n-1, a); - for (i = 0; i < n - 1; i++) - s = (s + a[i]) % b; - a[n-1] = (b - s) % b; -} - -int -perm_sign(int *a, int n) -{ - int i, j, ret = 0; - - for (i = 0; i < n; i++) - for (j = i+1; j < n; j++) - ret += (a[i] > a[j]) ? 1 : 0; - - return ret % 2; -} - -/* Indexers ******************************************************************/ - -uint64_t -index_eofb(Cube *cube) -{ - return (uint64_t)digit_array_to_int(cube->eo, 11, 2); -} - -uint64_t -index_coud(Cube *cube) -{ - return (uint64_t)digit_array_to_int(cube->co, 7, 3); -} - -uint64_t -index_cp(Cube *cube) -{ - return (uint64_t)perm_to_index(cube->cp, 8); -} - -uint64_t -index_epe(Cube *cube) -{ - int i, e[4]; - - for (i = 0; i < 4; i++) - e[i] = cube->ep[i+8] - 8; - - return (uint64_t)perm_to_index(e, 4); -} - -uint64_t -index_epud(Cube *cube) -{ - return (uint64_t)perm_to_index(cube->ep, 8); -} - -uint64_t -index_epos(Cube *cube) -{ - int i, a[12]; - - for (i = 0; i < 12; i++) - a[i] = (cube->ep[i] < 8) ? 0 : 1; - - return (uint64_t)subset_to_index(a, 12, 4); -} - -uint64_t -index_eposepe(Cube *cube) -{ - int i, j, e[4]; - uint64_t epos, epe; - - epos = (uint64_t)index_epos(cube); - for (i = 0, j = 0; i < 12; i++) - if (cube->ep[i] >= 8) - e[j++] = cube->ep[i] - 8; - epe = (uint64_t)perm_to_index(e, 4); - - return epos * FACTORIAL4 + epe; -} - -/* Inverse indexers **********************************************************/ - -void -invindex_eofb(uint64_t ind, Cube *cube) -{ - int_to_sum_zero_array(ind, 2, 12, cube->eo); -} - -void -invindex_coud(uint64_t ind, Cube *cube) -{ - int_to_sum_zero_array(ind, 3, 8, cube->co); -} - -void -invindex_cp(uint64_t ind, Cube *cube) -{ - index_to_perm(ind, 8, cube->cp); -} - -void -invindex_epe(uint64_t ind, Cube *cube) -{ - int i; - - index_to_perm(ind, 4, &cube->ep[8]); - for (i = 0; i < 4; i++) - cube->ep[i+8] += 8; -} - -void -invindex_epud(uint64_t ind, Cube *cube) -{ - index_to_perm(ind, 8, cube->ep); -} - -void -invindex_epos(uint64_t ind, Cube *cube) -{ - int i, j, k; - - index_to_subset(ind, 12, 4, cube->ep); - for (i = 0, j = 0, k = 8; i < 12; i++) - if (cube->ep[i] == 0) - cube->ep[i] = j++; - else - cube->ep[i] = k++; -} - -void -invindex_eposepe(uint64_t ind, Cube *cube) -{ - int i, j, k, e[4]; - uint64_t epos, epe; - - epos = ind / FACTORIAL4; - epe = ind % FACTORIAL4; - - index_to_subset(epos, 12, 4, cube->ep); - index_to_perm(epe, 4, e); - - for (i = 0, j = 0, k = 0; i < 12; i++) - if (cube->ep[i] == 0) - cube->ep[i] = j++; - else - cube->ep[i] = e[k++] + 8; -} - -/* Other local functions *****************************************************/ +static void genptable(Coordinate *coord); +static void genptable_bfs(Coordinate *coord, int d); +static void fixnasty(Coordinate *coord, uint64_t i, int d); +static void genptable_compress(Coordinate *coord); +static void genptable_setbase(Coordinate *coord); +static uint64_t ptablesize(Coordinate *coord); +static void ptable_update(Coordinate *coord, uint64_t ind, int m); +static bool read_ptable_file(Coordinate *coord); +static bool write_ptable_file(Coordinate *coord); static uint64_t indexers_getmax(Indexer **is) @@ -667,6 +392,8 @@ gen_coord(Coordinate *coord) } coord->generated = true; + genptable(coord); + return; error_gc: @@ -808,3 +535,253 @@ trans_coord(Coordinate *coord, Trans t, uint64_t ind) return coord->max; /* Only reached in case of error */ } + +static void +genptable(Coordinate *coord) +{ + bool compact; + int d, i; + uint64_t oldn, sz; + + compact = coord->base[1] != NULL; + sz = ptablesize(coord) * (compact ? 2 : 1); + coord->ptable = malloc(sz * sizeof(entry_group_t)); + + if (read_ptable_file(coord)) + return; + + /* For the first steps we proceed the same way for compact and not */ + coord->compact = false; + + fprintf(stderr, "Generating pt_%s\n", coord->name); + + /* TODO: replace with loop */ + memset(coord->ptable, ~(uint8_t)0, + ptablesize(coord)*sizeof(entry_group_t)); + for (i = 0; i < 16; i++) + coord->count[i] = 0; + + coord->updated = 0; + oldn = 0; + ptable_update(coord, 0, 0); + fixnasty(coord, 0, 0); + fprintf(stderr, "Depth %d done, generated %" + PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", + 0, coord->updated - oldn, coord->updated, coord->max); + oldn = coord->updated; + coord->count[0] = coord->updated; + for (d = 0; d < 15 && coord->updated < coord->max; d++) { + genptable_bfs(coord, d); + fprintf(stderr, "Depth %d done, generated %" + PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", + d+1, coord->updated-oldn, coord->updated, coord->max); + coord->count[d+1] = coord->updated - oldn; + oldn = coord->updated; + } + fprintf(stderr, "Pruning table generated!\n"); + + genptable_setbase(coord); + if (compact) + genptable_compress(coord); + + if (!write_ptable_file(coord)) + fprintf(stderr, "Error writing ptable file\n"); +} + +static void +genptable_bfs(Coordinate *coord, int d) +{ + uint64_t i, ii; + int pval; + Move m; + + for (i = 0; i < coord->max; i++) { + pval = ptableval(coord, i); + if (pval != d) + continue; + for (m = U; m <= B3; m++) { + if (!coord->moveset(m)) + continue; + ii = move_coord(coord, m, i, NULL); + ptable_update(coord, ii, d+1); + fixnasty(coord, ii, d+1); + } + } +} + +static void +fixnasty(Coordinate *coord, uint64_t i, int d) +{ + uint64_t ii, ss, M; + int j; + Trans t; + + if (coord->type != SYMCOMP_COORD) + return; + + M = coord->base[1]->max; + ss = coord->base[0]->selfsim[i/M]; + for (j = 0; j < coord->base[0]->tgrp->n; j++) { + t = coord->base[0]->tgrp->t[j]; + if (t == uf || !(ss & ((uint64_t)1<<t))) + continue; + ii = trans_coord(coord, t, i); + ptable_update(coord, ii, d); + } +} + +static void +genptable_compress(Coordinate *coord) +{ + int val; + uint64_t i, j; + entry_group_t mask, v; + + fprintf(stderr, "Compressing table to 2 bits per entry\n"); + + for (i = 0; i < coord->max; i += ENTRIES_PER_GROUP_COMPACT) { + mask = (entry_group_t)0; + for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) { + if (i+j >= coord->max) + break; + val = ptableval(coord, i+j) - coord->ptablebase; + v = (entry_group_t)MIN(3, MAX(0, val)); + mask |= v << (2*j); + } + coord->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask; + } + + coord->compact = true; + coord->ptable = realloc(coord->ptable, + sizeof(entry_group_t)*ptablesize(coord)); +} + +static void +genptable_setbase(Coordinate *coord) +{ + int i; + uint64_t sum, newsum; + + coord->ptablebase = 0; + sum = coord->count[0] + coord->count[1] + coord->count[2]; + for (i = 3; i < 16; i++) { + newsum = sum + coord->count[i] - coord->count[i-3]; + if (newsum > sum) + coord->ptablebase = i-3; + sum = newsum; + } +} + +void +print_ptable(Coordinate *coord) +{ + uint64_t i; + + printf("Table %s\n", coord->name); + printf("Base value: %d\n", coord->ptablebase); + for (i = 0; i < 16; i++) + printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, coord->count[i]); +} + +static uint64_t +ptablesize(Coordinate *coord) +{ + uint64_t e; + + e = coord->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; + + return (coord->max + e - 1) / e; +} + +static void +ptable_update(Coordinate *coord, uint64_t ind, int n) +{ + int sh; + entry_group_t mask; + uint64_t i; + + if (ptableval(coord, ind) <= n) + return; + + sh = 4 * (ind % ENTRIES_PER_GROUP); + mask = ((entry_group_t)15) << sh; + i = ind/ENTRIES_PER_GROUP; + coord->ptable[i] &= ~mask; + coord->ptable[i] |= (((entry_group_t)n)&15) << sh; + + coord->updated++; +} + +int +ptableval(Coordinate *coord, uint64_t ind) +{ + int ret, j, sh; + uint64_t e, ii; + + if (coord->compact) { + e = ENTRIES_PER_GROUP_COMPACT; + sh = (ind % e) * 2; + ret = (coord->ptable[ind/e] & (3 << sh)) >> sh; + if (ret != coord->ptablebase) + return ret; + for (j = 0; coord->base[j] != NULL; j++) ; + for ( ; j >= 0; j--) { + ii = ind % coord->base[j]->max; + ret = MAX(ret, ptableval(coord->base[j], ii)); + ind /= coord->base[j]->max; + } + return ret; + } + + e = ENTRIES_PER_GROUP; + sh = (ind % e) * 4; + return (coord->ptable[ind/e] & (15 << sh)) >> sh; +} + +static bool +read_ptable_file(Coordinate *coord) +{ + FILE *f; + char fname[256]; + int i; + uint64_t r; + + strcpy(fname, "tables/pt_"); + strcat(fname, coord->name); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(&(coord->ptablebase), sizeof(int), 1, f); + for (i = 0; i < 16; i++) + r += fread(&(coord->count[i]), sizeof(uint64_t), 1, f); + r += fread(coord->ptable, sizeof(entry_group_t), ptablesize(coord), f); + + fclose(f); + + return r == 17 + ptablesize(coord); +} + +static bool +write_ptable_file(Coordinate *coord) +{ + FILE *f; + char fname[256]; + int i; + uint64_t w; + + strcpy(fname, "tables/pt_"); + strcat(fname, coord->name); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + w = fwrite(&(coord->ptablebase), sizeof(int), 1, f); + for (i = 0; i < 16; i++) + w += fwrite(&(coord->count[i]), sizeof(uint64_t), 1, f); + w += fwrite(coord->ptable, sizeof(entry_group_t), ptablesize(coord), f); + fclose(f); + + return w == 17 + ptablesize(coord); +} + diff --git a/src/coord.h b/src/coord.h @@ -8,6 +8,9 @@ #include "cube.h" +#define entry_group_t uint8_t + +typedef bool (Moveset)(Move); typedef enum { COMP_COORD, SYM_COORD, SYMCOMP_COORD } CoordType; typedef struct { int n; @@ -17,8 +20,6 @@ typedef struct { typedef struct coordinate { char * name; CoordType type; - bool generated; - Indexer * i[99]; uint64_t max; uint64_t * mtable[NMOVES]; uint64_t * ttable[NTRANS]; @@ -28,7 +29,17 @@ typedef struct coordinate { uint64_t * symrep; Trans * transtorep; Trans * ttrep_move[NMOVES]; - uint64_t * selfsim; + + bool generated; + Indexer * i[99]; + uint64_t * selfsim; /* used only in fixnasty */ + + Moveset * moveset; /* for pruning, mt and compressing */ + uint64_t updated; + entry_group_t * ptable; + int ptablebase; /* Renamed */ + bool compact; /* Only needed for generation, maybe keep */ + uint64_t count[16]; /* Only needed for generation and print */ } Coordinate; void gen_coord(Coordinate *coord); @@ -39,183 +50,7 @@ uint64_t move_coord(Coordinate *coord, Move m, bool test_coord(Coordinate *coord); uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind); -/* Base coordinates and their index functions ********************************/ - -#ifndef COORD_C - -extern Coordinate coord_eofb; -extern Coordinate coord_coud; -extern Coordinate coord_cp; -extern Coordinate coord_epos; -extern Coordinate coord_epe; -extern Coordinate coord_eposepe; -extern Coordinate coord_epud; -extern Coordinate coord_eofbepos; -extern Coordinate coord_eofbepos_sym16; -extern Coordinate coord_drud_sym16; -extern Coordinate coord_cp_sym16; -extern Coordinate coord_drudfin_noE_sym16; - -#else - -/* Indexers ******************************************************************/ - -uint64_t index_eofb(Cube *cube); -void invindex_eofb(uint64_t ind, Cube *ret); -Indexer -i_eofb = { - .n = POW2TO11, - .index = index_eofb, - .to_cube = invindex_eofb, -}; - -uint64_t index_coud(Cube *cube); -void invindex_coud(uint64_t ind, Cube *ret); -Indexer -i_coud = { - .n = POW3TO7, - .index = index_coud, - .to_cube = invindex_coud, -}; - -uint64_t index_cp(Cube *cube); -void invindex_cp(uint64_t ind, Cube *ret); -Indexer -i_cp = { - .n = FACTORIAL8, - .index = index_cp, - .to_cube = invindex_cp, -}; - -uint64_t index_epos(Cube *cube); -void invindex_epos(uint64_t ind, Cube *ret); -Indexer -i_epos = { - .n = BINOM12ON4, - .index = index_epos, - .to_cube = invindex_epos, -}; - -uint64_t index_epe(Cube *cube); -void invindex_epe(uint64_t ind, Cube *ret); -Indexer -i_epe = { - .n = FACTORIAL4, - .index = index_epe, - .to_cube = invindex_epe, -}; - -uint64_t index_eposepe(Cube *cube); -void invindex_eposepe(uint64_t ind, Cube *ret); -Indexer -i_eposepe = { - .n = BINOM12ON4 * FACTORIAL4, - .index = index_eposepe, - .to_cube = invindex_eposepe, -}; - -uint64_t index_epud(Cube *cube); -void invindex_epud(uint64_t ind, Cube *ret); -Indexer -i_epud = { - .n = FACTORIAL8, - .index = index_epud, - .to_cube = invindex_epud, -}; - -/* Composite coordinates *****************************************************/ - -Coordinate -coord_eofb = { - .name = "eofb", - .type = COMP_COORD, - .i = {&i_eofb, NULL}, -}; - -Coordinate -coord_coud = { - .name = "coud", - .type = COMP_COORD, - .i = {&i_coud, NULL}, -}; - -Coordinate -coord_cp = { - .name = "cp", - .type = COMP_COORD, - .i = {&i_cp, NULL}, -}; - -Coordinate -coord_epos = { - .name = "epos", - .type = COMP_COORD, - .i = {&i_epos, NULL}, -}; - -Coordinate -coord_epe = { - .name = "epe", - .type = COMP_COORD, - .i = {&i_epe, NULL}, -}; - -Coordinate -coord_eposepe = { - .name = "eposepe", - .type = COMP_COORD, - .i = {&i_eposepe, NULL}, -}; - -Coordinate -coord_epud = { - .name = "epud", - .type = COMP_COORD, - .i = {&i_epud, NULL}, -}; - -Coordinate -coord_eofbepos = { - .name = "eofbepos", - .type = COMP_COORD, - .i = {&i_epos, &i_eofb, NULL}, -}; - -/* Symcoordinates ************************************************************/ - -Coordinate -coord_eofbepos_sym16 = { - .name = "eofbepos_sym16", - .type = SYM_COORD, - .base = {&coord_eofbepos, NULL}, - .tgrp = &tgrp_udfix, -}; - -Coordinate -coord_cp_sym16 = { - .name = "cp_sym16", - .type = SYM_COORD, - .base = {&coord_cp, NULL}, - .tgrp = &tgrp_udfix, -}; - -/* "Symcomp" coordinates *****************************************************/ - -Coordinate -coord_drud_sym16 = { - .name = "drud_sym16", - .type = SYMCOMP_COORD, - .base = {&coord_eofbepos_sym16, &coord_coud}, -}; - -Coordinate -coord_drudfin_noE_sym16 = { - .name = "drudfin_noE_sym16", - .type = SYMCOMP_COORD, - .base = {&coord_cp_sym16, &coord_epud}, -}; - -#endif +void print_ptable(Coordinate *coord); +int ptableval(Coordinate *coord, uint64_t ind); #endif - diff --git a/src/pruning.c b/src/pruning.c @@ -1,323 +0,0 @@ -#define PRUNING_C - -#include "pruning.h" - -#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) -#define ENTRIES_PER_GROUP_COMPACT (4*sizeof(entry_group_t)) - -static void genptable_bfs(PruneData *pd, int d); -static void fixnasty(PruneData *pd, uint64_t i, int d); -static void genptable_compress(PruneData *pd); -static void genptable_setbase(PruneData *pd); -static void ptable_update(PruneData *pd, uint64_t ind, int m); -static bool read_ptable_file(PruneData *pd); -static bool write_ptable_file(PruneData *pd); - -PDGenData *active_pdg[256]; - -bool -allowed_HTM(Move m) -{ - return m >= U && m <= B3; -} - -bool -allowed_URF(Move m) -{ - Move b = base_move(m); - - return b == U || b == R || b == F; -} - -bool -allowed_eofb(Move m) -{ - Move b = base_move(m); - - return b == U || b == D || b == R || b == L || - ((b == F || b == B) && m == b+1); -} - -bool -allowed_drud(Move m) -{ - Move b = base_move(m); - - return b == U || b == D || - ((b == R || b == L || b == F || b == B) && m == b + 1); -} - -bool -allowed_htr(Move m) -{ - return allowed_HTM(m) && m == base_move(m) + 1; -} - -PruneData * -genptable(PDGenData *pdg) -{ - bool compact; - int d, i; - uint64_t oldn, sz; - PruneData *pd; - - for (i = 0; active_pdg[i] != NULL; i++) { - pd = active_pdg[i]->pd; - if (pd->coord == pdg->coord && - pd->moveset == pdg->moveset && - pd->compact == pdg->compact) - return pd; - } - - pd = malloc(sizeof(PruneData)); - pdg->pd = pd; - pd->coord = pdg->coord; - pd->moveset = pdg->moveset; - pd->compact = pdg->compact; - - sz = ptablesize(pd) * (pd->compact ? 2 : 1); - pd->ptable = malloc(sz * sizeof(entry_group_t)); - - gen_coord(pd->coord); - - if (read_ptable_file(pd)) - goto genptable_done; - - /* For the first steps we proceed the same way for compact and not */ - compact = pd->compact; - pd->compact = false; - - fprintf(stderr, "Generating pt_%s\n", pd->coord->name); - - memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); - for (i = 0; i < 16; i++) - pd->count[i] = 0; - - ptable_update(pd, 0, 0); - pd->n = 1; - oldn = 0; - fixnasty(pd, 0, 0); - fprintf(stderr, "Depth %d done, generated %" - PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", - 0, pd->n - oldn, pd->n, pd->coord->max); - oldn = pd->n; - pd->count[0] = pd->n; - for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { - genptable_bfs(pd, d); - fprintf(stderr, "Depth %d done, generated %" - PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", - d+1, pd->n - oldn, pd->n, pd->coord->max); - pd->count[d+1] = pd->n - oldn; - oldn = pd->n; - } - fprintf(stderr, "Pruning table generated!\n"); - - genptable_setbase(pd); - if (compact) - genptable_compress(pd); - - if (!write_ptable_file(pd)) - fprintf(stderr, "Error writing ptable file\n"); - -genptable_done: - for (i = 0; active_pdg[i] != NULL; i++); - active_pdg[i] = malloc(sizeof(PDGenData)); - active_pdg[i]->coord = pdg->coord; - active_pdg[i]->moveset = pdg->moveset; - active_pdg[i]->compact = pdg->compact; - active_pdg[i]->pd = pd; - - return pd; -} - -static void -genptable_bfs(PruneData *pd, int d) -{ - uint64_t i, ii; - int pval; - Move m; - - for (i = 0; i < pd->coord->max; i++) { - pval = ptableval(pd, i); - if (pval != d) - continue; - for (m = U; m <= B3; m++) { - if (!pd->moveset(m)) - continue; - ii = move_coord(pd->coord, m, i, NULL); - ptable_update(pd, ii, d+1); - fixnasty(pd, ii, d+1); - } - } -} - -static void -fixnasty(PruneData *pd, uint64_t i, int d) -{ - uint64_t ii, ss, M; - int j; - Trans t; - - if (pd->coord->type != SYMCOMP_COORD) - return; - - M = pd->coord->base[1]->max; - ss = pd->coord->base[0]->selfsim[i/M]; - for (j = 0; j < pd->coord->base[0]->tgrp->n; j++) { - t = pd->coord->base[0]->tgrp->t[j]; - if (t == uf || !(ss & ((uint64_t)1<<t))) - continue; - ii = trans_coord(pd->coord, t, i); - ptable_update(pd, ii, d); - } -} - -static void -genptable_compress(PruneData *pd) -{ - int val; - uint64_t i, j; - entry_group_t mask, v; - - fprintf(stderr, "Compressing table to 2 bits per entry\n"); - - for (i = 0; i < pd->coord->max; i += ENTRIES_PER_GROUP_COMPACT) { - mask = (entry_group_t)0; - for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) { - if (i+j >= pd->coord->max) - break; - val = ptableval(pd, i+j) - pd->base; - v = (entry_group_t)MIN(3, MAX(0, val)); - mask |= v << (2*j); - } - pd->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask; - } - - pd->compact = true; - pd->ptable = realloc(pd->ptable, sizeof(entry_group_t)*ptablesize(pd)); -} - -static void -genptable_setbase(PruneData *pd) -{ - int i; - uint64_t sum, newsum; - - pd->base = 0; - sum = pd->count[0] + pd->count[1] + pd->count[2]; - for (i = 3; i < 16; i++) { - newsum = sum + pd->count[i] - pd->count[i-3]; - if (newsum > sum) - pd->base = i-3; - sum = newsum; - } -} - -void -print_ptable(PruneData *pd) -{ - uint64_t i; - - printf("Table %s\n", pd->coord->name); - printf("Base value: %d\n", pd->base); - for (i = 0; i < 16; i++) - printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); -} - -uint64_t -ptablesize(PruneData *pd) -{ - uint64_t e; - - e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; - - return (pd->coord->max + e - 1) / e; -} - -static void -ptable_update(PruneData *pd, uint64_t ind, int n) -{ - int sh; - entry_group_t mask; - uint64_t i; - - if (ptableval(pd, ind) <= n) - return; - - sh = 4 * (ind % ENTRIES_PER_GROUP); - mask = ((entry_group_t)15) << sh; - i = ind/ENTRIES_PER_GROUP; - pd->ptable[i] &= ~mask; - pd->ptable[i] |= (((entry_group_t)n)&15) << sh; - pd->n++; -} - -int -ptableval(PruneData *pd, uint64_t ind) -{ - int sh, ret; - uint64_t e; - entry_group_t m; - - if (pd->compact) { - e = ENTRIES_PER_GROUP_COMPACT; - m = 3; - sh = (ind % e) * 2; - } else { - e = ENTRIES_PER_GROUP; - m = 15; - sh = (ind % e) * 4; - } - - ret = (pd->ptable[ind/e] & (m << sh)) >> sh; - - return pd->compact ? ret + pd->base : ret; -} - -static bool -read_ptable_file(PruneData *pd) -{ - FILE *f; - char fname[256]; - int i; - uint64_t r; - - strcpy(fname, "tables/pt_"); - strcat(fname, pd->coord->name); - - if ((f = fopen(fname, "rb")) == NULL) - return false; - - r = fread(&(pd->base), sizeof(int), 1, f); - for (i = 0; i < 16; i++) - r += fread(&(pd->count[i]), sizeof(uint64_t), 1, f); - r += fread(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); - - fclose(f); - - return r == 17 + ptablesize(pd); -} - -static bool -write_ptable_file(PruneData *pd) -{ - FILE *f; - char fname[256]; - int i; - uint64_t w; - - strcpy(fname, "tables/pt_"); - strcat(fname, pd->coord->name); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - w = fwrite(&(pd->base), sizeof(int), 1, f); - for (i = 0; i < 16; i++) - w += fwrite(&(pd->count[i]), sizeof(uint64_t), 1, f); - w += fwrite(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); - fclose(f); - - return w == 17 + ptablesize(pd); -} - diff --git a/src/pruning.h b/src/pruning.h @@ -1,42 +0,0 @@ -#ifndef PRUNING_H -#define PRUNING_H - -#include "coord.h" - -#define entry_group_t uint8_t - -typedef bool (Moveset)(Move); -typedef struct { - entry_group_t * ptable; - uint64_t n; - Coordinate * coord; - Moveset * moveset; - bool compact; - int base; - uint64_t count[16]; - uint64_t fbmod; -} PruneData; -typedef struct { - Coordinate * coord; - Moveset * moveset; - bool compact; - PruneData * pd; -} PDGenData; - -bool allowed_all(Move m); -bool allowed_HTM(Move m); -bool allowed_URF(Move m); -bool allowed_eofb(Move m); -bool allowed_drud(Move m); -bool allowed_htr(Move m); - -void free_pd(PruneData *pd); -PruneData * genptable(PDGenData *data); -void print_ptable(PruneData *pd); -uint64_t ptablesize(PruneData *pd); -int ptableval(PruneData *pd, uint64_t ind); - -extern PDGenData *active_pdg[256]; - -#endif - diff --git a/src/solve.c b/src/solve.c @@ -1,25 +1,12 @@ #define SOLVE_C +#include "coord.h" +#include "steps.h" #include "solve.h" -#include "pruning.h" - -#define MAX_N_COORD 3 typedef enum { NORMAL, INVERSE, NISS } SolutionType; typedef struct { uint64_t val; Trans t; } Movable; typedef struct { - char * shortname; - bool filter; - Moveset * moveset; - Coordinate * coord[MAX_N_COORD]; - PruneData * pd[MAX_N_COORD]; - bool compact_pd[MAX_N_COORD]; - Coordinate * fallback_coord[MAX_N_COORD]; - PruneData * fallback_pd[MAX_N_COORD]; - uint64_t fbmod[MAX_N_COORD]; - -} Step; -typedef struct { Cube * cube; Movable ind[MAX_N_COORD]; Step * s; @@ -44,33 +31,6 @@ static void dfs(DfsArg *arg); static void dfs_niss(DfsArg *arg); static bool dfs_move_checkstop(DfsArg *arg); static bool niss_makes_sense(DfsArg *arg); -static bool singlecwend(Alg *alg); - -Step eofb_HTM = { - .shortname = "eofb", - .filter = true, - .moveset = allowed_HTM, - .coord = {&coord_eofb, NULL}, - .compact_pd = {false}, -}; - -Step drud_HTM = { - .shortname = "drud", - .filter = true, - .moveset = allowed_HTM, - .coord = {&coord_drud_sym16, NULL}, - .compact_pd = {false}, /* TODO: compactify! */ -}; - -Step drfin_drud = { - .shortname = "drudfin", - .filter = false, - .moveset = allowed_drud, - .coord = {&coord_drudfin_noE_sym16, &coord_epe, NULL}, - .compact_pd = {false}, /* TODO: compactify! */ -}; - -Step *steps[] = { &eofb_HTM, &drud_HTM, &drfin_drud, NULL }; static void append_sol(DfsArg *arg) @@ -144,17 +104,11 @@ copy_dfsarg(DfsArg *src, DfsArg *dst) static int estimate_step(Step *step, Movable *ind) { - int i, v, ret = -1; - - for (i = 0; step->coord[i] != NULL; i++) { - v = ptableval(step->pd[i], ind[i].val); - if (v == step->pd[i]->base && step->compact_pd[i]) - v = ptableval(step->fallback_pd[i], - ind[i].val / step->fbmod[i]); - if (v == 0 && ind[i].val != 0) - v = 1; - ret = MAX(ret, v); - } + int i, ret; + + ret = -1; + for (i = 0; step->coord[i] != NULL; i++) + ret = MAX(ret, ptableval(step->coord[i], ind[i].val)); return ret; } @@ -164,16 +118,15 @@ dfs(DfsArg *arg) { Move m; DfsArg newarg; - bool len, singlecw, niss; + bool len, niss; if (dfs_move_checkstop(arg)) return; if (arg->bound == 0) { len = arg->current_alg->len == arg->d; - singlecw = singlecwend(arg->current_alg); niss = !(arg->st == NISS) || arg->has_nissed; - if (len && singlecw && niss) + if (len && niss) append_sol(arg); return; } @@ -276,29 +229,6 @@ niss_makes_sense(DfsArg *arg) return estimate_step(aux.s, aux.ind) > 0; } -bool -singlecwend(Alg *alg) -{ - int i; - bool nor, inv; - Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; - - for (i = 0; i < alg->len; i++) { - if (alg->inv[i]) { - l2i = l1i; - l1i = alg->move[i]; - } else { - l2 = l1; - l1 = alg->move[i]; - } - } - - nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); - inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); - - return nor && inv; -} - /* Public functions **********************************************************/ static bool @@ -378,22 +308,8 @@ solve(char *step, char *trans, int d, char *type, char *scramble, char *sol) if (!set_step(step, &arg.s)) return 1; /* Prepare step TODO: remove all initialization! */ - PDGenData pdg; - pdg.moveset = arg.s->moveset; - for (i = 0; arg.s->coord[i] != NULL; i++) { + for (i = 0; arg.s->coord[i] != NULL; i++) gen_coord(arg.s->coord[i]); - pdg.coord = arg.s->coord[i]; - pdg.compact = arg.s->compact_pd[i]; - pdg.pd = NULL; - arg.s->pd[i] = genptable(&pdg); - if (arg.s->compact_pd[i]) { - gen_coord(arg.s->fallback_coord[i]); - pdg.coord = arg.s->fallback_coord[i]; - pdg.compact = false; - pdg.pd = NULL; - arg.s->fallback_pd[i] = genptable(&pdg); - } - } if (!set_trans(trans, &arg.t)) return 2; diff --git a/src/steps.c b/src/steps.c @@ -0,0 +1,485 @@ +#include "steps.h" + +static bool moveset_HTM(Move m); +static bool moveset_eofb(Move m); +static bool moveset_drud(Move m); +static bool moveset_htr(Move m); + +static uint64_t index_eofb(Cube *cube); +static void invindex_eofb(uint64_t ind, Cube *ret); +Indexer i_eofb = { + .n = POW2TO11, + .index = index_eofb, + .to_cube = invindex_eofb, +}; + +static uint64_t index_coud(Cube *cube); +static void invindex_coud(uint64_t ind, Cube *ret); +Indexer i_coud = { + .n = POW3TO7, + .index = index_coud, + .to_cube = invindex_coud, +}; + +static uint64_t index_cp(Cube *cube); +static void invindex_cp(uint64_t ind, Cube *ret); +Indexer i_cp = { + .n = FACTORIAL8, + .index = index_cp, + .to_cube = invindex_cp, +}; + +static uint64_t index_epos(Cube *cube); +static void invindex_epos(uint64_t ind, Cube *ret); +Indexer i_epos = { + .n = BINOM12ON4, + .index = index_epos, + .to_cube = invindex_epos, +}; + +static uint64_t index_epe(Cube *cube); +static void invindex_epe(uint64_t ind, Cube *ret); +Indexer i_epe = { + .n = FACTORIAL4, + .index = index_epe, + .to_cube = invindex_epe, +}; + +static uint64_t index_eposepe(Cube *cube); +static void invindex_eposepe(uint64_t ind, Cube *ret); +Indexer i_eposepe = { + .n = BINOM12ON4 * FACTORIAL4, + .index = index_eposepe, + .to_cube = invindex_eposepe, +}; + +static uint64_t index_epud(Cube *cube); +static void invindex_epud(uint64_t ind, Cube *ret); +Indexer i_epud = { + .n = FACTORIAL8, + .index = index_epud, + .to_cube = invindex_epud, +}; + +Coordinate coord_eofb = { + .name = "eofb", + .type = COMP_COORD, + .i = {&i_eofb, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_coud = { + .name = "coud", + .type = COMP_COORD, + .i = {&i_coud, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_cp = { + .name = "cp", + .type = COMP_COORD, + .i = {&i_cp, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_epos = { + .name = "epos", + .type = COMP_COORD, + .i = {&i_epos, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_epe = { + .name = "epe", + .type = COMP_COORD, + .i = {&i_epe, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_eposepe = { + .name = "eposepe", + .type = COMP_COORD, + .i = {&i_eposepe, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_epud = { + .name = "epud", + .type = COMP_COORD, + .i = {&i_epud, NULL}, + .moveset = moveset_drud, +}; + +Coordinate coord_eofbepos = { + .name = "eofbepos", + .type = COMP_COORD, + .i = {&i_epos, &i_eofb, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_eofbepos_sym16 = { + .name = "eofbepos_sym16", + .type = SYM_COORD, + .base = {&coord_eofbepos, NULL}, + .tgrp = &tgrp_udfix, + .moveset = moveset_HTM, +}; + +Coordinate coord_cp_sym16 = { + .name = "cp_sym16", + .type = SYM_COORD, + .base = {&coord_cp, NULL}, + .tgrp = &tgrp_udfix, + .moveset = moveset_HTM, +}; + +Coordinate coord_drud_sym16 = { + .name = "drud_sym16", + .type = SYMCOMP_COORD, + .base = {&coord_eofbepos_sym16, &coord_coud}, + .moveset = moveset_HTM, +}; + +Coordinate coord_drudfin_noE_sym16 = { + .name = "drudfin_noE_sym16", + .type = SYMCOMP_COORD, + .base = {&coord_cp_sym16, &coord_epud}, + .moveset = moveset_drud, +}; + +Coordinate *coordinates[] = { + &coord_eofb, &coord_coud, &coord_cp, &coord_epos, &coord_epe, + &coord_eposepe, &coord_epud, &coord_eofbepos, &coord_eofbepos_sym16, + &coord_drud_sym16, &coord_cp_sym16, &coord_drudfin_noE_sym16, + NULL +}; + +Step eofb_HTM = { + .shortname = "eofb", + .moveset = moveset_HTM, + .coord = {&coord_eofb, NULL}, +}; + +Step drud_HTM = { + .shortname = "drud", + .moveset = moveset_HTM, + .coord = {&coord_drud_sym16, NULL}, +}; + +Step drfin_drud = { + .shortname = "drudfin", + .moveset = moveset_drud, + .coord = {&coord_drudfin_noE_sym16, &coord_epe, NULL}, +}; + +Step *steps[] = {&eofb_HTM, &drud_HTM, &drfin_drud, NULL}; + +static bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +static bool +moveset_eofb(Move m) +{ + Move b = base_move(m); + + return b == U || b == D || b == R || b == L || + ((b == F || b == B) && m == b+1); +} + +static bool +moveset_drud(Move m) +{ + Move b = base_move(m); + + return b == U || b == D || + ((b == R || b == L || b == F || b == B) && m == b + 1); +} + +static bool +moveset_htr(Move m) +{ + return moveset_HTM(m) && m == base_move(m) + 1; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static uint64_t +index_eofb(Cube *cube) +{ + return (uint64_t)digit_array_to_int(cube->eo, 11, 2); +} + +static uint64_t +index_coud(Cube *cube) +{ + return (uint64_t)digit_array_to_int(cube->co, 7, 3); +} + +static uint64_t +index_cp(Cube *cube) +{ + return (uint64_t)perm_to_index(cube->cp, 8); +} + +static uint64_t +index_epe(Cube *cube) +{ + int i, e[4]; + + for (i = 0; i < 4; i++) + e[i] = cube->ep[i+8] - 8; + + return (uint64_t)perm_to_index(e, 4); +} + +static uint64_t +index_epud(Cube *cube) +{ + return (uint64_t)perm_to_index(cube->ep, 8); +} + +static uint64_t +index_epos(Cube *cube) +{ + int i, a[12]; + + for (i = 0; i < 12; i++) + a[i] = (cube->ep[i] < 8) ? 0 : 1; + + return (uint64_t)subset_to_index(a, 12, 4); +} + +static uint64_t +index_eposepe(Cube *cube) +{ + int i, j, e[4]; + uint64_t epos, epe; + + epos = (uint64_t)index_epos(cube); + for (i = 0, j = 0; i < 12; i++) + if (cube->ep[i] >= 8) + e[j++] = cube->ep[i] - 8; + epe = (uint64_t)perm_to_index(e, 4); + + return epos * FACTORIAL4 + epe; +} + +static void +invindex_eofb(uint64_t ind, Cube *cube) +{ + int_to_sum_zero_array(ind, 2, 12, cube->eo); +} + +static void +invindex_coud(uint64_t ind, Cube *cube) +{ + int_to_sum_zero_array(ind, 3, 8, cube->co); +} + +static void +invindex_cp(uint64_t ind, Cube *cube) +{ + index_to_perm(ind, 8, cube->cp); +} + +static void +invindex_epe(uint64_t ind, Cube *cube) +{ + int i; + + index_to_perm(ind, 4, &cube->ep[8]); + for (i = 0; i < 4; i++) + cube->ep[i+8] += 8; +} + +static void +invindex_epud(uint64_t ind, Cube *cube) +{ + index_to_perm(ind, 8, cube->ep); +} + +static void +invindex_epos(uint64_t ind, Cube *cube) +{ + int i, j, k; + + index_to_subset(ind, 12, 4, cube->ep); + for (i = 0, j = 0, k = 8; i < 12; i++) + if (cube->ep[i] == 0) + cube->ep[i] = j++; + else + cube->ep[i] = k++; +} + +static void +invindex_eposepe(uint64_t ind, Cube *cube) +{ + int i, j, k, e[4]; + uint64_t epos, epe; + + epos = ind / FACTORIAL4; + epe = ind % FACTORIAL4; + + index_to_subset(epos, 12, 4, cube->ep); + index_to_perm(epe, 4, e); + + for (i = 0, j = 0, k = 0; i < 12; i++) + if (cube->ep[i] == 0) + cube->ep[i] = j++; + else + cube->ep[i] = e[k++] + 8; +} diff --git a/src/steps.h b/src/steps.h @@ -0,0 +1,36 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "coord.h" +#include "cube.h" + +#define MAX_N_COORD 3 + +typedef struct { + char * shortname; + Moveset * moveset; + Coordinate * coord[MAX_N_COORD]; +} Step; + +extern Coordinate coord_eofb; +extern Coordinate coord_coud; +extern Coordinate coord_cp; +extern Coordinate coord_epos; +extern Coordinate coord_epe; +extern Coordinate coord_eposepe; +extern Coordinate coord_epud; +extern Coordinate coord_eofbepos; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_cp_sym16; +extern Coordinate coord_drudfin_noE_sym16; + +extern Coordinate *coordinates[]; + +extern Step eofb_HTM; +extern Step drud_HTM; +extern Step drfin_drud; + +extern Step *steps[]; + +#endif