My Project
hash.c
Go to the documentation of this file.
1
22#include "bit.h"
23#include "hash.h"
24#include "options.h"
25#include "stats.h"
26#include "search.h"
27#include "util.h"
28#include "settings.h"
29
30#include <stdlib.h>
31#include <stdio.h>
32#include <assert.h>
33
35unsigned long long hash_rank[16][256];
36
38unsigned long long hash_move[64][60];
39
42
47{
48 int i, j;
49 Random r;
50
51 random_seed(&r, 0x5DEECE66Dull);
52 for (i = 0; i < 16; ++i)
53 for (j = 0; j < 256; ++j) {
54 do {
55 hash_rank[i][j] = random_get(&r);
56 } while (bit_count(hash_rank[i][j]) < 8);
57 }
58}
59
60
65{
66 int i, j;
67 Random r;
68
69 random_seed(&r, 0x5DEECE66Dull);
70 for (i = 0; i < 64; ++i)
71 for (j = 0; j < 60; ++j) {
72 do {
73 hash_move[i][j] = random_get(&r);
74 } while (bit_count(hash_move[i][j]) < 8);
75 }
76}
77
86void hash_init(HashTable *hash_table, const unsigned long long size)
87{
88 int i, n_way;
89
90 for (n_way = 1; n_way < HASH_N_WAY; n_way <<= 1);
91
92 assert(hash_table != NULL);
93 assert((n_way & -n_way) == n_way);
94
95 info("< init hashtable of %llu entries>\n", size);
96 if (hash_table->hash != NULL) free(hash_table->memory);
97 hash_table->memory = malloc((size + n_way + 1) * sizeof (Hash));
98 if (hash_table->memory == NULL) {
99 fatal_error("hash_init: cannot allocate the hash table\n");
100 }
101
102 if (HASH_ALIGNED) {
103 const size_t alignment = n_way * sizeof (Hash) - 1;
104 hash_table->hash = (Hash*) (((size_t) hash_table->memory + alignment) & ~alignment);
105 hash_table->hash_mask = size - n_way;
106 } else {
107 hash_table->hash = (Hash*) hash_table->memory;
108 hash_table->hash_mask = size - 1;
109 }
110
111 hash_cleanup(hash_table);
112
113 hash_table->n_lock = 256 * MAX(get_cpu_number(), 1);
114 hash_table->lock_mask = hash_table->n_lock - 1;
115 hash_table->n_lock += n_way + 1;
116 hash_table->lock = (HashLock*) malloc(hash_table->n_lock * sizeof (HashLock));
117
118 for (i = 0; i < hash_table->n_lock; ++i) spin_init(hash_table->lock + i);
119}
120
127void hash_cleanup(HashTable *hash_table)
128{
129 register unsigned int i;
130
131 assert(hash_table != NULL && hash_table->hash != NULL);
132
133 info("< cleaning hashtable >\n");
134 for (i = 0; i <= hash_table->hash_mask + HASH_N_WAY; ++i) {
135 HASH_COLLISIONS(hash_table->hash[i].key = 0;)
136 hash_table->hash[i].board.player = hash_table->hash[i].board.opponent = 0;
137 hash_table->hash[i].data = HASH_DATA_INIT;
138 }
139 hash_table->date = 0;
140}
141
148void hash_clear(HashTable *hash_table)
149{
150 assert(hash_table != NULL);
151
152 if (hash_table->date == 127) hash_cleanup(hash_table);
153 ++hash_table->date;
154 info("< clearing hashtable -> date = %d>\n", hash_table->date);
155 assert(hash_table->date > 0 && hash_table->date <= 127);
156}
157
164void hash_free(HashTable *hash_table)
165{
166 int i;
167 assert(hash_table != NULL && hash_table->hash != NULL);
168 free(hash_table->memory);
169 hash_table->hash = NULL;
170 for (i = 0; i < hash_table->n_lock; ++i) spin_free(hash_table->lock + i);
171 free(hash_table->lock);
172}
173
180inline unsigned int writeable_level(HashData *data)
181{
182 if (USE_TYPE_PUNING) { // HACK: depends on little endian.
183 return (*(unsigned int*) data);
184 } else { // slow but more portable implementation.
185 return (((unsigned)data->date) << 24) + (((unsigned)data->cost) << 16) + (data->selectivity << 8) + data->depth;
186 }
187}
188
202static void data_update(HashData *data, const int cost, const int alpha, const int beta, const int score, const int move)
203{
204 if (score < beta && score < data->upper) data->upper = (signed char) score;
205 if (score > alpha && score > data->lower) data->lower = (signed char) score;
206 if ((score > alpha || score == SCORE_MIN) && data->move[0] != move) {
207 data->move[1] = data->move[0];
208 data->move[0] = (unsigned char) move;
209 }
210 data->cost = (unsigned char) MAX(cost, data->cost);
212}
213
229static void data_upgrade(HashData *data, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
230{
231 if (score < beta) data->upper = (signed char) score; else data->upper = SCORE_MAX;
232 if (score > alpha) data->lower =(signed char) score; else data->lower = SCORE_MIN;
233 if ((score > alpha || score == SCORE_MIN) && data->move[0] != move) {
234 data->move[1] = data->move[0];
235 data->move[0] = (unsigned char) move;
236 }
237 data->depth = depth;
238 data->selectivity = selectivity;
239 data->cost = (unsigned char) MAX(cost, data->cost); // this may not work well in parallel search.
241
242 assert(data->upper >= data->lower);
243}
244
258static void data_new(HashData *data, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
259{
260 if (score < beta) data->upper = (signed char) score; else data->upper = SCORE_MAX;
261 if (score > alpha) data->lower = (signed char) score; else data->lower = SCORE_MIN;
262 if (score > alpha || score == SCORE_MIN) data->move[0] = (unsigned char) move;
263 else data->move[0] = NOMOVE;
264 data->move[1] = NOMOVE;
265 data->depth = depth;
266 data->selectivity = selectivity;
267 data->cost = cost;
268 data->date = date;
269 assert(data->upper >= data->lower);
270}
271
292#if (HASH_COLLISIONS(1)+0)
293static void hash_new(Hash *hash, HashLock *lock, const unsigned long long hash_code, const Board* board, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
294#else
295static void hash_new(Hash *hash, HashLock *lock, const Board* board, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
296#endif
297{
298 spin_lock(lock);
299 HASH_STATS(if (date == hash->data.date) ++statistics.n_hash_remove;)
301 HASH_COLLISIONS(hash->key = hash_code;)
302 hash->board = *board;
303 data_new(&hash->data, date, depth, selectivity, cost, alpha, beta, score, move);
304 spin_unlock(lock);
305}
306
326#if (HASH_COLLISIONS(1)+0)
327static void hash_set(Hash *hash, HashLock *lock, const unsigned long long hash_code, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int lower, const int upper, const int move)
328#else
329static void hash_set(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int lower, const int upper, const int move)
330#endif
331{
332 spin_lock(lock);
333 HASH_STATS(if (date == hash->data.date) ++statistics.n_hash_remove;)
335 HASH_COLLISIONS(hash->key = hash_code;)
336 hash->board = *board;
337 hash->data.upper = (signed char) upper;
338 hash->data.lower = (signed char) lower;
339 hash->data.move[0] = (unsigned char) move;
340 hash->data.move[1] = NOMOVE;
341 hash->data.depth = (unsigned char) depth;
342 hash->data.selectivity = (unsigned char) selectivity;
343 hash->data.cost = (unsigned char) cost;
344 hash->data.date = (unsigned char) date;
345 assert(hash->data.upper >= hash->data.lower);
346 spin_unlock(lock);
347}
348
349
371static bool hash_update(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
372{
373 bool ok = false;
374 HashData *data;
375
376 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
377 spin_lock(lock);
378 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
379 data = &hash->data;
380 if (data->selectivity == selectivity && data->depth == depth) data_update(data, cost, alpha, beta, score, move);
381 else data_upgrade(data, depth, selectivity, cost, alpha, beta, score, move);
382 data->date = (unsigned char) date;
383 if (data->lower > data->upper) { // reset the hash-table...
384 data_new(data, date, depth, selectivity, cost, alpha, beta, score, move);
385 }
386 ok = true;
387 }
388 spin_unlock(lock);
389 }
390 return ok;
391}
392
414static bool hash_replace(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
415{
416 bool ok = false;
417
418 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
419 spin_lock(lock);
420 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
421 data_new(&hash->data, date, depth, selectivity, cost, alpha, beta, score, move);
422 ok = true;
423 }
424 spin_unlock(lock);
425 }
426 return ok;
427}
428
442static bool hash_reset(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int lower, const int upper, const int move)
443{
444 bool ok = false;
445 HashData *data;
446
447 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
448 spin_lock(lock);
449 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
450 data = &hash->data;
451 if (data->selectivity == selectivity && data->depth == depth) {
452 if (data->lower < lower) data->lower = (signed char) lower;
453 if (data->upper > upper) data->upper = (signed char) upper;
454 } else {
455 data->depth = (unsigned char) depth;
456 data->selectivity = (unsigned char) selectivity;
457 data->lower = (signed char) lower;
458 data->upper = (signed char) upper;
459 }
460 data->cost = 0;
461 data->date = (unsigned char) date;
462 if (move != NOMOVE) {
463 if (data->move[0] != move) {
464 data->move[1] = data->move[0];
465 data->move[0] = (unsigned char) move;
466 } else {
467 data->move[1] = (unsigned char) move;
468 }
469 }
470 ok = true;
471 }
472 spin_unlock(lock);
473 }
474 return ok;
475}
476
477
489void hash_feed(HashTable *hash_table, const Board *board, const unsigned long long hash_code, const int depth, const int selectivity, const int lower, const int upper, const int move)
490{
491 Hash *hash, *worst;
492 HashLock *lock;
493 int i;
494 int date = hash_table->date ? hash_table->date : 1;
495
496 worst = hash = hash_table->hash + (hash_code & hash_table->hash_mask);
497 lock = hash_table->lock + (hash_code & hash_table->lock_mask);
498 if (hash_reset(hash, lock, board, date, depth, selectivity, lower, upper, move)) return;
499
500 for (i = 1; i < HASH_N_WAY; ++i) {
501 ++hash;
502 if (hash_reset(hash, lock, board, date, depth, selectivity, lower, upper, move)) return;
503 if (writeable_level(&worst->data) > writeable_level(&hash->data)) {
504 worst = hash;
505 }
506 }
507
508 // new entry
509#if (HASH_COLLISIONS(1)+0)
510 hash_set(worst, lock, hash_code, board, date, depth, selectivity, 0, lower, upper, move);
511#else
512 hash_set(worst, lock, board, date, depth, selectivity, 0, lower, upper, move);
513#endif
514}
515
544void hash_store(HashTable *hash_table, const Board *board, const unsigned long long hash_code, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
545{
546 register int i;
547 Hash *worst, *hash;
548 HashLock *lock;
549
550 worst = hash = hash_table->hash + (hash_code & hash_table->hash_mask);
551 lock = hash_table->lock + (hash_code & hash_table->lock_mask);
552 if (hash_update(hash, lock, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move)) return;
553
554 for (i = 1; i < HASH_N_WAY; ++i) {
555 ++hash;
556 if (hash_update(hash, lock, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move)) return;
557 if (writeable_level(&worst->data) > writeable_level(&hash->data)) {
558 worst = hash;
559 }
560 }
561#if (HASH_COLLISIONS(1)+0)
562 hash_new(worst, lock, hash_code, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move);
563#else
564 hash_new(worst, lock, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move);
565#endif
566}
567
583void hash_force(HashTable *hash_table, const Board *board, const unsigned long long hash_code, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
584{
585 register int i;
586 Hash *worst, *hash;
587 HashLock *lock;
588
589 worst = hash = hash_table->hash + (hash_code & hash_table->hash_mask);
590 lock = hash_table->lock + (hash_code & hash_table->lock_mask);
591 if (hash_replace(hash, lock, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move)) return;
592
593 for (i = 1; i < HASH_N_WAY; ++i) {
594 ++hash;
595 if (hash_replace(hash, lock, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move)) return;
596 if (writeable_level(&worst->data) > writeable_level(&hash->data)) {
597 worst = hash;
598 }
599 }
600
601#if (HASH_COLLISIONS(1)+0)
602 hash_new(worst, lock, hash_code, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move);
603#else
604 hash_new(worst, lock, board, hash_table->date, depth, selectivity, cost, alpha, beta, score, move);
605#endif
606}
607
616bool hash_get(HashTable *hash_table, const Board *board, const unsigned long long hash_code, HashData *data)
617{
618 register int i;
619 Hash *hash;
620 HashLock *lock;
621 bool ok = false;
622
625 hash = hash_table->hash + (hash_code & hash_table->hash_mask);
626 lock = hash_table->lock + (hash_code & hash_table->lock_mask);
627 for (i = 0; i < HASH_N_WAY; ++i) {
628 HASH_COLLISIONS(if (hash->key == hash_code) {)
629 HASH_COLLISIONS( spin_lock(lock);)
630 HASH_COLLISIONS( if (hash->key == hash_code && (hash->board.player != board->player || hash->board.opponent != board->opponent)) {)
631 HASH_COLLISIONS( ++statistics.n_hash_collision;)
632 HASH_COLLISIONS( printf("key = %llu\n", hash_code);)
633 HASH_COLLISIONS( board_print(board, WHITE, stdout);)
634 HASH_COLLISIONS( board_print(&hash->board, WHITE, stdout);)
635 HASH_COLLISIONS( })
636 HASH_COLLISIONS( spin_unlock(lock);)
638 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
639 spin_lock(lock);
640 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
641 *data = hash->data;
643 hash->data.date = hash_table->date;
644 ok = true;
645 }
646 spin_unlock(lock);
647 if (ok) return true;
648 }
649 ++hash;
650 }
651 *data = HASH_DATA_INIT;
652 return false;
653}
654
662void hash_exclude_move(HashTable *hash_table, const Board *board, const unsigned long long hash_code, const int move)
663{
664 register int i;
665 Hash *hash;
666 HashLock *lock;
667
668 hash = hash_table->hash + (hash_code & hash_table->hash_mask);
669 lock = hash_table->lock + (hash_code & hash_table->lock_mask);
670 for (i = 0; i < HASH_N_WAY; ++i) {
671 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
672 spin_lock(lock);
673 if (hash->board.player == board->player && hash->board.opponent == board->opponent) {
674 if (hash->data.move[0] == move) {
675 hash->data.move[0] = hash->data.move[1];
676 hash->data.move[1] = NOMOVE;
677 } else if (hash->data.move[1] == move) {
678 hash->data.move[1] = NOMOVE;
679 }
680 hash->data.lower = SCORE_MIN;
681 }
682 spin_unlock(lock);
683 return;
684 }
685 ++hash;
686 }
687}
688
695void hash_copy(const HashTable *src, HashTable *dest)
696{
697 register unsigned int i;
698
699 assert(src->hash_mask == dest->hash_mask);
700 info("<hash copy>\n");
701 for (i = 0; i <= src->hash_mask + HASH_N_WAY; ++i) {
702 dest->hash[i] = src->hash[i];
703 }
704 dest->date = src->date;
705}
706
713void hash_print(const HashData *data, FILE *f)
714{
715 char s_move[4];
716 int p_selectivity[] = {72, 87, 95, 98, 99, 100};
717
718 fprintf(f, "moves = %s, ", move_to_string(data->move[0], WHITE, s_move));
719 fprintf(f, "%s ; ", move_to_string(data->move[1], WHITE, s_move));
720 fprintf(f, "score = [%+02d, %+02d] ; ", data->lower, data->upper);
721 fprintf(f, "level = %2d:%2d:%2d@%3d%%", data->date, data->cost, data->depth, p_selectivity[data->selectivity]);
722}
723
DLL_API int bit_count(unsigned long long b)
Count the number of bits set to one in an unsigned long long.
Definition bit.c:72
#define SCORE_MAX
Definition const.h:58
#define SCORE_INF
Definition const.h:52
@ NOMOVE
Definition const.h:37
@ WHITE
Definition const.h:43
#define SCORE_MIN
Definition const.h:55
void hash_exclude_move(HashTable *hash_table, const unsigned long long hash_code, const int move)
Erase an hash table entry.
Definition hash-lock-free.c:629
void hash_print(const HashData *data, FILE *f)
print HashData content.
Definition hash-lock-free.c:670
void hash_copy(const HashTable *src, HashTable *dest)
Copy an hastable to another one.
Definition hash-lock-free.c:652
static bool hash_reset(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int lower, const int upper, const int move)
Reset an hash entry from new data values.
Definition hash.c:442
bool hash_get(HashTable *hash_table, const Board *board, const unsigned long long hash_code, HashData *data)
Find an hash table entry according to the evaluated board hash codes.
Definition hash.c:616
unsigned long long hash_rank[16][256]
Definition hash.c:35
static bool hash_update(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
update the hash entry
Definition hash.c:371
static void data_new(HashData *data, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
Set an hash table data item.
Definition hash.c:258
static bool hash_replace(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
replace the hash entry.
Definition hash.c:414
static void data_update(HashData *data, const int cost, const int alpha, const int beta, const int score, const int move)
update an hash table item.
Definition hash.c:202
static void hash_set(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int lower, const int upper, const int move)
Set a new hash table item.
Definition hash.c:329
static void data_upgrade(HashData *data, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
Upgrade an hash table data item.
Definition hash.c:229
void hash_clear(HashTable *hash_table)
Clear the hashtable.
Definition hash.c:148
void hash_store(HashTable *hash_table, const Board *board, const unsigned long long hash_code, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
Store an hashtable item.
Definition hash.c:544
void hash_force(HashTable *hash_table, const Board *board, const unsigned long long hash_code, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
Store an hashtable item.
Definition hash.c:583
void hash_init(HashTable *hash_table, const unsigned long long size)
Initialise the hashtable.
Definition hash.c:86
unsigned int writeable_level(HashData *data)
make a level from date, cost, depth & selectivity.
Definition hash.c:180
void hash_cleanup(HashTable *hash_table)
Clear the hashtable.
Definition hash.c:127
void hash_move_init(void)
Initialize global hash move data.
Definition hash.c:64
const HashData HASH_DATA_INIT
Definition hash.c:41
unsigned long long hash_move[64][60]
Definition hash.c:38
void hash_free(HashTable *hash_table)
Free the hashtable.
Definition hash.c:164
static void hash_new(Hash *hash, HashLock *lock, const Board *board, const int date, const int depth, const int selectivity, const int cost, const int alpha, const int beta, const int score, const int move)
Initialize a new hash table item.
Definition hash.c:295
void hash_feed(HashTable *hash_table, const Board *board, const unsigned long long hash_code, const int depth, const int selectivity, const int lower, const int upper, const int move)
feed hash table (from Cassio).
Definition hash.c:489
void hash_code_init(void)
Initialize global hash code data.
Definition hash.c:46
struct Hash Hash
char * move_to_string(const int x, const int player, char *s)
Print out a move.
Definition move.c:76
#define USE_TYPE_PUNING
Definition settings.h:69
#define HASH_N_WAY
Definition settings.h:74
#define HASH_ALIGNED
Definition settings.h:77
Statistics statistics
Definition stats.c:21
Statistics header.
#define HASH_COLLISIONS(x)
Definition stats.h:25
#define HASH_STATS(x)
Definition stats.h:23
Definition board.h:26
unsigned long long player
Definition board.h:27
unsigned long long opponent
Definition board.h:27
Definition hash.h:24
unsigned char move[2]
Definition hash.h:31
signed char lower
Definition hash.h:29
unsigned char cost
Definition hash.h:27
unsigned char date
Definition hash.h:28
signed char upper
Definition hash.h:30
unsigned char selectivity
Definition hash.h:26
unsigned char depth
Definition hash.h:25
Definition hash.h:42
Definition hash.h:47
unsigned char date
Definition hash.h:55
unsigned int lock_mask
Definition hash.h:52
Hash * hash
Definition hash.h:49
unsigned long long hash_mask
Definition hash.h:51
HashLock * lock
Definition hash.h:50
void * memory
Definition hash.h:48
int n_lock
Definition hash.h:54
Definition hash.h:35
HashData data
Definition hash.h:38
Board board
Definition hash.h:37
Definition util.h:87
unsigned long long n_hash_found
Definition stats.h:72
unsigned long long n_hash_upgrade
Definition stats.h:68
unsigned long long n_hash_n
Definition stats.h:74
unsigned long long n_hash_search
Definition stats.h:71
unsigned long long n_hash_update
Definition stats.h:67
unsigned long long n_hash_new
Definition stats.h:69
unsigned long long n_hash_remove
Definition stats.h:70
int get_cpu_number(void)
Get the number of cpus or cores on the machine.
Definition util.c:987
unsigned long long random_get(Random *random)
Pseudo-random number generator.
Definition util.c:1043
void random_seed(Random *random, const unsigned long long seed)
Pseudo-random number seed.
Definition util.c:1062
Miscellaneous utilities header.
#define fatal_error(...)
Display an error message as "FATAL_ERROR : file name : function name : line number : ....
Definition util.h:349
#define info(...)
Display a message.
Definition util.h:382
#define MAX(a, b)
Definition util.h:98