/* this contains all the code the the hash tables (transposition tables) The transposition table has 2 levels. The first level is replaced if the new entry has a higher priority than the old entry. The 2nd level is a "always replace" level where entries are placed if they are of lower priority than the first level. */ #include "includes.h" #include "knightcap.h" int hash_hits, hash_misses, hash_shallow; static int bad_updates, good_updates; static unsigned hash_tag=0; extern int mulling; extern struct state *state; #if APLINUX static unsigned num_cells; static unsigned cell; #endif #define PAR_HASH_LEVEL -1 struct hash_entry *hash_table; unsigned hash_table_size; static int initialised; unsigned hts() { return hash_table_size; } void hash_reset_stats(void) { hash_misses = hash_hits = hash_shallow = 0; bad_updates = good_updates = 0; } void hash_reset(void) { if (!initialised) return; if (!hash_table) { init_hash_table(); return; } memset(hash_table, 0, sizeof(hash_table[0])*hash_table_size); lprintf(0,"reset hash table\n"); if (state->move_time > 1) brain_fill_hash(NULL); } void init_hash_table(void) { int size; if (initialised) return; initialised = 1; hash_reset_stats(); do { hash_table_size = (state->hash_table_size * 1024*1024) / sizeof(hash_table[0]); #if HASH_LEVELS hash_table_size &= ~(HASH_LEVELS - 1); #endif size = hash_table_size*sizeof(hash_table[0]); hash_table = (struct hash_entry *)malloc(size); if (!hash_table) { state->hash_table_size--; } } while (!hash_table); printf("hash table size %d MB %d entries\n", state->hash_table_size, hash_table_size); if (!mulling) { hash_reset(); order_reset(); } #if APLINUX num_cells = getncel(); cell = getcid(); #endif } static inline unsigned get_index(Position *b) { unsigned ret; ret = b->hash1 % hash_table_size; #if HASH_LEVELS ret &= ~(HASH_LEVELS - 1); #endif return ret; } int check_hash(Position *b, int depth, Eval testv, Eval *v, Move *move) { struct hash_entry *t; uint32 hashindex = get_index(b); t = &hash_table[hashindex]; #if APLINUX if (depth > PAR_HASH_LEVEL) { int get_flag = 0; int cid = (b->hash1 >> HASH_TABLE_BITS) % num_cells; get(cid, &b->h_entry, sizeof(*t), t, &get_flag, NULL); amcheck(&get_flag, 1); } else { b->h_entry = (*t); } t = &b->h_entry; #endif #if HASH_LEVELS { int j; for (j=0;jhash2 == b->hash2 && t->hash1 == b->hash1) break; if (j == HASH_LEVELS) { if (depth) hash_misses++; return HASH_MISS; } } #else if (t->hash2 != b->hash2 || t->hash1 != b->hash1) { if (depth) hash_misses++; return HASH_MISS; } #endif if (move) { /* even if we get a hash miss we return the move if we have one - it might be a good guess */ move->from = t->from; move->to = t->to; } if (t->depth_high >= depth && t->high.v < testv.v) { if (depth) hash_hits++; (*v) = t->high; return HASH_HIT; } if (t->depth_low >= depth && t->low.v >= testv.v) { if (depth) hash_hits++; (*v) = t->low; return HASH_HIT; } if (depth) hash_shallow++; return HASH_MISS; } struct hash_entry *fetch_hash(Position *b) { struct hash_entry *t; uint32 hashindex; init_hash_table(); hashindex = get_index(b); t = &hash_table[hashindex]; #if HASH_LEVELS { int j; for (j=0;jhash2 == b->hash2 && t->hash1 == b->hash1) break; if (j == HASH_LEVELS) { return NULL; } } #else if (t->hash2 != b->hash2 || t->hash1 != b->hash1) { return 0; } #endif return t; } static inline int maxdepth(struct hash_entry *t) { return imax(t->depth_low, t->depth_high); } void insert_hash(Position *b, int depth, Eval testv, Eval evaluation, Move *move) { int depth0; struct hash_entry *t; uint32 hashindex = get_index(b); int lower = (evaluation.v >= testv.v); /* is this a new lower bound? */ #if APLINUX struct hash_entry *t1; int cid; #endif t = &hash_table[hashindex]; #if APLINUX t1 = t; t = &b->h_entry; #endif if (t[0].move_num || t[1].move_num) { if (t[0].hash1 != b->hash1) return; else { lprintf(0, "overwriting hash entry: %d %d %d/%d depth=%d/%d %08x by: %08x depth=%d\n", t[0].move_num, t[1].move_num, t[0].low.v, t[0].high.v, t[0].depth_low, t[0].depth_high, t[0].hash1, b->hash1, depth); } } /* see if it matches either entry */ if (t[0].hash1 == b->hash1 && t[0].hash2 == b->hash2) { /* we match the deep entry, don't need to do anything */ } else if (t[1].hash1 == b->hash1 && t[1].hash2 == b->hash2) { /* we match the "always" entry. This might refresh the hash tag on the always entry, so check if the always and deep entries need swapping */ if (maxdepth(&t[1]) >= maxdepth(&t[0])) { struct hash_entry tmp; tmp = t[0]; t[0] = t[1]; t[1] = tmp; } else { /* they don't need swapping, just use the "always" entry */ t++; } } else if (t[0].tag == hash_tag && maxdepth(&t[0]) > depth) { /* the deep entry is deeper than the new entry. Use the always entry unless this is a quiesce entry and the always entry isn't */ if (depth == 0 && maxdepth(&t[1]) > 0 && t[1].tag == hash_tag) return; /* put it in the "always replace" slot */ t++; } else { /* replace the deep entry, and move the deep entry to the "always" slot */ t[1] = t[0]; } t->tag = hash_tag; if (t->hash2 != b->hash2 || t->hash1 != b->hash1) { t->depth_low = 0; t->depth_high = 0; t->low = makeeval(b, -INFINITY); t->high = makeeval(b, INFINITY); t->hash1 = b->hash1; t->hash2 = b->hash2; t->from = t->to = A1; } else { #if SAVE_EXTENSIONS if (depth > 2 && depth >= (lower?t->depth_low+1:t->depth_high+1)) { ddprintf(0, "%s %d %d %d %d %d %d %d\n", position_to_ppn(b), t->depth_low, t->depth_high, t->low.v, t->high.v, lower?evaluation.v:t->low.v, lower?t->high.v:evaluation.v, depth); } #endif if (depth < (lower?t->depth_low:t->depth_high)) bad_updates++; else if ((lower?t->depth_low:t->depth_high) > 0) good_updates++; } if (lower) { if (move) { t->from = move->from; t->to = move->to; } depth0 = t->depth_low; t->depth_low = depth; t->low = evaluation; if (t->high.v < t->low.v) { if (depth0 == depth && t->depth_high == depth) { t->high = t->low; } else { t->high = makeeval(b, INFINITY); t->depth_high = 0; } } } else { depth0 = t->depth_high; t->depth_high = depth; t->high = evaluation; if (t->high.v < t->low.v) { if (depth0 == depth && t->depth_low == depth) { t->low = t->high; } else { t->low = makeeval(b, -INFINITY); t->depth_low = 0; } } } #if APLINUX if (depth > PAR_HASH_LEVEL) { cid = (b->hash1 >> HASH_TABLE_BITS) % num_cells; put(cid, t, sizeof(*t), t1, NULL, NULL, 0); } else { (*t1) = (*t); } #endif } void hash_change_tag(int move_num) { static int last_move_num; if (move_num < last_move_num) { hash_reset(); } last_move_num = move_num; hash_tag = (hash_tag % 15) + 1; } char *hashstats(void) { static char ret[30]; sprintf(ret, "h/s/b=%d/%d/%d%%", (100*hash_hits)/(hash_misses+hash_hits+hash_shallow+1), (100*hash_shallow)/(hash_misses+hash_hits+hash_shallow+1), (100*bad_updates)/(good_updates+bad_updates+1)); return ret; } int check_hash2(Position *b, int depth, Eval testv, Eval *v) { struct hash_entry *t; uint32 hashindex = get_index(b); t = &hash_table[hashindex]; #if HASH_LEVELS { int j; for (j=0;jhash2 == b->hash2 && t->hash1 == b->hash1) break; if (j == HASH_LEVELS) { return 0; } } #else if (t->hash2 != b->hash2 || t->hash1 != b->hash1) { return 0; } #endif if (t->depth_high >= depth && t->high.v < testv.v) { if (depth) hash_hits++; (*v) = t->high; return 1; } if (depth) hash_shallow++; return 0; } int ettc_check_hash(Position *b, Move *moves, int num_moves, int depth, Eval testv, Eval *v, Move *m1) { int m; uint32 hash1, hash2; Eval v1; int cutoff = 0; hash1 = b->hash1; hash2 = b->hash2; testv = flip(testv); depth--; for (m=0;mboard[moves[m].from]); if (b->board[moves[m].to]) { remove_hash(b, moves[m].to, b->board[moves[m].to]); } add_hash(b, moves[m].to, b->board[moves[m].from]); b->hash1 ^= 1; if (check_hash2(b, depth, testv, &v1)) { /* now confirm it */ Position b1; b->hash1 = hash1; b->hash2 = hash2; if (!do_move(&b1, b, &moves[m])) continue; if (check_repitition(&b1, 1)) continue; if (check_hash2(&b1, depth, testv, &v1)) { if (!cutoff || (-v1.v) > v->v) { cutoff = 1; (*v) = v1; v->v = -v->v; if (m1) (*m1) = moves[m]; } } } else { b->hash1 = hash1; b->hash2 = hash2; } } return cutoff; } /* return >0 if this move could produce a hash hit, <0 if it can't and =0 if we can't tell */ int hash_ordering(Position *b, Move *move, Eval testv) { uint32 hash1, hash2, hashindex; struct hash_entry *t; hash1 = b->hash1; hash2 = b->hash2; testv = flip(testv); remove_hash(b, move->from, b->board[move->from]); if (b->board[move->to]) { remove_hash(b, move->to, b->board[move->to]); } add_hash(b, move->to, b->board[move->from]); b->hash1 ^= 1; hashindex = get_index(b); t = &hash_table[hashindex]; #if HASH_LEVELS { int j; for (j=0;jhash2 == b->hash2 && t->hash1 == b->hash1) break; if (j == HASH_LEVELS) { b->hash1 = hash1; b->hash2 = hash2; return 0; } } #else if (t->hash2 != b->hash2 || t->hash1 != b->hash1) { b->hash1 = hash1; b->hash2 = hash2; return 0; } #endif b->hash1 = hash1; b->hash2 = hash2; if (t->low.v >= testv.v) { return -(1+((t->low.v - testv.v) / (STATIC_PAWN_VALUE/2))); } if (t->high.v < testv.v) { return 1+((testv.v - t->high.v) / (STATIC_PAWN_VALUE/2)); } return 0; }