Skip to content

Commit

Permalink
store isPV in TT
Browse files Browse the repository at this point in the history
  • Loading branch information
tryingsomestuff committed Jul 11, 2020
1 parent 3b1269c commit d0744cd
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Fathom
Submodule Fathom updated 1 files
+10 −2 src/tbprobe.c
3 changes: 1 addition & 2 deletions Source/com.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ namespace COM {
mode = m_force;
stm = stm_white;
readFEN(startPosition, COM::position);
TT::clearTT();
ThreadPool::instance().clear(); // re-init all threads data
ThreadPool::instance().clearGame(); // re-init all threads data
}

void init() {
Expand Down
16 changes: 10 additions & 6 deletions Source/moveSort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,23 @@ void MoveSorter::computeScore(Move & m)const{
else{
if (isInCheck && from == p.king[C]) s += 10000; // king evasion
if ( isCapture(t) && !isPromotion(t)){
const Piece pp = PieceTools::getPieceType(p,from);
const Piece ppOpp = (t != T_ep) ? PieceTools::getPieceType(p,to) : P_wp;
assert(pp>0);
assert(ppOpp>0);
const EvalScore * const pst = EvalConfig::PST[pp - 1];
const EvalScore * const pstOpp = EvalConfig::PST[ppOpp- 1];
s += ScaleScore(pst[ColorSquarePstHelper<C>(to)] - pst[ColorSquarePstHelper<C>(from)] + pstOpp[ColorSquarePstHelper<~C>(to)],gp);
if ( useSEE && !isInCheck ){
const ScoreType see = context.SEE(p,m);
s += see;
if ( VALIDMOVE(p.lastMove) && isCapture(p.lastMove) && to == Move2To(p.lastMove) ) s += 500; // recapture bonus
if ( VALIDMOVE(p.lastMove) && isCapture(p.lastMove) && to == Move2To(p.lastMove) ) s += 150; // recapture bonus
else if ( see < -80 ) s -= 2*MoveScoring[T_capture]; // too bad capture
}
else{ // MVVLVA
if ( VALIDMOVE(p.lastMove) && isCapture(p.lastMove) && to == Move2To(p.lastMove) ) s += 500; // recapture bonus
else{
const Piece victim = (t != T_ep) ? PieceTools::getPieceType(p,to) : P_wp;
const Piece attacker = PieceTools::getPieceType(p,from);
assert(victim>0); assert(attacker>0);
s += SearchConfig::MvvLvaScores[victim-1][attacker-1]; //[0 400]
s += SearchConfig::MvvLvaScores[ppOpp-1][pp-1]; //[0 400]
}
}
}
Expand All @@ -57,7 +61,7 @@ void MoveSorter::computeScore(Move & m)const{
s += context.getCMHScore(p, from, to, cmhPtr) /3; // +/- HISTORY_MAX = 1000
if ( !isInCheck ){
if ( refutation != INVALIDMOVE && from == Move2To(refutation) && context.SEE_GE(p,m,-80)) s += 1000; // move (safely) leaving threat square from null move search
const EvalScore * const pst = EvalConfig::PST[std::abs(pp) - 1];
const EvalScore * const pst = EvalConfig::PST[std::abs(pp) - 1];
s += ScaleScore(pst[ColorSquarePstHelper<C>(to)] - pst[ColorSquarePstHelper<C>(from)],gp);
}
}
Expand Down
10 changes: 9 additions & 1 deletion Source/searcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,22 @@ void Searcher::clearPawnTT() {
for (unsigned int k = 0; k < ttSizePawn; ++k) tablePawn[k].h = 0;
}

void Searcher::clear(){
void Searcher::clearGame(){
clearPawnTT();
stats.init();
killerT.initKillers();
historyT.initHistory();
counterT.initCounter();
}

void Searcher::clearSearch(){
//clearPawnTT(); // to be used for reproductible results ///@todo verify again
stats.init();
killerT.initKillers();
historyT.initHistory(true);
counterT.initCounter();
}

bool Searcher::getPawnEntry(Hash h, PawnEntry *& pe){
assert(h > 0);
PawnEntry & _e = tablePawn[h&(ttSizePawn-1)];
Expand Down
3 changes: 2 additions & 1 deletion Source/searcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ struct Searcher{

void clearPawnTT();

void clear();
void clearGame();
void clearSearch();

bool getPawnEntry(Hash h, PawnEntry *& pe);

Expand Down
21 changes: 11 additions & 10 deletions Source/searcherDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void Searcher::displayGUI(DepthType depth, DepthType seldepth, ScoreType bestSco
const TimeType ms = std::max((TimeType)1,(TimeType)std::chrono::duration_cast<std::chrono::milliseconds>(now - startTime).count());
getData().datas.times[depth] = ms;
std::stringstream str;
Counter nodeCount = ThreadPool::instance().counter(Stats::sid_nodes) + ThreadPool::instance().counter(Stats::sid_qnodes);
const Counter nodeCount = ThreadPool::instance().counter(Stats::sid_nodes) + ThreadPool::instance().counter(Stats::sid_qnodes);
if (Logging::ct == Logging::CT_xboard) {
str << int(depth) << " " << bestScore << " " << ms / 10 << " " << nodeCount << " ";
if (DynamicConfig::fullXboardOutput) str << (int)seldepth << " " << Counter(nodeCount / (ms / 1000.f) / 1000.) << " " << ThreadPool::instance().counter(Stats::sid_tbHit1) + ThreadPool::instance().counter(Stats::sid_tbHit2);
Expand Down Expand Up @@ -51,21 +51,16 @@ PVList Searcher::search(const Position & p, Move & m, DepthType & d, ScoreType &
Logging::LogIt(Logging::logInfo) << "Search params :" ;
Logging::LogIt(Logging::logInfo) << "requested time " << getCurrentMoveMs() ;
Logging::LogIt(Logging::logInfo) << "requested depth " << (int) d ;
//TT::clearTT(); // to be forced for reproductible results
TT::age();
MoveDifficultyUtil::variability = 1.f;
ThreadPool::instance().clearSearch(); // reset for all other threads !!!
}
else{
Logging::LogIt(Logging::logInfo) << "helper thread waiting ... " << id() ;
while(startLock.load()){;}
Logging::LogIt(Logging::logInfo) << "... go for id " << id() ;
}
//clearPawnTT(); // to be used for reproductible results ///@todo verify again
stats.init();
killerT.initKillers();
historyT.initHistory(true); // to be used for reproductible results :: false but this is a lot weaker, around 30 Elo !!!
counterT.initCounter(); ///@todo verify without ?


stack[p.halfmoves].h = p.h;

DepthType reachedDepth = 0;
Expand Down Expand Up @@ -101,13 +96,16 @@ PVList Searcher::search(const Position & p, Move & m, DepthType & d, ScoreType &

bool fhBreak = false;

const auto maxNodes = TimeMan::maxNodes;
TimeMan::maxNodes = 0; // reset this for depth 1 to be sure to iterate at least once ...

if ( DynamicConfig::level == 0 ){ // random mover
bestScore = randomMover(p,pvOut,isInCheck);
goto pvsout;
}

// only main thread here, stopflag will be triggered anyway for other threads
if ( isMainThread() && DynamicConfig::multiPV == 1 && d > easyMoveDetectionDepth+5
if ( isMainThread() && DynamicConfig::multiPV == 1 && d > easyMoveDetectionDepth+5 && maxNodes == 0
&& currentMoveMs < INFINITETIME && currentMoveMs > 800 && TimeMan::msecUntilNextTC > 0){
// easy move detection (small open window search)
rootScores.clear();
Expand Down Expand Up @@ -140,7 +138,10 @@ PVList Searcher::search(const Position & p, Move & m, DepthType & d, ScoreType &
else{
// delayed other thread start
Logging::LogIt(Logging::logInfo) << "Unlocking other threads";
if ( depth > 1) startLock.store(false);
if ( depth > 1){
TimeMan::maxNodes = maxNodes; // restore real value
startLock.store(false);
}
}
Logging::LogIt(Logging::logInfo) << "Thread " << id() << " searching depth " << (int)depth;
PVList pvLoc;
Expand Down
55 changes: 42 additions & 13 deletions Source/searcherPVS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,30 @@
#include "tools.hpp"
#include "transposition.hpp"

#define PERIODICCHECK 1024ull

// pvs inspired by Xiphos
template< bool pvnode, bool canPrune>
ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, DepthType depth, unsigned int ply, PVList & pv, DepthType & seldepth, bool isInCheck, bool cutNode, const std::vector<MiniMove>* skipMoves){
if (stopFlag) return STOPSCORE;
//if ( TimeMan::maxKNodes>0 && (stats.counters[Stats::sid_nodes] + stats.counters[Stats::sid_qnodes])/1000 > TimeMan::maxKNodes) { stopFlag = true; Logging::LogIt(Logging::logInfo) << "stopFlag triggered (nodes limits) in thread " << id(); } ///@todo nodes per move
if ( (TimeType)std::max(1, (int)std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - startTime).count()) > getCurrentMoveMs() ){ stopFlag = true; Logging::LogIt(Logging::logInfo) << "stopFlag triggered in thread " << id(); }
if ( isMainThread() ){
static int periodicCheck = 0;
if ( periodicCheck == 0 ){
periodicCheck = (TimeMan::maxNodes > 0) ? std::min(TimeMan::maxNodes/PERIODICCHECK,PERIODICCHECK) : PERIODICCHECK;
const Counter nodeCount = ThreadPool::instance().counter(Stats::sid_nodes) + ThreadPool::instance().counter(Stats::sid_qnodes);
if ( TimeMan::maxNodes > 0 && nodeCount > TimeMan::maxNodes) {
stopFlag = true;
Logging::LogIt(Logging::logInfo) << "stopFlag triggered (nodes limits) in thread " << id();
return STOPSCORE;
}
if ( (TimeType)std::max(1, (int)std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - startTime).count()) > getCurrentMoveMs() ){
stopFlag = true;
Logging::LogIt(Logging::logInfo) << "stopFlag triggered in thread " << id();
return STOPSCORE;
}
}
--periodicCheck;
}

EvalData data;
if (ply >= MAX_DEPTH - 1 || depth >= MAX_DEPTH - 1) return eval(p, data, *this);
Expand Down Expand Up @@ -48,19 +66,22 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep

// probe TT
TT::Entry e;
if ( TT::getEntry(*this, p, pHash, depth, e)) { // if depth of TT entry is enough
bool ttDepthOk = TT::getEntry(*this, p, pHash, depth, e);
TT::Bound bound = TT::Bound(e.b & ~TT::B_ttFlag);
if (ttDepthOk) { // if depth of TT entry is enough
if ( !rootnode && !pvnode &&
( (e.b == TT::B_alpha && e.s <= alpha) || (e.b == TT::B_beta && e.s >= beta) || (e.b == TT::B_exact) ) ) {
( (bound == TT::B_alpha && e.s <= alpha) || (bound == TT::B_beta && e.s >= beta) || (bound == TT::B_exact) ) ) {
// increase history bonus of this move
if (!isInCheck && e.m != INVALIDMINIMOVE && Move2Type(e.m) == T_std ) updateTables(*this, p, depth, ply, e.m, e.b, cmhPtr);
if (!isInCheck && e.m != INVALIDMINIMOVE && Move2Type(e.m) == T_std ) updateTables(*this, p, depth, ply, e.m, bound, cmhPtr);
return adjustHashScore(e.s, ply);
}
}
// if entry hash is not null and entry move is valid, this is a valid TT move (we don't care about depth here !)
bool ttHit = e.h != nullHash;
bool validTTmove = ttHit && e.m != INVALIDMINIMOVE;
bool ttPV = pvnode || (validTTmove && (e.b&TT::B_ttFlag));
bool formerPV = ttPV && !pvnode;


#ifdef WITH_SYZYGY
ScoreType tbScore = 0;
if ( !rootnode && withoutSkipMove
Expand Down Expand Up @@ -108,7 +129,7 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep
// if no TT hit yet, we insert an eval without a move here in case of forward pruning (depth is negative, bound is none) ...
if ( !ttHit ) TT::setEntry(*this,pHash,INVALIDMOVE,createHashScore(evalScore,ply),createHashScore(evalScore,ply),TT::B_none,-2);
// if TT hit, we can use its score as a best draft
if ( ttHit && !isInCheck && ((e.b == TT::B_alpha && e.s < evalScore) || (e.b == TT::B_beta && e.s > evalScore) || (e.b == TT::B_exact)) ) evalScore = adjustHashScore(e.s,ply), evalScoreIsHashScore=true;
if ( ttHit && !isInCheck && ((bound == TT::B_alpha && e.s < evalScore) || (bound == TT::B_beta && e.s > evalScore) || (bound == TT::B_exact)) ) evalScore = adjustHashScore(e.s,ply), evalScoreIsHashScore=true;

ScoreType bestScore = -MATE + ply;
MoveList moves;
Expand Down Expand Up @@ -221,7 +242,10 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep
TT::getEntry(*this, p, pHash, 0, e);
ttHit = e.h != nullHash;
validTTmove = ttHit && e.m != INVALIDMINIMOVE;
if ( ttHit && !isInCheck && ((e.b == TT::B_alpha && e.s < evalScore) || (e.b == TT::B_beta && e.s > evalScore) || (e.b == TT::B_exact)) ){
bound = TT::Bound(e.b & ~TT::B_ttFlag);
ttPV = pvnode || (ttHit && (e.b&TT::B_ttFlag));
formerPV = ttPV && !pvnode;
if ( ttHit && !isInCheck && ((bound == TT::B_alpha && e.s < evalScore) || (bound == TT::B_beta && e.s > evalScore) || (bound == TT::B_exact)) ){
evalScore = adjustHashScore(e.s,ply);
evalScoreIsHashScore=true;
marginDepth = std::max(1,depth-(evalScoreIsHashScore?e.d:0)); // a depth that take TT depth into account
Expand Down Expand Up @@ -306,7 +330,7 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep
// threat on queen extension
//if (EXTENDMORE(extension) && pvnode && (p.pieces_const<P_wq>(p.c) && isQuiet && PieceTools::getPieceType(p, Move2From(e.m)) == P_wq && isAttacked(p, BBTools::SquareFromBitBoard(p.pieces_const<P_wq>(p.c)))) && SEE_GE(p, e.m, 0)) ++stats.counters[Stats::sid_queenThreatExtension], ++extension;
// singular move extension
if (EXTENDMORE(extension) && withoutSkipMove && depth >= SearchConfig::singularExtensionDepth && !rootnode && !isMateScore(e.s) && e.b == TT::B_beta && e.d >= depth - 3){
if (EXTENDMORE(extension) && withoutSkipMove && depth >= SearchConfig::singularExtensionDepth && !rootnode && !isMateScore(e.s) && bound == TT::B_beta && e.d >= depth - 3){
const ScoreType betaC = e.s - 2*depth;
PVList sePV;
DepthType seSeldetph = 0;
Expand Down Expand Up @@ -345,7 +369,7 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep
++stats.counters[Stats::sid_ttbeta];
// increase history bonus of this move
if ( !isInCheck && isQuiet /*&& depth > 1*/) updateTables(*this, p, depth + (ttScore > (beta+80)), ply, e.m, TT::B_beta, cmhPtr);
TT::setEntry(*this,pHash,e.m,createHashScore(ttScore,ply),createHashScore(evalScore,ply),TT::B_beta,depth);
TT::setEntry(*this,pHash,e.m,createHashScore(ttScore,ply),createHashScore(evalScore,ply),TT::Bound(TT::B_beta|(ttPV?TT::B_ttFlag:TT::B_none)),depth);
return ttScore;
}
++stats.counters[Stats::sid_ttalpha];
Expand Down Expand Up @@ -463,7 +487,8 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep
// futility
if (futility && isPrunableStdNoCheck) {++stats.counters[Stats::sid_futility]; continue;}
// LMP
if (lmp && isPrunableStdNoCheck && validMoveCount > /*(1+(2*dangerFactor)/SearchConfig::dangerLimitPruning)**/SearchConfig::lmpLimit[improving][depth] + 2*isEmergencyDefence ) {++stats.counters[Stats::sid_lmp]; continue;}
const bool moveCountPruning = validMoveCount > /*(1+(2*dangerFactor)/SearchConfig::dangerLimitPruning)**/SearchConfig::lmpLimit[improving][depth] + 2*isEmergencyDefence;
if (lmp && isPrunableStdNoCheck && moveCountPruning) {++stats.counters[Stats::sid_lmp]; continue;}
// History pruning (with CMH)
if (historyPruning && isPrunableStdNoCheck && Move2Score(*it) < SearchConfig::historyPruningThresholdInit + marginDepth*SearchConfig::historyPruningThresholdDepth) {++stats.counters[Stats::sid_historyPruning]; continue;}
// CMH pruning alone
Expand All @@ -478,15 +503,19 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep
}
// LMR
DepthType reduction = 0;
if (SearchConfig::doLMR && (isReductible && isQuiet ) && depth >= SearchConfig::lmrMinDepth ){
if (SearchConfig::doLMR && depth >= SearchConfig::lmrMinDepth
&& ( (isReductible && isQuiet) /*|| (isPrunableCap && stack[p.halfmoves].eval <= alpha ) || cutNode*/ )
/*&& validMoveCount > 1 + 2*rootnode*/ ){
++stats.counters[Stats::sid_lmr];
reduction += SearchConfig::lmrReduction[std::min((int)depth,MAX_DEPTH-1)][std::min(validMoveCount,MAX_DEPTH)];
// more reduction
reduction += !improving + ttMoveIsCapture;
reduction += (cutNode && evalScore - SearchConfig::failHighReductionThresholdInit[evalScoreIsHashScore] - marginDepth*SearchConfig::failHighReductionThresholdDepth[evalScoreIsHashScore] > beta); ///@todo try without
//reduction += moveCountPruning && !formerPV;
// less reduction
reduction -= /*std::min(2,*/HISTORY_DIV(2 * Move2Score(*it))/*)*/; //history reduction/extension (beware killers and counter are scored above history max)
reduction -= reduction && (pvnode || isDangerRed || !noCheck /*|| ttMoveSingularExt*/ /*|| isEmergencyDefence*/);
//reduction -= ttPV*2;
// never extend more than reduce
if ( extension - reduction > 0 ) reduction = extension;
if ( reduction >= depth - 1 + extension ) reduction = depth - 1 + extension - 1;
Expand Down Expand Up @@ -542,6 +571,6 @@ ScoreType Searcher::pvs(ScoreType alpha, ScoreType beta, const Position & p, Dep
}

if ( validMoveCount==0 ) return (isInCheck || !withoutSkipMove)?-MATE + ply : 0;
TT::setEntry(*this,pHash,bestMove,createHashScore(bestScore,ply),createHashScore(evalScore,ply),hashBound,depth);
TT::setEntry(*this,pHash,bestMove,createHashScore(bestScore,ply),createHashScore(evalScore,ply),TT::Bound(hashBound|(ttPV?TT::B_ttFlag:TT::B_none)),depth);
return bestScore;
}
Loading

0 comments on commit d0744cd

Please sign in to comment.