diff options
| author | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2021-12-23 00:31:12 +0100 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2021-12-23 00:31:12 +0100 |
| commit | 4dddac9e257433a8e2f5f763d91470a7e05ff680 (patch) | |
| tree | b6f01defc37373ceabd216146262969b6958e7ed | |
| parent | 9d3c52efd1115e3d01869f729f274027813422c3 (diff) | |
| download | nissy-4dddac9e257433a8e2f5f763d91470a7e05ff680.tar.gz nissy-4dddac9e257433a8e2f5f763d91470a7e05ff680.zip | |
Added the possibility to compress tables to 2 bits per entry.
This is done similarly to nxopt: one base value is selected and entries
are memorized based on that base value. Values higher than base+3
are returned as base+3 (still a valid estimate) and values lower
or equal to base require a lookup on a "fallback" table, which
must give a valid estimate for the larger one (e.g. nxopt31 or khuge
can fallback to drud_sym16).
I have also added some info to the pruning table files: base value and
distribution. Unfortunately this means that everyone who has used nissy
2.0beta has to re-generate the tables.
| -rwxr-xr-x | nissy | bin | 319928 -> 321808 bytes | |||
| -rw-r--r-- | src/cubetypes.h | 5 | ||||
| -rw-r--r-- | src/pruning.c | 128 | ||||
| -rw-r--r-- | src/symcoord.c | 8 |
4 files changed, 108 insertions, 33 deletions
| Binary files differ | |||
diff --git a/src/cubetypes.h b/src/cubetypes.h index d1d36b2..7563abb 100644 --- a/src/cubetypes.h +++ b/src/cubetypes.h | |||
| @@ -265,6 +265,11 @@ prunedata | |||
| 265 | uint64_t n; | 265 | uint64_t n; |
| 266 | Coordinate * coord; | 266 | Coordinate * coord; |
| 267 | Moveset * moveset; | 267 | Moveset * moveset; |
| 268 | bool compact; | ||
| 269 | int base; | ||
| 270 | uint64_t count[16]; | ||
| 271 | PruneData * fallback; | ||
| 272 | uint64_t fbmod; | ||
| 268 | }; | 273 | }; |
| 269 | 274 | ||
| 270 | struct | 275 | struct |
diff --git a/src/pruning.c b/src/pruning.c index 0a6e305..9fdc32e 100644 --- a/src/pruning.c +++ b/src/pruning.c | |||
| @@ -1,11 +1,13 @@ | |||
| 1 | #include "pruning.h" | 1 | #include "pruning.h" |
| 2 | 2 | ||
| 3 | #define NCHUNKS 100000 | 3 | #define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) |
| 4 | #define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) | 4 | #define ENTRIES_PER_GROUP_COMPACT (4*sizeof(entry_group_t)) |
| 5 | 5 | ||
| 6 | static int findchunk(PruneData *pd, int nchunks, uint64_t i); | 6 | static int findchunk(PruneData *pd, int nchunks, uint64_t i); |
| 7 | static void genptable_bfs(PruneData *pd, int d, int nt, int nc); | 7 | static void genptable_bfs(PruneData *pd, int d, int nt, int nc); |
| 8 | static void genptable_compress(PruneData *pd); | ||
| 8 | static void genptable_fixnasty(PruneData *pd, int d); | 9 | static void genptable_fixnasty(PruneData *pd, int d); |
| 10 | static void genptable_setbase(PruneData *pd); | ||
| 9 | static void * instance_bfs(void *arg); | 11 | static void * instance_bfs(void *arg); |
| 10 | static void ptable_update(PruneData *pd, Cube cube, int m); | 12 | static void ptable_update(PruneData *pd, Cube cube, int m); |
| 11 | static void ptable_update_index(PruneData *pd, uint64_t ind, int m); | 13 | static void ptable_update_index(PruneData *pd, uint64_t ind, int m); |
| @@ -76,6 +78,7 @@ pd_htrfin_htr = { | |||
| 76 | .moveset = &moveset_htr, | 78 | .moveset = &moveset_htr, |
| 77 | }; | 79 | }; |
| 78 | 80 | ||
| 81 | /* TODO: remove */ | ||
| 79 | PruneData | 82 | PruneData |
| 80 | pd_khuge_HTM = { | 83 | pd_khuge_HTM = { |
| 81 | .filename = "pt_khuge_HTM", | 84 | .filename = "pt_khuge_HTM", |
| @@ -88,6 +91,10 @@ pd_nxopt31_HTM = { | |||
| 88 | .filename = "pt_nxopt31_HTM", | 91 | .filename = "pt_nxopt31_HTM", |
| 89 | .coord = &coord_nxopt31, | 92 | .coord = &coord_nxopt31, |
| 90 | .moveset = &moveset_HTM, | 93 | .moveset = &moveset_HTM, |
| 94 | |||
| 95 | .compact = true, | ||
| 96 | .fallback = &pd_drud_sym16_HTM, | ||
| 97 | .fbmod = BINOM8ON4, | ||
| 91 | }; | 98 | }; |
| 92 | 99 | ||
| 93 | PruneData * allpd[NPTABLES] = { | 100 | PruneData * allpd[NPTABLES] = { |
| @@ -100,7 +107,7 @@ PruneData * allpd[NPTABLES] = { | |||
| 100 | &pd_drudfin_noE_sym16_drud, | 107 | &pd_drudfin_noE_sym16_drud, |
| 101 | &pd_htr_drud, | 108 | &pd_htr_drud, |
| 102 | &pd_htrfin_htr, | 109 | &pd_htrfin_htr, |
| 103 | &pd_khuge_HTM, | 110 | /* &pd_khuge_HTM,*/ |
| 104 | &pd_nxopt31_HTM, | 111 | &pd_nxopt31_HTM, |
| 105 | }; | 112 | }; |
| 106 | 113 | ||
| @@ -135,10 +142,9 @@ genptable(PruneData *pd, int nthreads) | |||
| 135 | } | 142 | } |
| 136 | pd->generated = true; | 143 | pd->generated = true; |
| 137 | 144 | ||
| 138 | nchunks = MIN(pd->coord->max/ENTRIES_PER_GROUP, NCHUNKS); | 145 | nchunks = MIN(ptablesize(pd), 100000); |
| 139 | fprintf(stderr, "Cannot load %s, generating it " | 146 | fprintf(stderr, "Cannot load %s, generating it with %d threads\n", |
| 140 | "with %d threads and %d chunks\n", | 147 | pd->filename, nthreads); |
| 141 | pd->filename, nthreads, nchunks); | ||
| 142 | 148 | ||
| 143 | memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); | 149 | memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); |
| 144 | 150 | ||
| @@ -150,16 +156,22 @@ genptable(PruneData *pd, int nthreads) | |||
| 150 | PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", | 156 | PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", |
| 151 | 0, pd->n - oldn, pd->n, pd->coord->max); | 157 | 0, pd->n - oldn, pd->n, pd->coord->max); |
| 152 | oldn = pd->n; | 158 | oldn = pd->n; |
| 159 | pd->count[0] = pd->n; | ||
| 153 | for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { | 160 | for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { |
| 154 | genptable_bfs(pd, d, nthreads, nchunks); | 161 | genptable_bfs(pd, d, nthreads, nchunks); |
| 155 | genptable_fixnasty(pd, d+1); | 162 | genptable_fixnasty(pd, d+1); |
| 156 | fprintf(stderr, "Depth %d done, generated %" | 163 | fprintf(stderr, "Depth %d done, generated %" |
| 157 | PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", | 164 | PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", |
| 158 | d+1, pd->n - oldn, pd->n, pd->coord->max); | 165 | d+1, pd->n - oldn, pd->n, pd->coord->max); |
| 166 | pd->count[d+1] = pd->n - oldn; | ||
| 159 | oldn = pd->n; | 167 | oldn = pd->n; |
| 160 | } | 168 | } |
| 161 | fprintf(stderr, "Pruning table generated!\n"); | 169 | fprintf(stderr, "Pruning table generated!\n"); |
| 162 | 170 | ||
| 171 | genptable_setbase(pd); | ||
| 172 | if (pd->compact) | ||
| 173 | genptable_compress(pd); | ||
| 174 | |||
| 163 | if (!write_ptable_file(pd)) | 175 | if (!write_ptable_file(pd)) |
| 164 | fprintf(stderr, "Error writing ptable file\n"); | 176 | fprintf(stderr, "Error writing ptable file\n"); |
| 165 | } | 177 | } |
| @@ -199,6 +211,27 @@ genptable_bfs(PruneData *pd, int d, int nthreads, int nchunks) | |||
| 199 | } | 211 | } |
| 200 | 212 | ||
| 201 | static void | 213 | static void |
| 214 | genptable_compress(PruneData *pd) | ||
| 215 | { | ||
| 216 | int val; | ||
| 217 | uint64_t i, j; | ||
| 218 | entry_group_t mask, v; | ||
| 219 | |||
| 220 | pd->compact = false; | ||
| 221 | for (i = 0; i < pd->coord->max; i += ENTRIES_PER_GROUP_COMPACT) { | ||
| 222 | mask = 0; | ||
| 223 | for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) { | ||
| 224 | val = ptableval_index(pd, i+j) - pd->base; | ||
| 225 | v = MIN(3, MAX(0, val)); | ||
| 226 | mask |= v << (2*j); | ||
| 227 | } | ||
| 228 | pd->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask; | ||
| 229 | } | ||
| 230 | pd->compact = true; | ||
| 231 | realloc(pd->ptable, sizeof(entry_group_t) * ptablesize(pd)); | ||
| 232 | } | ||
| 233 | |||
| 234 | static void | ||
| 202 | genptable_fixnasty(PruneData *pd, int d) | 235 | genptable_fixnasty(PruneData *pd, int d) |
| 203 | { | 236 | { |
| 204 | uint64_t i; | 237 | uint64_t i; |
| @@ -227,6 +260,22 @@ genptable_fixnasty(PruneData *pd, int d) | |||
| 227 | } | 260 | } |
| 228 | } | 261 | } |
| 229 | 262 | ||
| 263 | static void | ||
| 264 | genptable_setbase(PruneData *pd) | ||
| 265 | { | ||
| 266 | int i; | ||
| 267 | uint64_t sum, newsum; | ||
| 268 | |||
| 269 | pd->base = 0; | ||
| 270 | sum = pd->count[0] + pd->count[1] + pd->count[2]; | ||
| 271 | for (i = 3; i < 16; i++) { | ||
| 272 | newsum = sum + pd->count[i] - pd->count[i-3]; | ||
| 273 | if (newsum > sum) | ||
| 274 | pd->base = i-3; | ||
| 275 | sum = newsum; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 230 | static void * | 279 | static void * |
| 231 | instance_bfs(void *arg) | 280 | instance_bfs(void *arg) |
| 232 | { | 281 | { |
| @@ -276,26 +325,25 @@ instance_bfs(void *arg) | |||
| 276 | void | 325 | void |
| 277 | print_ptable(PruneData *pd) | 326 | print_ptable(PruneData *pd) |
| 278 | { | 327 | { |
| 279 | uint64_t i, a[16]; | 328 | uint64_t i; |
| 280 | |||
| 281 | for (i = 0; i < 16; i++) | ||
| 282 | a[i] = 0; | ||
| 283 | 329 | ||
| 284 | if (!pd->generated) | 330 | if (!pd->generated) |
| 285 | genptable(pd, 1); /* TODO: set default nthreads somewhere */ | 331 | genptable(pd, 1); /* TODO: set default nthreads somewhere */ |
| 286 | |||
| 287 | for (i = 0; i < pd->coord->max; i++) | ||
| 288 | a[ptableval_index(pd, i)]++; | ||
| 289 | 332 | ||
| 290 | fprintf(stderr, "Values for table %s\n", pd->filename); | 333 | printf("Table %s\n", pd->filename); |
| 334 | printf("Base value: %d\n", pd->base); | ||
| 291 | for (i = 0; i < 16; i++) | 335 | for (i = 0; i < 16; i++) |
| 292 | printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, a[i]); | 336 | printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); |
| 293 | } | 337 | } |
| 294 | 338 | ||
| 295 | uint64_t | 339 | uint64_t |
| 296 | ptablesize(PruneData *pd) | 340 | ptablesize(PruneData *pd) |
| 297 | { | 341 | { |
| 298 | return (pd->coord->max + ENTRIES_PER_GROUP - 1) / ENTRIES_PER_GROUP; | 342 | uint64_t e; |
| 343 | |||
| 344 | e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; | ||
| 345 | |||
| 346 | return (pd->coord->max + e - 1) / e; | ||
| 299 | } | 347 | } |
| 300 | 348 | ||
| 301 | static void | 349 | static void |
| @@ -328,9 +376,10 @@ ptableval(PruneData *pd, Cube cube) | |||
| 328 | static int | 376 | static int |
| 329 | ptableval_index(PruneData *pd, uint64_t ind) | 377 | ptableval_index(PruneData *pd, uint64_t ind) |
| 330 | { | 378 | { |
| 331 | int sh; | 379 | int sh, ret; |
| 332 | entry_group_t mask; | 380 | entry_group_t mask; |
| 333 | uint64_t i; | 381 | uint64_t i, e; |
| 382 | entry_group_t m; | ||
| 334 | 383 | ||
| 335 | if (!pd->generated) { | 384 | if (!pd->generated) { |
| 336 | fprintf(stderr, "Warning: request pruning table value" | 385 | fprintf(stderr, "Warning: request pruning table value" |
| @@ -340,11 +389,23 @@ ptableval_index(PruneData *pd, uint64_t ind) | |||
| 340 | genptable(pd, 1); /* TODO: set default or remove this case */ | 389 | genptable(pd, 1); /* TODO: set default or remove this case */ |
| 341 | } | 390 | } |
| 342 | 391 | ||
| 343 | sh = 4 * (ind % ENTRIES_PER_GROUP); | 392 | e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; |
| 344 | mask = ((entry_group_t)15) << sh; | 393 | m = pd->compact ? 3 : 15; |
| 345 | i = ind/ENTRIES_PER_GROUP; | ||
| 346 | 394 | ||
| 347 | return (pd->ptable[i] & mask) >> sh; | 395 | sh = 4 * (ind % e); |
| 396 | mask = m << sh; | ||
| 397 | i = ind/e; | ||
| 398 | |||
| 399 | ret = (pd->ptable[i] & mask) >> sh; | ||
| 400 | |||
| 401 | if (pd->compact) { | ||
| 402 | if (ret) | ||
| 403 | ret += pd->base; | ||
| 404 | else | ||
| 405 | ret = ptableval_index(pd->fallback, ind % pd->fbmod); | ||
| 406 | } | ||
| 407 | |||
| 408 | return ret; | ||
| 348 | } | 409 | } |
| 349 | 410 | ||
| 350 | static bool | 411 | static bool |
| @@ -354,6 +415,7 @@ read_ptable_file(PruneData *pd) | |||
| 354 | 415 | ||
| 355 | FILE *f; | 416 | FILE *f; |
| 356 | char fname[strlen(tabledir)+100]; | 417 | char fname[strlen(tabledir)+100]; |
| 418 | int i; | ||
| 357 | uint64_t r; | 419 | uint64_t r; |
| 358 | 420 | ||
| 359 | strcpy(fname, tabledir); | 421 | strcpy(fname, tabledir); |
| @@ -363,10 +425,14 @@ read_ptable_file(PruneData *pd) | |||
| 363 | if ((f = fopen(fname, "rb")) == NULL) | 425 | if ((f = fopen(fname, "rb")) == NULL) |
| 364 | return false; | 426 | return false; |
| 365 | 427 | ||
| 366 | r = fread(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); | 428 | r = fread(&(pd->base), sizeof(int), 1, f); |
| 429 | for (i = 0; i < 16; i++) | ||
| 430 | r += fread(&(pd->count[i]), sizeof(uint64_t), 1, f); | ||
| 431 | r += fread(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); | ||
| 432 | |||
| 367 | fclose(f); | 433 | fclose(f); |
| 368 | 434 | ||
| 369 | return r == ptablesize(pd); | 435 | return r == 17 + ptablesize(pd); |
| 370 | } | 436 | } |
| 371 | 437 | ||
| 372 | static bool | 438 | static bool |
| @@ -376,7 +442,8 @@ write_ptable_file(PruneData *pd) | |||
| 376 | 442 | ||
| 377 | FILE *f; | 443 | FILE *f; |
| 378 | char fname[strlen(tabledir)+100]; | 444 | char fname[strlen(tabledir)+100]; |
| 379 | uint64_t written; | 445 | int i; |
| 446 | uint64_t w; | ||
| 380 | 447 | ||
| 381 | strcpy(fname, tabledir); | 448 | strcpy(fname, tabledir); |
| 382 | strcat(fname, "/"); | 449 | strcat(fname, "/"); |
| @@ -385,9 +452,12 @@ write_ptable_file(PruneData *pd) | |||
| 385 | if ((f = fopen(fname, "wb")) == NULL) | 452 | if ((f = fopen(fname, "wb")) == NULL) |
| 386 | return false; | 453 | return false; |
| 387 | 454 | ||
| 388 | written = fwrite(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); | 455 | w = fwrite(&(pd->base), sizeof(int), 1, f); |
| 456 | for (i = 0; i < 16; i++) | ||
| 457 | w += fwrite(&(pd->count[i]), sizeof(uint64_t), 1, f); | ||
| 458 | w += fwrite(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); | ||
| 389 | fclose(f); | 459 | fclose(f); |
| 390 | 460 | ||
| 391 | return written == ptablesize(pd); | 461 | return w == 17 + ptablesize(pd); |
| 392 | } | 462 | } |
| 393 | 463 | ||
diff --git a/src/symcoord.c b/src/symcoord.c index 8b0eeb4..cb178b7 100644 --- a/src/symcoord.c +++ b/src/symcoord.c | |||
| @@ -166,8 +166,8 @@ antindex_nxopt31(uint64_t ind) | |||
| 166 | Cube c; | 166 | Cube c; |
| 167 | 167 | ||
| 168 | c = antindex_eofbepos_sym16(ind/(BINOM8ON4*POW3TO7)); | 168 | c = antindex_eofbepos_sym16(ind/(BINOM8ON4*POW3TO7)); |
| 169 | c.cp = coord_cpud_separate.cube((ind/POW3TO7)%BINOM8ON4).cp; | 169 | c.cp = coord_cpud_separate.cube(ind % BINOM8ON4).cp; |
| 170 | c.coud = ind % POW3TO7; | 170 | c.coud = (ind / BINOM8ON4) % POW3TO7; |
| 171 | 171 | ||
| 172 | return c; | 172 | return c; |
| 173 | } | 173 | } |
| @@ -231,9 +231,9 @@ index_nxopt31(Cube cube) | |||
| 231 | 231 | ||
| 232 | t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; | 232 | t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; |
| 233 | c = apply_trans(t, cube); | 233 | c = apply_trans(t, cube); |
| 234 | a = (index_eofbepos_sym16(c)*BINOM8ON4) + coord_cpud_separate.index(c); | 234 | a = (index_eofbepos_sym16(c)*POW3TO7) + c.coud; |
| 235 | 235 | ||
| 236 | return a * POW3TO7 + c.coud; | 236 | return a * BINOM8ON4 + coord_cpud_separate.index(c); |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | static int | 239 | static int |
