1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-01 17:19:36 +00:00

Hash rewrite

This commit is contained in:
Marco Costalba 2016-04-21 22:11:25 +02:00
commit 1073ffb26a
2 changed files with 152 additions and 182 deletions

View file

@ -46,8 +46,6 @@
#define WDLSUFFIX ".rtbw" #define WDLSUFFIX ".rtbw"
#define DTZSUFFIX ".rtbz" #define DTZSUFFIX ".rtbz"
#define WDLDIR "RTBWDIR"
#define DTZDIR "RTBZDIR"
#define TBPIECES 6 #define TBPIECES 6
int Tablebases::MaxCardinality = 0; int Tablebases::MaxCardinality = 0;
@ -153,11 +151,6 @@ struct DTZEntry_pawn {
uint8_t *map; uint8_t *map;
}; };
struct TBHashEntry {
uint64_t key;
struct TBEntry *ptr;
};
struct DTZTableEntry { struct DTZTableEntry {
uint64_t key1; uint64_t key1;
uint64_t key2; uint64_t key2;
@ -355,45 +348,93 @@ const short KK_idx[10][64] = {
} }
}; };
const uint8_t WDL_MAGIC[4] = { 0x71, 0xe8, 0x23, 0x5d }; const uint8_t WDL_MAGIC[] = { 0x71, 0xE8, 0x23, 0x5D };
const uint8_t DTZ_MAGIC[4] = { 0xd7, 0x66, 0x0c, 0xa5 }; const uint8_t DTZ_MAGIC[] = { 0xD7, 0x66, 0x0C, 0xA5 };
const int wdl_to_map[5] = { 1, 3, 0, 2, 0 }; const int wdl_to_map[] = { 1, 3, 0, 2, 0 };
const uint8_t pa_flags[5] = { 8, 0, 0, 0, 4 }; const uint8_t pa_flags[] = { 8, 0, 0, 0, 4 };
const Value WDL_to_value[] = {
-VALUE_MATE + MAX_PLY + 1,
VALUE_DRAW - 2,
VALUE_DRAW,
VALUE_DRAW + 2,
VALUE_MATE - MAX_PLY - 1
};
const int DTZ_ENTRIES = 64;
const int TBMAX_PIECE = 254; const int TBMAX_PIECE = 254;
const int TBMAX_PAWN = 256; const int TBMAX_PAWN = 256;
const int TBHASHBITS = 10;
const int HSHMAX = 5;
const int DTZ_ENTRIES = 64;
const std::string PieceChar = " PNBRQK"; const std::string PieceChar = " PNBRQK";
int TBnum_piece, TBnum_pawn; int TBnum_piece;
int TBnum_pawn;
Mutex TB_mutex;
std::string TBPaths;
TBEntry_piece TB_piece[TBMAX_PIECE]; TBEntry_piece TB_piece[TBMAX_PIECE];
TBEntry_pawn TB_pawn[TBMAX_PAWN]; TBEntry_pawn TB_pawn[TBMAX_PAWN];
Mutex TB_mutex;
TBHashEntry TB_hash[1 << TBHASHBITS][HSHMAX];
DTZTableEntry DTZ_table[DTZ_ENTRIES]; DTZTableEntry DTZ_table[DTZ_ENTRIES];
int Binomial[5][64]; int Binomial[5][64];
int Pawnidx[5][24]; int Pawnidx[5][24];
int Pfactor[5][4]; int Pfactor[5][4];
// TBPaths stores the paths to directories where the .rtbw and .rtbz files can class HashTable {
// be found. Multiple directories are separated by ";" on Windows and by ":"
// on Unix-based operating systems. struct Entry {
// Key key;
// Example: struct TBEntry* ptr;
// C:\tb\wdl345;C:\tb\wdl6;D:\tb\dtz345;D:\tb\dtz6 };
std::string TBPaths;
static const int TBHASHBITS = 10;
static const int HSHMAX = 5;
Entry table[1 << TBHASHBITS][HSHMAX];
public:
TBEntry* operator[](Key key) {
Entry* entry = table[key >> (64 - TBHASHBITS)];
for (int i = 0; i < HSHMAX; i++, entry++)
if (entry->key == key)
return entry->ptr;
return nullptr;
}
void insert(TBEntry* ptr, Key key) {
Entry* entry = table[key >> (64 - TBHASHBITS)];
for (int i = 0; i < HSHMAX; i++, entry++)
if (!entry->ptr) {
entry->key = key;
entry->ptr = ptr;
return;
}
std::cerr << "HSHMAX too low!" << std::endl;
exit(1);
}
void clear() { std::memset(table, 0, sizeof(table)); }
};
HashTable TBHash;
class TBFile : public std::ifstream { class TBFile : public std::ifstream {
std::string fname; std::string fname;
public: public:
// Open the file with the given name found among the TBPaths // Open the file with the given name found among the TBPaths. TBPaths stores
// the paths to directories where the .rtbw and .rtbz files can be found.
// Multiple directories are separated by ";" on Windows and by ":" on
// Unix-based operating systems.
//
// Example:
// C:\tb\wdl345;C:\tb\wdl6;D:\tb\dtz345;D:\tb\dtz6
TBFile(const std::string& f) { TBFile(const std::string& f) {
#ifndef _WIN32 #ifndef _WIN32
@ -413,7 +454,7 @@ public:
} }
} }
// Maps the file to memory. File is closed after mapping // Memory map the file. File is closed after mapping
char* map(uint64_t* mapping) { char* map(uint64_t* mapping) {
assert(is_open()); assert(is_open());
@ -461,9 +502,6 @@ public:
static void unmap(char* data, uint64_t mapping) { static void unmap(char* data, uint64_t mapping) {
if (!data)
return;
#ifndef _WIN32 #ifndef _WIN32
munmap(data, mapping); munmap(data, mapping);
#else #else
@ -473,9 +511,9 @@ public:
} }
}; };
// Given a position, produce a 64-bit material signature key. // Given a position, produce a 64-bit material signature key. If the engine
// If the engine supports such a key, it should equal the engine's key. // supports such a key, it should equal the engine's key.
Key calc_key(Position& pos, bool mirror) Key get_key(Position& pos, bool mirror)
{ {
Key key = 0; Key key = 0;
@ -491,7 +529,7 @@ Key calc_key(Position& pos, bool mirror)
// defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white // defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
// pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black // pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
// pawns, ..., kings. // pawns, ..., kings.
Key calc_key_from_pcs(uint8_t* pcs, bool mirror) Key get_key(uint8_t* pcs, bool mirror)
{ {
Key key = 0; Key key = 0;
@ -503,21 +541,6 @@ Key calc_key_from_pcs(uint8_t* pcs, bool mirror)
return key; return key;
} }
void add_to_hash(TBEntry* ptr, uint64_t key)
{
TBHashEntry* entry = TB_hash[key >> (64 - TBHASHBITS)];
for (int i = 0; i < HSHMAX && entry->ptr; i++, entry++) {}
if (!entry->ptr) {
entry->key = key;
entry->ptr = ptr;
} else {
std::cerr << "HSHMAX too low!" << std::endl;
exit(1);
}
}
void free_wdl_entry(TBEntry_piece* entry) void free_wdl_entry(TBEntry_piece* entry)
{ {
TBFile::unmap(entry->data, entry->mapping); TBFile::unmap(entry->data, entry->mapping);
@ -580,9 +603,6 @@ void init_tb(const std::vector<PieceType>& pieces)
if (num > Tablebases::MaxCardinality) if (num > Tablebases::MaxCardinality)
Tablebases::MaxCardinality = num; Tablebases::MaxCardinality = num;
uint64_t key1 = calc_key_from_pcs(pcs, 0);
uint64_t key2 = calc_key_from_pcs(pcs, 1);
bool hasPawns = pcs[W_PAWN] + pcs[B_PAWN]; bool hasPawns = pcs[W_PAWN] + pcs[B_PAWN];
if (hasPawns) { if (hasPawns) {
@ -627,19 +647,22 @@ void init_tb(const std::vector<PieceType>& pieces)
entry = (TBEntry*)ptr; entry = (TBEntry*)ptr;
} }
Key key1 = get_key(pcs, 0);
Key key2 = get_key(pcs, 1);
entry->key = key1; entry->key = key1;
entry->ready = 0; entry->ready = 0;
entry->num = num; entry->num = num;
entry->symmetric = (key1 == key2); entry->symmetric = (key1 == key2);
entry->has_pawns = hasPawns; entry->has_pawns = hasPawns;
add_to_hash(entry, key1); TBHash.insert(entry, key1);
if (key2 != key1) if (key2 != key1)
add_to_hash(entry, key2); TBHash.insert(entry, key2);
} }
uint64_t encode_piece(TBEntry_piece *ptr, uint8_t *norm, int *pos, int *factor) uint64_t encode_piece(TBEntry_piece* ptr, uint8_t* norm, int* pos, int* factor)
{ {
uint64_t idx; uint64_t idx;
int i, j, m, l, p; int i, j, m, l, p;
@ -1086,10 +1109,10 @@ int init_table_wdl(TBEntry *entry, const std::string& str)
uint8_t *data = (uint8_t *)entry->data; uint8_t *data = (uint8_t *)entry->data;
if (data[0] != WDL_MAGIC[0] || if ( data[0] != WDL_MAGIC[0]
data[1] != WDL_MAGIC[1] || || data[1] != WDL_MAGIC[1]
data[2] != WDL_MAGIC[2] || || data[2] != WDL_MAGIC[2]
data[3] != WDL_MAGIC[3]) { || data[3] != WDL_MAGIC[3]) {
std::cerr << "Corrupted table" << std::endl; std::cerr << "Corrupted table" << std::endl;
TBFile::unmap(entry->data, entry->mapping); TBFile::unmap(entry->data, entry->mapping);
entry->data = 0; entry->data = 0;
@ -1395,32 +1418,26 @@ uint8_t decompress_pairs(PairsData *d, uint64_t idx)
return sympat[3 * sym]; return sympat[3 * sym];
} }
template uint8_t decompress_pairs<true >(PairsData*, uint64_t); uint8_t decompress_pairs(PairsData *d, uint64_t idx)
template uint8_t decompress_pairs<false>(PairsData*, uint64_t); {
const union { uint32_t i; char c[4]; } bint = {0x01020304};
const bool isLittleEndian = (bint.c[0] == 4);
return isLittleEndian ? decompress_pairs<true >(d, idx)
: decompress_pairs<false>(d, idx);
}
void load_dtz_table(const std::string& str, uint64_t key1, uint64_t key2) void load_dtz_table(const std::string& str, uint64_t key1, uint64_t key2)
{ {
int i;
TBEntry *ptr, *ptr3;
TBHashEntry *ptr2;
DTZ_table[0].key1 = key1; DTZ_table[0].key1 = key1;
DTZ_table[0].key2 = key2; DTZ_table[0].key2 = key2;
DTZ_table[0].entry = NULL; DTZ_table[0].entry = NULL;
// find corresponding WDL entry TBEntry* ptr = TBHash[key1];
ptr2 = TB_hash[key1 >> (64 - TBHASHBITS)];
for (i = 0; i < HSHMAX; i++) if (!ptr)
if (ptr2[i].key == key1)
break;
if (i == HSHMAX)
return; return;
ptr = ptr2[i].ptr; TBEntry* ptr3 = (TBEntry*)malloc(ptr->has_pawns
ptr3 = (TBEntry *)malloc(ptr->has_pawns
? sizeof(DTZEntry_pawn) ? sizeof(DTZEntry_pawn)
: sizeof(DTZEntry_piece)); : sizeof(DTZEntry_piece));
@ -1469,55 +1486,24 @@ std::string prt_str(Position& pos, bool mirror)
return s; return s;
} }
bool is_little_endian()
{
union {
int i;
char c[sizeof(int)];
} x;
x.i = 1;
return x.c[0] == 1;
}
uint8_t decompress_pairs(PairsData *d, uint64_t idx)
{
static const bool isLittleEndian = is_little_endian();
return isLittleEndian ? decompress_pairs<true >(d, idx)
: decompress_pairs<false>(d, idx);
}
// probe_wdl_table and probe_dtz_table require similar adaptations.
int probe_wdl_table(Position& pos, int *success) int probe_wdl_table(Position& pos, int *success)
{ {
TBEntry *ptr;
TBHashEntry *ptr2;
uint64_t idx; uint64_t idx;
uint64_t key; int i, res;
int i;
uint8_t res;
int p[TBPIECES]; int p[TBPIECES];
// Obtain the position's material signature key. Key key = pos.material_key();
key = pos.material_key();
// Test for KvK. if (pos.count<ALL_PIECES>(WHITE) + pos.count<ALL_PIECES>(BLACK) == 2)
if (key == (Zobrist::psq[WHITE][KING][0] ^ Zobrist::psq[BLACK][KING][0])) return 0; // KvK
return 0;
ptr2 = TB_hash[key >> (64 - TBHASHBITS)]; TBEntry* ptr = TBHash[key];
for (i = 0; i < HSHMAX; i++) if (!ptr) {
if (ptr2[i].key == key)
break;
if (i == HSHMAX) {
*success = 0; *success = 0;
return 0; return 0;
} }
ptr = ptr2[i].ptr;
if (!ptr->ready) { if (!ptr->ready) {
TB_mutex.lock(); TB_mutex.lock();
@ -1525,7 +1511,7 @@ int probe_wdl_table(Position& pos, int *success)
std::string s = prt_str(pos, ptr->key != key); std::string s = prt_str(pos, ptr->key != key);
if (!init_table_wdl(ptr, s)) { if (!init_table_wdl(ptr, s)) {
ptr2[i].key = 0ULL; // Was ptr2->key = 0ULL; Just leave !ptr->ready condition
*success = 0; *success = 0;
TB_mutex.unlock(); TB_mutex.unlock();
return 0; return 0;
@ -1609,13 +1595,11 @@ int probe_wdl_table(Position& pos, int *success)
int probe_dtz_table(Position& pos, int wdl, int *success) int probe_dtz_table(Position& pos, int wdl, int *success)
{ {
TBEntry *ptr;
uint64_t idx; uint64_t idx;
int i, res; int i, res;
int p[TBPIECES]; int p[TBPIECES];
// Obtain the position's material signature key. Key key = pos.material_key();
uint64_t key = pos.material_key();
if (DTZ_table[0].key1 != key && DTZ_table[0].key2 != key) { if (DTZ_table[0].key1 != key && DTZ_table[0].key2 != key) {
for (i = 1; i < DTZ_ENTRIES; i++) for (i = 1; i < DTZ_ENTRIES; i++)
@ -1630,18 +1614,12 @@ int probe_dtz_table(Position& pos, int wdl, int *success)
DTZ_table[0] = table_entry; DTZ_table[0] = table_entry;
} else { } else {
TBHashEntry *ptr2 = TB_hash[key >> (64 - TBHASHBITS)]; TBEntry* ptr = TBHash[key];
if (!ptr) {
for (i = 0; i < HSHMAX; i++)
if (ptr2[i].key == key)
break;
if (i == HSHMAX) {
*success = 0; *success = 0;
return 0; return 0;
} }
ptr = ptr2[i].ptr;
bool mirror = (ptr->key != key); bool mirror = (ptr->key != key);
std::string s = prt_str(pos, mirror); std::string s = prt_str(pos, mirror);
@ -1651,11 +1629,11 @@ int probe_dtz_table(Position& pos, int wdl, int *success)
for (i = DTZ_ENTRIES - 1; i > 0; i--) for (i = DTZ_ENTRIES - 1; i > 0; i--)
DTZ_table[i] = DTZ_table[i - 1]; DTZ_table[i] = DTZ_table[i - 1];
load_dtz_table(s, calc_key(pos, mirror), calc_key(pos, !mirror)); load_dtz_table(s, get_key(pos, mirror), get_key(pos, !mirror));
} }
} }
ptr = DTZ_table[0].entry; TBEntry* ptr = DTZ_table[0].entry;
if (!ptr) { if (!ptr) {
*success = 0; *success = 0;
@ -1823,7 +1801,7 @@ int probe_ab(Position& pos, int alpha, int beta, int *success)
} // namespace } // namespace
void Tablebases::init(const std::string& path) void Tablebases::init(const std::string& paths)
{ {
for (int i = 0; i < TBnum_piece; i++) for (int i = 0; i < TBnum_piece; i++)
free_wdl_entry(&TB_piece[i]); free_wdl_entry(&TB_piece[i]);
@ -1837,11 +1815,11 @@ void Tablebases::init(const std::string& path)
DTZ_table[i].entry = nullptr; DTZ_table[i].entry = nullptr;
} }
std::memset(TB_hash, 0, sizeof(TB_hash)); TBHash.clear();
TBnum_piece = TBnum_pawn = 0; TBnum_piece = TBnum_pawn = 0;
MaxCardinality = 0; MaxCardinality = 0;
TBPaths = path; TBPaths = paths;
if (TBPaths.empty() || TBPaths == "<empty>") if (TBPaths.empty() || TBPaths == "<empty>")
return; return;
@ -2243,14 +2221,6 @@ static int has_repeated(StateInfo *st)
} }
} }
static Value wdl_to_Value[5] = {
-VALUE_MATE + MAX_PLY + 1,
VALUE_DRAW - 2,
VALUE_DRAW,
VALUE_DRAW + 2,
VALUE_MATE - MAX_PLY - 1
};
// Use the DTZ tables to filter out moves that don't preserve the win or draw. // Use the DTZ tables to filter out moves that don't preserve the win or draw.
// If the position is lost, but DTZ is fairly high, only keep moves that // If the position is lost, but DTZ is fairly high, only keep moves that
// maximise DTZ. // maximise DTZ.
@ -2269,7 +2239,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves, Value&
StateInfo st; StateInfo st;
CheckInfo ci(pos); CheckInfo ci(pos);
// Probe each move. // Probe each move
for (size_t i = 0; i < rootMoves.size(); i++) { for (size_t i = 0; i < rootMoves.size(); i++) {
Move move = rootMoves[i].pv[0]; Move move = rootMoves[i].pv[0];
pos.do_move(move, st, pos.gives_check(move, ci)); pos.do_move(move, st, pos.gives_check(move, ci));
@ -2318,7 +2288,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves, Value&
wdl = (-dtz + cnt50 <= 100) ? -2 : -1; wdl = (-dtz + cnt50 <= 100) ? -2 : -1;
// Determine the score to report to the user. // Determine the score to report to the user.
score = wdl_to_Value[wdl + 2]; score = WDL_to_value[wdl + 2];
// If the position is winning or losing, but too few moves left, adjust the // If the position is winning or losing, but too few moves left, adjust the
// score to show how close it is to winning or losing. // score to show how close it is to winning or losing.
@ -2399,14 +2369,14 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Val
if (!success) if (!success)
return false; return false;
score = wdl_to_Value[wdl + 2]; score = WDL_to_value[wdl + 2];
StateInfo st; StateInfo st;
CheckInfo ci(pos); CheckInfo ci(pos);
int best = -2; int best = -2;
// Probe each move. // Probe each move
for (size_t i = 0; i < rootMoves.size(); i++) { for (size_t i = 0; i < rootMoves.size(); i++) {
Move move = rootMoves[i].pv[0]; Move move = rootMoves[i].pv[0];
pos.do_move(move, st, pos.gives_check(move, ci)); pos.do_move(move, st, pos.gives_check(move, ci));

View file

@ -7,9 +7,9 @@ namespace Tablebases {
extern int MaxCardinality; extern int MaxCardinality;
void init(const std::string& path); void init(const std::string& paths);
int probe_wdl(Position& pos, int *success); int probe_wdl(Position& pos, int* success);
int probe_dtz(Position& pos, int *success); int probe_dtz(Position& pos, int* success);
bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score); bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score); bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);