Skip to content

Commit

Permalink
Add verification search to NMP (#524)
Browse files Browse the repository at this point in the history
Bench: 2542136

Implemented as-is from SF.

Elo | -0.68 +- 1.34 (95%)
SPRT | 6.0+0.06s Threads=1 Hash=8MB
LLR | 0.31 (-2.94, 2.94) [-2.50, 0.50]
Games | N: 126616 W: 31109 L: 31356 D: 64151
http://chess.grantnet.us/test/33902/

Elo | -0.24 +- 2.57 (95%)
SPRT | 40.0+0.40s Threads=1 Hash=64MB
LLR | 0.61 (-2.94, 2.94) [-2.50, 0.50]
Games | N: 33352 W: 7938 L: 7961 D: 17453
http://chess.grantnet.us/test/33911/
  • Loading branch information
jhonnold committed Nov 9, 2023
1 parent 4361a92 commit accb7d6
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 22 deletions.
12 changes: 0 additions & 12 deletions src/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,18 +238,6 @@ void PrintBoard(Board* board) {
printf("\nFEN: %s\n\n", fenBuffer);
}

inline int HasNonPawn(Board* board) {
return BitCount(OccBB(board->stm) ^ PieceBB(KING, board->stm) ^ PieceBB(PAWN, board->stm));
}

inline int IsOCB(Board* board) {
BitBoard nonBishopMaterial = PieceBB(QUEEN, WHITE) | PieceBB(QUEEN, BLACK) | PieceBB(ROOK, WHITE) |
PieceBB(ROOK, BLACK) | PieceBB(KNIGHT, WHITE) | PieceBB(KNIGHT, BLACK);

return !nonBishopMaterial && BitCount(PieceBB(BISHOP, WHITE)) == 1 && BitCount(PieceBB(BISHOP, BLACK)) == 1 &&
BitCount((PieceBB(BISHOP, WHITE) | PieceBB(BISHOP, BLACK)) & DARK_SQS) == 1;
}

// Special pieces are those giving check, and those that are pinned
// these must be recalculated every move for faster move legality purposes
inline void SetSpecialPieces(Board* board) {
Expand Down
6 changes: 4 additions & 2 deletions src/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ int IsRepetition(Board* board, int ply);
int IsMaterialDraw(Board* board);
int IsFiftyMoveRule(Board* board);

int HasNonPawn(Board* board);

void MakeNullMove(Board* board);
void UndoNullMove(Board* board);
void MakeMove(Move move, Board* board);
Expand All @@ -68,6 +66,10 @@ int IsLegal(Move move, Board* board);
void InitCuckoo();
int HasCycle(Board* board, int ply);

INLINE int HasNonPawn(Board* board, const int color) {
return !!(OccBB(color) ^ PieceBB(KING, color) ^ PieceBB(PAWN, color));
}

INLINE int MoveRequiresRefresh(int piece, int from, int to) {
if (PieceType(piece) != KING)
return 0;
Expand Down
2 changes: 1 addition & 1 deletion src/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
EXE = berserk
SRC = *.c nn/*.c pyrrhic/tbprobe.c
CC = gcc
VERSION = 20231108
VERSION = 20231108b
MAIN_NETWORK = berserk-8d34b8587772.nn
EVALFILE = $(MAIN_NETWORK)
DEFS = -DVERSION=\"$(VERSION)\" -DEVALFILE=\"$(EVALFILE)\" -DNDEBUG
Expand Down
26 changes: 20 additions & 6 deletions src/search.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,8 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
// i.e. Our position is so good we can give our opponnent a free move and
// they still can't catch up (this is usually countered by captures or mate
// threats)
if (depth >= 4 && (ss - 1)->move != NULL_MOVE && !ss->skip && eval >= beta &&
// weiss conditional
HasNonPawn(board) > (depth > 12)) {
if (depth >= 4 && (ss - 1)->move != NULL_MOVE && !ss->skip && eval >= beta && HasNonPawn(board, board->stm) &&
(ss->ply >= thread->nmpMinPly || board->stm != thread->npmColor)) {
int R = 5 + 221 * depth / 1024 + Min(5 * (eval - beta) / 1024, 4) + !board->easyCapture;
R = Min(depth, R); // don't go too low

Expand All @@ -502,8 +501,23 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*

UndoNullMove(board);

if (score >= beta)
return score < TB_WIN_BOUND ? score : beta;
if (score >= beta) {
if (score >= TB_WIN_BOUND)
score = beta;

if (thread->nmpMinPly || (abs(beta) < TB_WIN_BOUND && depth < 14))
return score;

thread->nmpMinPly = ss->ply + 3 * (depth - R) / 4;
thread->npmColor = board->stm;

Score verify = Negamax(beta - 1, beta, depth - R, 0, thread, pv, ss);

thread->nmpMinPly = 0;

if (verify >= beta)
return score;
}
}

// Prob cut
Expand Down Expand Up @@ -559,7 +573,7 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
int history = GetHistory(ss, thread, move);

int R = LMR[Min(depth, 63)][Min(legalMoves, 63)];
R -= history / 8192; // adjust reduction based on historical score
R -= history / 8192; // adjust reduction based on historical score
R += (IsCap(hashMove) || IsPromo(hashMove)); // increase reduction if hash move is noisy

if (bestScore > -TB_WIN_BOUND) {
Expand Down
5 changes: 4 additions & 1 deletion src/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ void* ThreadInit(void* arg) {

// Alloc all the necessary accumulators
thread->accumulators = (Accumulator*) AlignedMalloc(sizeof(Accumulator) * (MAX_SEARCH_PLY + 1), alignment);
thread->refreshTable = (AccumulatorKingState*) AlignedMalloc(sizeof(AccumulatorKingState) * 2 * 2 * N_KING_BUCKETS, alignment);
thread->refreshTable =
(AccumulatorKingState*) AlignedMalloc(sizeof(AccumulatorKingState) * 2 * 2 * N_KING_BUCKETS, alignment);
ResetRefreshTable(thread->refreshTable);

// Copy these onto the board for easier access within the engine
Expand Down Expand Up @@ -211,6 +212,7 @@ void SetupMainThread(Board* board) {
mainThread->calls = 0;
mainThread->nodes = 0;
mainThread->tbhits = 0;
mainThread->nmpMinPly = 0;

memcpy(&mainThread->board, board, offsetof(Board, accumulators));

Expand Down Expand Up @@ -241,6 +243,7 @@ void SetupOtherThreads(Board* board) {
thread->calls = 0;
thread->nodes = 0;
thread->tbhits = 0;
thread->nmpMinPly = 0;

for (int j = 0; j < mainThread->numRootMoves; j++)
InitRootMove(&thread->rootMoves[j], mainThread->rootMoves[j].move);
Expand Down
2 changes: 2 additions & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ struct ThreadData {
int idx, multiPV, depth, seldepth;
atomic_uint_fast64_t nodes, tbhits;

int nmpMinPly, npmColor;

Accumulator* accumulators;
AccumulatorKingState* refreshTable;

Expand Down

2 comments on commit accb7d6

@jherrera80
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might wanna take a look at some simplifications that where made to Stockfish's verification code:

official-stockfish/Stockfish@f66c362
official-stockfish/Stockfish@a4fedd8

@jhonnold
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the second one in particular will require some more time to investigate.

Please sign in to comment.