Skip to content

Commit b505ae2

Browse files
committed
Replace custom Syzygy probing code with the Fathom library
1 parent 52ba99a commit b505ae2

File tree

17 files changed

+437
-2624
lines changed

17 files changed

+437
-2624
lines changed

CMakeLists.txt

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ set(SOURCE_FILES
1616
pawns.cpp pawns.h
1717
search.h search.cpp
1818
pvs.h pvs.cpp
19-
syzygy/tbcore.h
20-
syzygy/tbprobe.h syzygy/tbprobe.cpp syzygy/tbresolve.h syzygy/tbresolve.cpp)
19+
syzygy/tbconfig.h syzygy/tbconfig.cpp syzygy/fathom.h syzygy/fathom.cpp)
2120
set(TEST_FILES testing/runner.cpp testing/util.h testing/util.cpp
2221
testing/test_bb.cpp
2322
testing/test_board.cpp
@@ -34,21 +33,31 @@ set(TEXEL_TUNE_FILES texeltuning/main.cpp
3433
# Add version definitions
3534
add_definitions(-DTOPPLE_VER="${TOPPLE_VERSION}")
3635

37-
# Set up Catch2 unit tests
36+
# Download dependencies
3837
Include(FetchContent)
3938
FetchContent_Declare(
4039
Catch2
4140
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
42-
GIT_TAG v2.13.3)
43-
FetchContent_MakeAvailable(Catch2)
44-
add_executable(ToppleTest ${SOURCE_FILES} ${TEST_FILES})
45-
target_link_libraries(ToppleTest Catch2::Catch2)
46-
target_compile_options(ToppleTest PUBLIC -march=native -O3)
41+
GIT_TAG v2.13.7
42+
)
43+
FetchContent_Declare(
44+
Fathom
45+
GIT_REPOSITORY https://github.com/jdart1/Fathom.git
46+
GIT_TAG 85b69687088a8baf33f911cf0ce31611906fdd12
47+
)
48+
FetchContent_MakeAvailable(Catch2 Fathom)
49+
50+
# Set up Fathom to probe syzygy tablebases
51+
include_directories(syzygy ${fathom_SOURCE_DIR}/src)
52+
list(APPEND SOURCE_FILES ${fathom_SOURCE_DIR}/src/tbprobe.c)
4753

48-
# Add tests to ctest
54+
# Enable unit tests
4955
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib)
5056
include(CTest)
5157
include(Catch)
58+
add_executable(ToppleTest ${SOURCE_FILES} ${TEST_FILES})
59+
target_link_libraries(ToppleTest Catch2::Catch2)
60+
target_compile_options(ToppleTest PUBLIC -march=native -O3)
5261
catch_discover_tests(ToppleTest)
5362

5463
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
@@ -71,24 +80,19 @@ target_compile_options(ToppleTexelTune PUBLIC -DTEXEL_TUNE -O3 -march=native -DN
7180

7281
# Configure the "Release" target
7382
if (CMAKE_BUILD_TYPE STREQUAL "Release")
74-
# Generally building releases for Windows so link everything statically
75-
set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++")
76-
7783
add_custom_target(Release)
7884
add_executable(Topple_${TOPPLE_VERSION}_legacy ${SOURCE_FILES} main.cpp)
7985
target_link_libraries(Topple_${TOPPLE_VERSION}_legacy Threads::Threads)
80-
target_compile_options(Topple_${TOPPLE_VERSION}_legacy PUBLIC -s -mmmx -msse -msse2)
86+
target_compile_options(Topple_${TOPPLE_VERSION}_legacy PUBLIC)
8187
add_dependencies(Release Topple_${TOPPLE_VERSION}_legacy)
8288

8389
add_executable(Topple_${TOPPLE_VERSION}_popcnt ${SOURCE_FILES} main.cpp)
8490
target_link_libraries(Topple_${TOPPLE_VERSION}_popcnt Threads::Threads)
85-
target_compile_options(Topple_${TOPPLE_VERSION}_popcnt PUBLIC -s -mmmx -msse -msse2
86-
-msse3 -mssse3 -msse4.1 -msse4.2 -mpopcnt)
91+
target_compile_options(Topple_${TOPPLE_VERSION}_popcnt PUBLIC -march=nehalem)
8792
add_dependencies(Release Topple_${TOPPLE_VERSION}_popcnt)
8893

8994
add_executable(Topple_${TOPPLE_VERSION}_modern ${SOURCE_FILES} main.cpp)
9095
target_link_libraries(Topple_${TOPPLE_VERSION}_modern Threads::Threads)
91-
target_compile_options(Topple_${TOPPLE_VERSION}_modern PUBLIC -s -mmmx -msse -msse2
92-
-msse3 -mssse3 -msse4.1 -msse4.2 -mpopcnt -mavx -mavx2 -mbmi -mbmi2)
96+
target_compile_options(Topple_${TOPPLE_VERSION}_modern PUBLIC -march=haswell)
9397
add_dependencies(Release Topple_${TOPPLE_VERSION}_modern)
9498
endif ()

eval.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,7 @@ void evaluator_t::prefetch(U64 pawn_hash) {
114114
size_t index = (pawn_hash & pawn_hash_entries);
115115
pawns::structure_t *bucket = pawn_hash_table + index;
116116

117-
#if defined(__GNUC__)
118117
__builtin_prefetch(bucket);
119-
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
120-
_mm_prefetch((char*) bucket, _MM_HINT_T0);
121-
#endif
122118
}
123119

124120
int evaluator_t::evaluate(const board_t &board) {

main.cpp

Lines changed: 4 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
#include "board.h"
88
#include "search.h"
9-
10-
#include "syzygy/tbprobe.h"
9+
#include "fathom.h"
1110

1211
U64 perft(board_t &, int);
1312

@@ -63,7 +62,6 @@ int main(int argc, char *argv[]) {
6362
std::cout << "option name MoveOverhead type spin default 50 min 0 max 10000" << std::endl;
6463
std::cout << "option name Threads type spin default 1 min 1 max 256" << std::endl;
6564
std::cout << "option name SyzygyPath type string default <empty>" << std::endl;
66-
std::cout << "option name SyzygyResolve type spin default 512 min 1 max 1024" << std::endl;
6765
std::cout << "option name Ponder type check default false" << std::endl;
6866

6967
std::cout << "uciok" << std::endl;
@@ -109,13 +107,9 @@ int main(int argc, char *argv[]) {
109107

110108
tb_path = tb_path.substr(1, tb_path.size() - 1);
111109

112-
std::cout << "Looking for tablebases in: " << tb_path << std::endl;
113-
114-
init_tablebases(tb_path.c_str());
115-
} else if (name == "SyzygyResolve") {
116-
std::string value;
117-
iss >> value; // Skip value
118-
iss >> syzygy_resolve;
110+
std::cout << "looking for tablebases in: " << tb_path << std::endl;
111+
init_tb(tb_path);
112+
std::cout << "found " << tb_largest() << " piece tablebases" << std::endl;
119113
} else if (name == "Ponder") {
120114
// Do nothing
121115
} else {
@@ -300,44 +294,6 @@ int main(int argc, char *argv[]) {
300294
} else {
301295
std::cerr << "warn: mirror command received, but no position specified" << std::endl;
302296
}
303-
} else if (cmd == "tbprobe") {
304-
std::string type;
305-
iss >> type;
306-
307-
if (board) {
308-
const std::string cases[5] = {"loss", "blessed_loss", "draw", "cursed_win", "win"};
309-
310-
if (type == "dtz") {
311-
int success;
312-
int dtz = probe_dtz(*board, &success);
313-
314-
if (success) {
315-
int cnt50 = board->now().halfmove_clock;
316-
int wdl = 0;
317-
if (dtz > 0)
318-
wdl = (dtz + cnt50 <= 100) ? 2 : 1;
319-
else if (dtz < 0)
320-
wdl = (-dtz + cnt50 <= 100) ? -2 : -1;
321-
322-
std::cout << "syzygy " << cases[wdl + 2] << " dtz " << dtz << std::endl;
323-
} else {
324-
std::cout << "syzygy failed" << std::endl;
325-
}
326-
} else if (type == "wdl") {
327-
int success;
328-
int wdl = probe_wdl(*board, &success);
329-
330-
if (success) {
331-
std::cout << "syzygy " << cases[wdl + 2] << std::endl;
332-
} else {
333-
std::cout << "syzygy failed" << std::endl;
334-
}
335-
} else {
336-
std::cerr << "warn: unrecognised table type: dtz or wdl?" << std::endl;
337-
}
338-
} else {
339-
std::cerr << "warn: tbprobe command received, but no position specified" << std::endl;
340-
}
341297
} else if (cmd == "print") {
342298
if (board) {
343299
std::cout << *board << std::endl;

pvs.cpp

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#include "pvs.h"
66

7-
#include "syzygy/tbprobe.h"
7+
#include "fathom.h"
88

99
namespace pvs {
1010
struct pv_move_t {
@@ -201,19 +201,21 @@ namespace pvs {
201201

202202
// Probe endgame tablebases
203203
if (ply && board->now().halfmove_clock == 0 && pop_count(board->all()) <= use_tb) {
204-
int success;
205-
int value = probe_wdl(*board, &success);
206-
if (success) {
204+
std::optional<WDL> result = probe_wdl(*board);
205+
if (result) {
207206
tb_hits++;
208-
tt::Bound bound;
209-
if (value < 0) {
207+
208+
WDL wdl = result.value();
209+
tt::Bound bound; int value;
210+
if (wdl == WDL::LOSS || wdl == WDL::BLESSED_LOSS) {
210211
bound = tt::UPPER;
211212
value = -TO_MATE_SCORE(MAX_TB_PLY + ply + 1);
212-
} else if (value > 0) {
213+
} else if (wdl == WDL::WIN || wdl == WDL::CURSED_WIN) {
213214
bound = tt::LOWER;
214215
value = TO_MATE_SCORE(MAX_TB_PLY + ply + 1);
215216
} else {
216217
bound = tt::EXACT;
218+
value = 0;
217219
}
218220

219221
if (bound == tt::EXACT
@@ -392,28 +394,32 @@ namespace pvs {
392394

393395
// Probe endgame tablebases
394396
if (ply && board->now().halfmove_clock == 0 && pop_count(board->all()) <= use_tb) {
395-
int success;
396-
int value = probe_wdl(*board, &success);
397-
if (success) {
397+
std::optional<WDL> result = probe_wdl(*board);
398+
if (result) {
398399
tb_hits++;
399-
tt::Bound bound;
400-
if (value < 0) {
400+
401+
WDL wdl = result.value();
402+
tt::Bound bound; int value;
403+
if (wdl == WDL::LOSS || wdl == WDL::BLESSED_LOSS) {
401404
bound = tt::UPPER;
402405
value = -TO_MATE_SCORE(MAX_TB_PLY + ply + 1);
403-
} else if (value > 0) {
406+
} else if (wdl == WDL::WIN || wdl == WDL::CURSED_WIN) {
404407
bound = tt::LOWER;
405408
value = TO_MATE_SCORE(MAX_TB_PLY + ply + 1);
406409
} else {
407410
bound = tt::EXACT;
411+
value = 0;
408412
}
409413

410414
if (bound == tt::EXACT
411-
|| (bound == tt::LOWER && value >= beta)
412-
|| (bound == tt::UPPER && value <= alpha)) {
413-
tt->save(bound, board->now().hash, MAX_PLY - 1, ply, stack[ply].eval, value,
414-
EMPTY_MOVE);
415+
|| (bound == tt::LOWER && value >= beta)
416+
|| (bound == tt::UPPER && value <= alpha)) {
417+
tt->save(bound, board->now().hash, MAX_PLY, ply, stack[ply].eval, value, EMPTY_MOVE);
415418
return value;
416419
}
420+
421+
if (bound == tt::LOWER) alpha = std::max(alpha, value);
422+
if (bound == tt::UPPER) beta = std::min(beta, value);
417423
}
418424
}
419425

@@ -504,28 +510,31 @@ namespace pvs {
504510

505511
// Probe endgame tablebases
506512
if (ply && board->now().halfmove_clock == 0 && pop_count(board->all()) <= use_tb) {
507-
int success;
508-
int value = probe_wdl(*board, &success);
509-
if (success) {
513+
std::optional<WDL> result = probe_wdl(*board);
514+
if (result) {
510515
tb_hits++;
511-
tt::Bound bound;
512-
if (value < 0) {
516+
517+
WDL wdl = result.value();
518+
tt::Bound bound; int value;
519+
if (wdl == WDL::LOSS || wdl == WDL::BLESSED_LOSS) {
513520
bound = tt::UPPER;
514521
value = -TO_MATE_SCORE(MAX_TB_PLY + ply + 1);
515-
} else if (value > 0) {
522+
} else if (wdl == WDL::WIN || wdl == WDL::CURSED_WIN) {
516523
bound = tt::LOWER;
517524
value = TO_MATE_SCORE(MAX_TB_PLY + ply + 1);
518525
} else {
519526
bound = tt::EXACT;
527+
value = 0;
520528
}
521529

522530
if (bound == tt::EXACT
523-
|| (bound == tt::LOWER && value >= beta)
524-
|| (bound == tt::UPPER && value <= beta - 1)) {
525-
tt->save(bound, board->now().hash, MAX_PLY - 1, ply, stack[ply].eval, value,
526-
EMPTY_MOVE);
531+
|| (bound == tt::LOWER && value >= beta)
532+
|| (bound == tt::UPPER && value <= beta - 1)) {
533+
tt->save(bound, board->now().hash, MAX_PLY, ply, stack[ply].eval, value, EMPTY_MOVE);
527534
return value;
528535
}
536+
537+
if (bound == tt::UPPER) beta = std::min(beta, value);
529538
}
530539
}
531540

search.cpp

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
#include <algorithm>
88

99
#include "search.h"
10-
11-
#include "syzygy/tbprobe.h"
12-
#include "syzygy/tbresolve.h"
10+
#include "fathom.h"
1311

1412
search_t::search_t(tt::hash_t *tt, const processed_params_t &params, int threads, bool silent)
1513
: tt(tt), params(params), limits(nullptr), silent(silent) {
@@ -71,27 +69,15 @@ search_result_t search_t::think(board_t &board, const search_limits_t &search_li
7169
}
7270

7371
// Probe tablebases at root if no root moves specified
74-
int use_tb = TBlargest;
75-
int tb_wdl = 0;
72+
unsigned use_tb = tb_largest();
7673

7774
// the UCI searchmoves option overrides tablebase root move filtering
78-
if (search_limits.search_moves.empty() && pop_count(board.all()) <= TBlargest) {
79-
std::vector<move_t> tb_root_moves = root_probe(board, tb_wdl);
75+
if (search_limits.search_moves.empty() && pop_count(board.all()) <= tb_largest()) {
76+
std::vector<move_t> tb_root_moves = probe_root(board);
8077

8178
if (!tb_root_moves.empty()) {
82-
// DTZ tablebases available: set root moves and don't use tablebases during search.
8379
root_moves = std::move(tb_root_moves);
8480
use_tb = 0;
85-
} else {
86-
tb_root_moves = root_probe_wdl(board, tb_wdl);
87-
88-
if (!tb_root_moves.empty()) {
89-
// WDL tablebases available: set root moves and only use tablebases during search if we're winning.
90-
root_moves = std::move(tb_root_moves);
91-
if (tb_wdl <= 0) {
92-
use_tb = 0;
93-
}
94-
}
9581
}
9682
}
9783

@@ -336,13 +322,7 @@ void search_t::print_stats(board_t &pos, int score, int depth, tt::Bound bound,
336322
// Get an appropriate PV
337323
std::vector<move_t> pv = bound == tt::EXACT ? workers[0]->context.get_current_pv() : workers[0]->context.get_saved_pv();
338324

339-
// Try syzygy resolution
340325
auto sel_depth = size_t(workers[0]->context.get_sel_depth());
341-
if (limits->syzygy_resolve > 0) {
342-
resolve_pv(pos, workers[0]->evaluator, pv, score, limits->syzygy_resolve, aborted);
343-
sel_depth = std::max(pv.size(), sel_depth);
344-
}
345-
346326
std::cout << "info depth " << depth << " seldepth " << sel_depth;
347327

348328
if (score > MINCHECKMATE) {

0 commit comments

Comments
 (0)