Skip to content

Commit

Permalink
Remove global TB variables from search.cpp
Browse files Browse the repository at this point in the history
Follow up cleanup of #4968, removes the global variables from search and
instead uses a dedicated tb config struct.

closes #4982

No functional change
  • Loading branch information
Disservin committed Jan 17, 2024
1 parent 32e46fc commit a5675f1
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 75 deletions.
6 changes: 2 additions & 4 deletions src/bitboard.cpp
Expand Up @@ -44,15 +44,13 @@ Bitboard BishopTable[0x1480]; // To store bishop attacks

void init_magics(PieceType pt, Bitboard table[], Magic magics[]);

}

// Returns the bitboard of target square for the given step
// from the given square. If the step is off the board, returns empty bitboard.
inline Bitboard safe_destination(Square s, int step) {
Bitboard safe_destination(Square s, int step) {
Square to = Square(s + step);
return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
}

}

// Returns an ASCII representation of a bitboard suitable
// to be printed to standard output. Useful for debugging.
Expand Down
73 changes: 8 additions & 65 deletions src/search.cpp
Expand Up @@ -29,7 +29,6 @@
#include <iostream>
#include <utility>

#include "bitboard.h"
#include "evaluate.h"
#include "misc.h"
#include "movegen.h"
Expand All @@ -46,14 +45,6 @@

namespace Stockfish {

namespace Tablebases {

int Cardinality;
bool RootInTB;
bool UseRule50;
Depth ProbeDepth;
}

namespace TB = Tablebases;

using Eval::evaluate;
Expand Down Expand Up @@ -237,7 +228,7 @@ void Search::Worker::start_searching() {
if (bestThread != this)
sync_cout << UCI::pv(*bestThread, main_manager()->tm.elapsed(threads.nodes_searched()),
threads.nodes_searched(), threads.tb_hits(), tt.hashfull(),
TB::RootInTB)
tbConfig.rootInTB)
<< sync_endl;

sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960());
Expand Down Expand Up @@ -379,7 +370,7 @@ void Search::Worker::iterative_deepening() {
&& mainThread->tm.elapsed(threads.nodes_searched()) > 3000)
sync_cout << UCI::pv(*this, mainThread->tm.elapsed(threads.nodes_searched()),
threads.nodes_searched(), threads.tb_hits(), tt.hashfull(),
TB::RootInTB)
tbConfig.rootInTB)
<< sync_endl;

// In case of failing low/high increase aspiration window and
Expand Down Expand Up @@ -414,7 +405,7 @@ void Search::Worker::iterative_deepening() {
|| mainThread->tm.elapsed(threads.nodes_searched()) > 3000))
sync_cout << UCI::pv(*this, mainThread->tm.elapsed(threads.nodes_searched()),
threads.nodes_searched(), threads.tb_hits(), tt.hashfull(),
TB::RootInTB)
tbConfig.rootInTB)
<< sync_endl;
}

Expand Down Expand Up @@ -659,13 +650,13 @@ Value Search::Worker::search(
}

// Step 5. Tablebases probe
if (!rootNode && !excludedMove && TB::Cardinality)
if (!rootNode && !excludedMove && tbConfig.cardinality)
{
int piecesCount = pos.count<ALL_PIECES>();

if (piecesCount <= TB::Cardinality
&& (piecesCount < TB::Cardinality || depth >= TB::ProbeDepth) && pos.rule50_count() == 0
&& !pos.can_castle(ANY_CASTLING))
if (piecesCount <= tbConfig.cardinality
&& (piecesCount < tbConfig.cardinality || depth >= tbConfig.probeDepth)
&& pos.rule50_count() == 0 && !pos.can_castle(ANY_CASTLING))
{
TB::ProbeState err;
TB::WDLScore wdl = Tablebases::probe_wdl(pos, &err);
Expand All @@ -678,7 +669,7 @@ Value Search::Worker::search(
{
thisThread->tbHits.fetch_add(1, std::memory_order_relaxed);

int drawScore = TB::UseRule50 ? 1 : 0;
int drawScore = tbConfig.useRule50 ? 1 : 0;

Value tbValue = VALUE_TB - ss->ply;

Expand Down Expand Up @@ -1962,53 +1953,5 @@ bool RootMove::extract_ponder_from_tt(const TranspositionTable& tt, Position& po
return pv.size() > 1;
}

void Tablebases::rank_root_moves(const OptionsMap& options,
Position& pos,
Search::RootMoves& rootMoves) {

RootInTB = false;
UseRule50 = bool(options["Syzygy50MoveRule"]);
ProbeDepth = int(options["SyzygyProbeDepth"]);
Cardinality = int(options["SyzygyProbeLimit"]);
bool dtz_available = true;

// Tables with fewer pieces than SyzygyProbeLimit are searched with
// ProbeDepth == DEPTH_ZERO
if (Cardinality > MaxCardinality)
{
Cardinality = MaxCardinality;
ProbeDepth = 0;
}

if (Cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
{
// Rank moves using DTZ tables
RootInTB = root_probe(pos, rootMoves, options["Syzygy50MoveRule"]);

if (!RootInTB)
{
// DTZ tables are missing; try to rank moves using WDL tables
dtz_available = false;
RootInTB = root_probe_wdl(pos, rootMoves, options["Syzygy50MoveRule"]);
}
}

if (RootInTB)
{
// Sort moves according to TB rank
std::stable_sort(rootMoves.begin(), rootMoves.end(),
[](const RootMove& a, const RootMove& b) { return a.tbRank > b.tbRank; });

// Probe during search only if DTZ is not available and we are winning
if (dtz_available || rootMoves[0].tbScore <= VALUE_DRAW)
Cardinality = 0;
}
else
{
// Clean up if root_probe() and root_probe_wdl() have failed
for (auto& m : rootMoves)
m.tbRank = 0;
}
}

} // namespace Stockfish
4 changes: 3 additions & 1 deletion src/search.h
Expand Up @@ -29,6 +29,7 @@
#include "misc.h"
#include "movepick.h"
#include "position.h"
#include "syzygy/tbprobe.h"
#include "timeman.h"
#include "types.h"

Expand All @@ -48,7 +49,6 @@ class UCI;

namespace Search {


// Stack struct keeps track of the information we need to remember from nodes
// shallower and deeper in the tree during the search. Each search thread has
// its own array of Stack objects, indexed by the current ply.
Expand Down Expand Up @@ -238,6 +238,8 @@ class Worker {
// The main thread has a SearchManager, the others have a NullSearchManager
std::unique_ptr<ISearchManager> manager;

Tablebases::Config tbConfig;

const OptionsMap& options;
ThreadPool& threads;
TranspositionTable& tt;
Expand Down
59 changes: 58 additions & 1 deletion src/syzygy/tbprobe.cpp
Expand Up @@ -18,7 +18,6 @@

#include "tbprobe.h"

#include <sys/stat.h>
#include <algorithm>
#include <atomic>
#include <cassert>
Expand All @@ -32,6 +31,7 @@
#include <mutex>
#include <sstream>
#include <string_view>
#include <sys/stat.h>
#include <type_traits>
#include <utility>
#include <vector>
Expand All @@ -42,6 +42,7 @@
#include "../position.h"
#include "../search.h"
#include "../types.h"
#include "../ucioption.h"

#ifndef _WIN32
#include <fcntl.h>
Expand Down Expand Up @@ -1680,4 +1681,60 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, boo
return true;
}

Config Tablebases::rank_root_moves(const OptionsMap& options,
Position& pos,
Search::RootMoves& rootMoves) {
Config config;

if (rootMoves.empty())
return config;

config.rootInTB = false;
config.useRule50 = bool(options["Syzygy50MoveRule"]);
config.probeDepth = int(options["SyzygyProbeDepth"]);
config.cardinality = int(options["SyzygyProbeLimit"]);

bool dtz_available = true;

// Tables with fewer pieces than SyzygyProbeLimit are searched with
// probeDepth == DEPTH_ZERO
if (config.cardinality > MaxCardinality)
{
config.cardinality = MaxCardinality;
config.probeDepth = 0;
}

if (config.cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
{
// Rank moves using DTZ tables
config.rootInTB = root_probe(pos, rootMoves, options["Syzygy50MoveRule"]);

if (!config.rootInTB)
{
// DTZ tables are missing; try to rank moves using WDL tables
dtz_available = false;
config.rootInTB = root_probe_wdl(pos, rootMoves, options["Syzygy50MoveRule"]);
}
}

if (config.rootInTB)
{
// Sort moves according to TB rank
std::stable_sort(
rootMoves.begin(), rootMoves.end(),
[](const Search::RootMove& a, const Search::RootMove& b) { return a.tbRank > b.tbRank; });

// Probe during search only if DTZ is not available and we are winning
if (dtz_available || rootMoves[0].tbScore <= VALUE_DRAW)
config.cardinality = 0;
}
else
{
// Clean up if root_probe() and root_probe_wdl() have failed
for (auto& m : rootMoves)
m.tbRank = 0;
}

return config;
}
} // namespace Stockfish
18 changes: 16 additions & 2 deletions src/syzygy/tbprobe.h
Expand Up @@ -20,16 +20,30 @@
#define TBPROBE_H

#include <string>
#include <vector>

#include "../search.h"

namespace Stockfish {
class Position;
class OptionsMap;

using Depth = int;

namespace Search {
struct RootMove;
using RootMoves = std::vector<RootMove>;
}
}

namespace Stockfish::Tablebases {

struct Config {
int cardinality = 0;
bool rootInTB = false;
bool useRule50 = false;
Depth probeDepth = 0;
};

enum WDLScore {
WDLLoss = -2, // Loss
WDLBlessedLoss = -1, // Loss, but draw under 50-move rule
Expand All @@ -54,7 +68,7 @@ WDLScore probe_wdl(Position& pos, ProbeState* result);
int probe_dtz(Position& pos, ProbeState* result);
bool root_probe(Position& pos, Search::RootMoves& rootMoves, bool rule50);
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, bool rule50);
void rank_root_moves(const OptionsMap& options, Position& pos, Search::RootMoves& rootMoves);
Config rank_root_moves(const OptionsMap& options, Position& pos, Search::RootMoves& rootMoves);

} // namespace Stockfish::Tablebases

Expand Down
4 changes: 2 additions & 2 deletions src/thread.cpp
Expand Up @@ -181,8 +181,7 @@ void ThreadPool::start_thinking(const OptionsMap& options,
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
rootMoves.emplace_back(m);

if (!rootMoves.empty())
Tablebases::rank_root_moves(options, pos, rootMoves);
Tablebases::Config tbConfig = Tablebases::rank_root_moves(options, pos, rootMoves);

// After ownership transfer 'states' becomes empty, so if we stop the search
// and call 'go' again without setting a new position states.get() == nullptr.
Expand All @@ -205,6 +204,7 @@ void ThreadPool::start_thinking(const OptionsMap& options,
th->worker->rootMoves = rootMoves;
th->worker->rootPos.set(pos.fen(), pos.is_chess960(), &th->worker->rootState);
th->worker->rootState = setupStates->back();
th->worker->tbConfig = tbConfig;
}

main_thread()->start_searching();
Expand Down

0 comments on commit a5675f1

Please sign in to comment.