From 9b7983a4521b66bf8d3c37ee58963d39deb2695c Mon Sep 17 00:00:00 2001 From: mstembera Date: Tue, 17 Nov 2020 15:58:25 -0800 Subject: [PATCH 01/88] Cleaned up MakeIndex() The index order in kpp_board_index[][] is reversed to be more optimal for the access pattern STC https://tests.stockfishchess.org/tests/view/5fbd74f967cbf42301d6b24f LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 27504 W: 2686 L: 2607 D: 22211 Ptnml(0-2): 84, 2001, 9526, 2034, 107 closes https://github.com/official-stockfish/Stockfish/pull/3233 No functional change --- src/nnue/evaluate_nnue.cpp | 21 --------------------- src/nnue/features/half_kp.cpp | 15 ++++++--------- src/nnue/features/half_kp.h | 4 ---- src/nnue/nnue_common.h | 9 ++++++++- 4 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index b0ed7d2f..382d8ff9 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -31,27 +31,6 @@ namespace Eval::NNUE { - const uint32_t kpp_board_index[PIECE_NB][COLOR_NB] = { - // convention: W - us, B - them - // viewed from other side, W and B are reversed - { PS_NONE, PS_NONE }, - { PS_W_PAWN, PS_B_PAWN }, - { PS_W_KNIGHT, PS_B_KNIGHT }, - { PS_W_BISHOP, PS_B_BISHOP }, - { PS_W_ROOK, PS_B_ROOK }, - { PS_W_QUEEN, PS_B_QUEEN }, - { PS_W_KING, PS_B_KING }, - { PS_NONE, PS_NONE }, - { PS_NONE, PS_NONE }, - { PS_B_PAWN, PS_W_PAWN }, - { PS_B_KNIGHT, PS_W_KNIGHT }, - { PS_B_BISHOP, PS_W_BISHOP }, - { PS_B_ROOK, PS_W_ROOK }, - { PS_B_QUEEN, PS_W_QUEEN }, - { PS_B_KING, PS_W_KING }, - { PS_NONE, PS_NONE } - }; - // Input feature converter LargePagePtr feature_transformer; diff --git a/src/nnue/features/half_kp.cpp b/src/nnue/features/half_kp.cpp index 116157cc..29322f04 100644 --- a/src/nnue/features/half_kp.cpp +++ b/src/nnue/features/half_kp.cpp @@ -28,12 +28,9 @@ namespace Eval::NNUE::Features { return Square(int(s) ^ (bool(perspective) * 63)); } - // Find the index of the feature quantity from the king position and PieceSquare - template - inline IndexType HalfKP::MakeIndex( - Color perspective, Square s, Piece pc, Square ksq) { - - return IndexType(orient(perspective, s) + kpp_board_index[pc][perspective] + PS_END * ksq); + // Index of a feature for a given king position and another piece on some square + inline IndexType make_index(Color perspective, Square s, Piece pc, Square ksq) { + return IndexType(orient(perspective, s) + kpp_board_index[perspective][pc] + PS_END * ksq); } // Get a list of indices for active features @@ -45,7 +42,7 @@ namespace Eval::NNUE::Features { Bitboard bb = pos.pieces() & ~pos.pieces(KING); while (bb) { Square s = pop_lsb(&bb); - active->push_back(MakeIndex(perspective, s, pos.piece_on(s), ksq)); + active->push_back(make_index(perspective, s, pos.piece_on(s), ksq)); } } @@ -60,9 +57,9 @@ namespace Eval::NNUE::Features { Piece pc = dp.piece[i]; if (type_of(pc) == KING) continue; if (dp.from[i] != SQ_NONE) - removed->push_back(MakeIndex(perspective, dp.from[i], pc, ksq)); + removed->push_back(make_index(perspective, dp.from[i], pc, ksq)); if (dp.to[i] != SQ_NONE) - added->push_back(MakeIndex(perspective, dp.to[i], pc, ksq)); + added->push_back(make_index(perspective, dp.to[i], pc, ksq)); } } diff --git a/src/nnue/features/half_kp.h b/src/nnue/features/half_kp.h index 52a83eec..708fd7ea 100644 --- a/src/nnue/features/half_kp.h +++ b/src/nnue/features/half_kp.h @@ -52,10 +52,6 @@ namespace Eval::NNUE::Features { // Get a list of indices for recently changed features static void AppendChangedIndices(const Position& pos, const DirtyPiece& dp, Color perspective, IndexList* removed, IndexList* added); - - private: - // Index of a feature for a given king position and another piece on some square - static IndexType MakeIndex(Color perspective, Square s, Piece pc, Square sq_k); }; } // namespace Eval::NNUE::Features diff --git a/src/nnue/nnue_common.h b/src/nnue/nnue_common.h index a9664262..f9ff2bc8 100644 --- a/src/nnue/nnue_common.h +++ b/src/nnue/nnue_common.h @@ -90,7 +90,14 @@ namespace Eval::NNUE { PS_END2 = 12 * SQUARE_NB + 1 }; - extern const uint32_t kpp_board_index[PIECE_NB][COLOR_NB]; + constexpr uint32_t kpp_board_index[COLOR_NB][PIECE_NB] = { + // convention: W - us, B - them + // viewed from other side, W and B are reversed + { PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_W_KING, PS_NONE, + PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_B_KING, PS_NONE }, + { PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_B_KING, PS_NONE, + PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_W_KING, PS_NONE } + }; // Type of input feature after conversion using TransformedFeatureType = std::uint8_t; From d6d6972a66cb2fb599748bae1f14d32e6c42fc1e Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Fri, 20 Nov 2020 18:09:41 +0100 Subject: [PATCH 02/88] Refine rook penalty on closed files +-----------------+ | . . . . . . . . | All files are closed. Some files are | . . . . . o o . | more valuable for rooks, because | . . . . o . . o | they might open in the future. | . . . o x . . x | | o . o x . x x . | | x o x . . . . . | x our pawns | . x . . . . . . | o their pawns | . . . . . . . . | ^ rooks are scored higher on these files +-----------------+ ^ ^ Files containing none of our own pawns are open or half-open (otherwise they are closed). Rooks on (half-)open files recieve a bonus for the future potential to act along all ranks. This commit refines the (relative) penalty of rooks on closed files. Files that contain one of our blocked pawns are considered less likely to open in the future; rooks on these files are now penalized stronger. This bonus does not generally correlate with mobility. If the condition is sufficiently refined in the future, it may be beneficial to adjust or override mobility scores in some cases. LTC LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 494384 W: 71565 L: 70231 D: 352588 Ptnml(0-2): 3907, 48050, 142118, 49036, 4081 https://tests.stockfishchess.org/tests/view/5fb9312e67cbf42301d6afb9 LTC (non-regression w/ book noob_3moves.epd) LLR: 2.95 (-2.94,2.94) {-0.75,0.25} Total: 208520 W: 27044 L: 26937 D: 154539 Ptnml(0-2): 1557, 19850, 61391, 19853, 1609 https://tests.stockfishchess.org/tests/view/5fc01ced67cbf42301d6b3df STC LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 98392 W: 20269 L: 19868 D: 58255 Ptnml(0-2): 1804, 11297, 22589, 11706, 1800 https://tests.stockfishchess.org/tests/view/5fb7f88a67cbf42301d6af10 closes https://github.com/official-stockfish/Stockfish/pull/3242 Bench: 3682630 --- src/evaluate.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 90d11a00..fd51ad53 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -240,9 +240,8 @@ namespace { S(0, 0), S(9, 28), S(15, 31), S(17, 39), S(64, 70), S(171, 177), S(277, 260) }; - // RookOnFile[semiopen/open] contains bonuses for each rook when there is - // no (friendly) pawn on the rook file. - constexpr Score RookOnFile[] = { S(19, 7), S(48, 27) }; + constexpr Score RookOnClosedFile = S(10, 5); + constexpr Score RookOnOpenFile[] = { S(19, 7), S(48, 27) }; // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to // which piece type attacks which one. Attacks on lesser pieces which are @@ -485,16 +484,28 @@ namespace { if (Pt == ROOK) { - // Bonus for rook on an open or semi-open file + // Bonuses for rook on a (semi-)open or closed file if (pos.is_on_semiopen_file(Us, s)) - score += RookOnFile[pos.is_on_semiopen_file(Them, s)]; - - // Penalty when trapped by the king, even more if the king cannot castle - else if (mob <= 3) { - File kf = file_of(pos.square(Us)); - if ((kf < FILE_E) == (file_of(s) < kf)) - score -= TrappedRook * (1 + !pos.castling_rights(Us)); + score += RookOnOpenFile[pos.is_on_semiopen_file(Them, s)]; + } + else + { + // If our pawn on this file is blocked, increase penalty + if ( pos.pieces(Us, PAWN) + & shift(pos.pieces()) + & file_bb(s)) + { + score -= RookOnClosedFile; + } + + // Penalty when trapped by the king, even more if the king cannot castle + if (mob <= 3) + { + File kf = file_of(pos.square(Us)); + if ((kf < FILE_E) == (file_of(s) < kf)) + score -= TrappedRook * (1 + !pos.castling_rights(Us)); + } } } From 66da1e802c22b1952c2a07af65c6224d0e01b3df Mon Sep 17 00:00:00 2001 From: lonfom169 Date: Thu, 26 Nov 2020 09:40:54 -0300 Subject: [PATCH 03/88] Remove bonus for killers. Passed non-regression STC: LLR: 2.94 (-2.94,2.94) {-1.25,0.25} Total: 14712 W: 1416 L: 1315 D: 11981 Ptnml(0-2): 59, 1029, 5082, 1124, 62 https://tests.stockfishchess.org/tests/view/5fbfa31f67cbf42301d6b36e Passed non-regression LTC: LLR: 2.95 (-2.94,2.94) {-0.75,0.25} Total: 27536 W: 1099 L: 1044 D: 25393 Ptnml(0-2): 11, 929, 11838, 974, 16 https://tests.stockfishchess.org/tests/view/5fbfac9167cbf42301d6b371 closes https://github.com/official-stockfish/Stockfish/pull/3241 Bench: 3887644 --- src/search.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 7c797bef..d854cd95 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1257,9 +1257,6 @@ moves_loop: // When in check, search starts from here int bonus = value > alpha ? stat_bonus(newDepth) : -stat_bonus(newDepth); - if (move == ss->killers[0]) - bonus += bonus / 4; - update_continuation_histories(ss, movedPiece, to_sq(move), bonus); } } From 6c429c4d6527a8e88d2ad1e7bfc8f4bd0ec05729 Mon Sep 17 00:00:00 2001 From: Unai Corzo Date: Sat, 28 Nov 2020 16:32:52 +0100 Subject: [PATCH 04/88] Search simplification STC https://tests.stockfishchess.org/tests/view/5fc2083942a050a89f02c8bb LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 23200 W: 2251 L: 2160 D: 18789 Ptnml(0-2): 86, 1726, 7895, 1797, 96 LTC https://tests.stockfishchess.org/tests/view/5fc22d7b42a050a89f02c8d0 LLR: 2.92 (-2.94,2.94) {-0.75,0.25} Total: 15832 W: 653 L: 590 D: 14589 Ptnml(0-2): 7, 521, 6795, 588, 5 closes https://github.com/official-stockfish/Stockfish/pull/3244/files bench: 3827317 Simplify search. --- src/search.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index d854cd95..99d1cb0e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1554,7 +1554,6 @@ moves_loop: // When in check, search starts from here // Do not search moves with negative SEE values if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY - && !(givesCheck && pos.is_discovery_check_on_king(~pos.side_to_move(), move)) && !pos.see_ge(move)) continue; From 2bc4ae172a7897106946ab9ede5db98db331c600 Mon Sep 17 00:00:00 2001 From: Unai Corzo Date: Sun, 29 Nov 2020 09:07:31 +0100 Subject: [PATCH 05/88] Update README.md fix a few typos closes https://github.com/official-stockfish/Stockfish/pull/3245 No functional change --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 409d0a10..eb7aa5a7 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ about how to use Stockfish with it. The Stockfish engine features two evaluation functions for chess, the classical evaluation based on handcrafted terms, and the NNUE evaluation based on efficiently -updateable neural networks. The classical evaluation runs efficiently on almost all +updatable neural networks. The classical evaluation runs efficiently on almost all CPU architectures, while the NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2, avx2, neon, or similar). @@ -108,7 +108,7 @@ Currently, Stockfish has the following UCI options: * #### SyzygyProbeDepth Minimum remaining search depth for which a position is probed. Set this option - to a higher value to probe less agressively if you experience too much slowdown + to a higher value to probe less aggressively if you experience too much slowdown (in terms of nps) due to TB probing. * #### Syzygy50MoveRule @@ -173,8 +173,8 @@ to be compatible with that binary. If the engine is searching a position that is not in the tablebases (e.g. a position with 8 pieces), it will access the tablebases during the search. -If the engine reports a very large score (typically 153.xx), this means -that it has found a winning line into a tablebase position. +If the engine reports a very large score (typically 153.xx), this means +it has found a winning line into a tablebase position. If the engine is given a position to search that is in the tablebases, it will use the tablebases at the beginning of the search to preselect all @@ -182,7 +182,7 @@ good moves, i.e. all moves that preserve the win or preserve the draw while taking into account the 50-move rule. It will then perform a search only on those moves. **The engine will not move immediately**, unless there is only a single good move. **The engine likely -will not report a mate score even if the position is known to be won.** +will not report a mate score, even if the position is known to be won.** It is therefore clear that this behaviour is not identical to what one might be used to with Nalimov tablebases. There are technical reasons for this @@ -207,7 +207,7 @@ will fall back to regular memory allocation when this is not the case. Large page support on Linux is obtained by the Linux kernel transparent huge pages functionality. Typically, transparent huge pages -are already enabled and no configuration is needed. +are already enabled, and no configuration is needed. ### Support on Windows @@ -216,7 +216,7 @@ The use of large pages requires "Lock Pages in Memory" privilege. See on how to enable this privilege, then run [RAMMap](https://docs.microsoft.com/en-us/sysinternals/downloads/rammap) to double-check that large pages are used. We suggest that you reboot your computer after you have enabled large pages, because long Windows -sessions suffer from memory fragmentation which may prevent Stockfish +sessions suffer from memory fragmentation, which may prevent Stockfish from getting large pages: a fresh session is better in this regard. ## Compiling Stockfish yourself from the sources @@ -236,7 +236,7 @@ targets with corresponding descriptions. make build ARCH=x86-64-modern ``` -When not using the Makefile to compile (for instance with Microsoft MSVC) you +When not using the Makefile to compile (for instance, with Microsoft MSVC) you need to manually set/unset some switches in the compiler command line; see file *types.h* for a quick reference. @@ -281,9 +281,9 @@ first, where the basics of Stockfish development are explained. ## Terms of use Stockfish is free, and distributed under the **GNU General Public License version 3** -(GPL v3). Essentially, this means that you are free to do almost exactly +(GPL v3). Essentially, this means you are free to do almost exactly what you want with the program, including distributing it among your -friends, making it available for download from your web site, selling +friends, making it available for download from your website, selling it (either by itself or as part of some bigger software package), or using it as the starting point for a software project of your own. From 045728a7da9dfee1746da0c5b4632a62f68c0d97 Mon Sep 17 00:00:00 2001 From: syzygy1 <3028851+syzygy1@users.noreply.github.com> Date: Sun, 29 Nov 2020 12:05:26 +0100 Subject: [PATCH 06/88] Remove piece lists This patch removes the incrementally updated piece lists from the Position object. This has been tried before but always failed. My reasons for trying again are: * 32-bit systems (including phones) are now much less important than they were some years ago (and are absent from fishtest); * NNUE may have made SF less finely tuned to the order in which moves were generated. STC: LLR: 2.94 (-2.94,2.94) {-1.25,0.25} Total: 55272 W: 5260 L: 5216 D: 44796 Ptnml(0-2): 208, 4147, 18898, 4159, 224 https://tests.stockfishchess.org/tests/view/5fc2986a42a050a89f02c926 LTC: LLR: 2.96 (-2.94,2.94) {-0.75,0.25} Total: 16600 W: 673 L: 608 D: 15319 Ptnml(0-2): 14, 533, 7138, 604, 11 https://tests.stockfishchess.org/tests/view/5fc2f98342a050a89f02c95c closes https://github.com/official-stockfish/Stockfish/pull/3247 Bench: 3940967 --- src/endgame.cpp | 8 ++++---- src/evaluate.cpp | 8 ++++---- src/movegen.cpp | 7 ++++--- src/pawns.cpp | 7 ++++--- src/position.cpp | 7 ------- src/position.h | 27 ++++----------------------- 6 files changed, 20 insertions(+), 44 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index c8be2198..7e005a28 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -553,8 +553,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 2)); assert(verify_material(pos, weakSide, RookValueMg, 1)); - Square strongPawn1 = pos.squares(strongSide)[0]; - Square strongPawn2 = pos.squares(strongSide)[1]; + Square strongPawn1 = lsb(pos.pieces(strongSide, PAWN)); + Square strongPawn2 = msb(pos.pieces(strongSide, PAWN)); Square weakKing = pos.square(weakSide); // Does the stronger side have a passed pawn? @@ -638,8 +638,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { return SCALE_FACTOR_NONE; Square weakKing = pos.square(weakSide); - Square strongPawn1 = pos.squares(strongSide)[0]; - Square strongPawn2 = pos.squares(strongSide)[1]; + Square strongPawn1 = lsb(pos.pieces(strongSide, PAWN)); + Square strongPawn2 = msb(pos.pieces(strongSide, PAWN)); Square blockSq1, blockSq2; if (relative_rank(strongSide, strongPawn1) > relative_rank(strongSide, strongPawn2)) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fd51ad53..6ee53621 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -387,15 +387,15 @@ namespace { constexpr Direction Down = -pawn_push(Us); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); - const Square* pl = pos.squares(Us); - + Bitboard b1 = pos.pieces(Us, Pt); Bitboard b, bb; Score score = SCORE_ZERO; attackedBy[Us][Pt] = 0; - for (Square s = *pl; s != SQ_NONE; s = *++pl) - { + while (b1) { + Square s = pop_lsb(&b1); + // Find attacked squares, including x-ray attacks for bishops and rooks b = Pt == BISHOP ? attacks_bb(s, pos.pieces() ^ pos.pieces(QUEEN)) : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK)) diff --git a/src/movegen.cpp b/src/movegen.cpp index 3340f65c..cc1518a0 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -180,10 +180,11 @@ namespace { static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); - const Square* pl = pos.squares(Us); + Bitboard bb = pos.pieces(Us, Pt); + + while (bb) { + Square from = pop_lsb(&bb); - for (Square from = *pl; from != SQ_NONE; from = *++pl) - { if (Checks) { if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) diff --git a/src/pawns.cpp b/src/pawns.cpp index 68aaf331..b6d29003 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -91,7 +91,7 @@ namespace { Square s; bool backward, passed, doubled; Score score = SCORE_ZERO; - const Square* pl = pos.squares(Us); + Bitboard b = pos.pieces(Us, PAWN); Bitboard ourPawns = pos.pieces( Us, PAWN); Bitboard theirPawns = pos.pieces(Them, PAWN); @@ -104,8 +104,9 @@ namespace { e->blockedCount += popcount(shift(ourPawns) & (theirPawns | doubleAttackThem)); // Loop through all pawns of the current color and score each pawn - while ((s = *pl++) != SQ_NONE) - { + while (b) { + s = pop_lsb(&b); + assert(pos.piece_on(s) == make_piece(Us, PAWN)); Rank r = relative_rank(Us, s); diff --git a/src/position.cpp b/src/position.cpp index 5ce7da22..07ce0a7c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -197,7 +197,6 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th std::memset(this, 0, sizeof(Position)); std::memset(si, 0, sizeof(StateInfo)); - std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE); st = si; ss >> std::noskipws; @@ -1327,16 +1326,10 @@ bool Position::pos_is_ok() const { assert(0 && "pos_is_ok: State"); for (Piece pc : Pieces) - { if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))) || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc)) assert(0 && "pos_is_ok: Pieces"); - for (int i = 0; i < pieceCount[pc]; ++i) - if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i) - assert(0 && "pos_is_ok: Index"); - } - for (Color c : { WHITE, BLACK }) for (CastlingRights cr : {c & KING_SIDE, c & QUEEN_SIDE}) { diff --git a/src/position.h b/src/position.h index d6f5c9fd..02156448 100644 --- a/src/position.h +++ b/src/position.h @@ -99,7 +99,6 @@ public: bool empty(Square s) const; template int count(Color c) const; template int count() const; - template const Square* squares(Color c) const; template Square square(Color c) const; bool is_on_semiopen_file(Color c, Square s) const; @@ -190,8 +189,6 @@ private: Bitboard byTypeBB[PIECE_TYPE_NB]; Bitboard byColorBB[COLOR_NB]; int pieceCount[PIECE_NB]; - Square pieceList[PIECE_NB][16]; - int index[SQUARE_NB]; int castlingRightsMask[SQUARE_NB]; Square castlingRookSquare[CASTLING_RIGHT_NB]; Bitboard castlingPath[CASTLING_RIGHT_NB]; @@ -254,13 +251,9 @@ template inline int Position::count() const { return count(WHITE) + count(BLACK); } -template inline const Square* Position::squares(Color c) const { - return pieceList[make_piece(c, Pt)]; -} - template inline Square Position::square(Color c) const { - assert(pieceCount[make_piece(c, Pt)] == 1); - return squares(c)[0]; + assert(count(c) == 1); + return lsb(pieces(c, Pt)); } inline Square Position::ep_square() const { @@ -394,35 +387,25 @@ inline void Position::put_piece(Piece pc, Square s) { board[s] = pc; byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s; byColorBB[color_of(pc)] |= s; - index[s] = pieceCount[pc]++; - pieceList[pc][index[s]] = s; + pieceCount[pc]++; pieceCount[make_piece(color_of(pc), ALL_PIECES)]++; psq += PSQT::psq[pc][s]; } inline void Position::remove_piece(Square s) { - // WARNING: This is not a reversible operation. If we remove a piece in - // do_move() and then replace it in undo_move() we will put it at the end of - // the list and not in its original place, it means index[] and pieceList[] - // are not invariant to a do_move() + undo_move() sequence. Piece pc = board[s]; byTypeBB[ALL_PIECES] ^= s; byTypeBB[type_of(pc)] ^= s; byColorBB[color_of(pc)] ^= s; /* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */ - Square lastSquare = pieceList[pc][--pieceCount[pc]]; - index[lastSquare] = index[s]; - pieceList[pc][index[lastSquare]] = lastSquare; - pieceList[pc][pieceCount[pc]] = SQ_NONE; + pieceCount[pc]--; pieceCount[make_piece(color_of(pc), ALL_PIECES)]--; psq -= PSQT::psq[pc][s]; } inline void Position::move_piece(Square from, Square to) { - // index[from] is not updated and becomes stale. This works as long as index[] - // is accessed just by known occupied squares. Piece pc = board[from]; Bitboard fromTo = from | to; byTypeBB[ALL_PIECES] ^= fromTo; @@ -430,8 +413,6 @@ inline void Position::move_piece(Square from, Square to) { byColorBB[color_of(pc)] ^= fromTo; board[from] = NO_PIECE; board[to] = pc; - index[to] = index[from]; - pieceList[pc][index[to]] = to; psq += PSQT::psq[pc][to] - PSQT::psq[pc][from]; } From 2442ba2b0e8a399b0dbfe9d23a8a2819cb0af987 Mon Sep 17 00:00:00 2001 From: Unai Corzo Date: Sun, 29 Nov 2020 13:52:36 +0100 Subject: [PATCH 07/88] Reductions simplification Simplify increase reduction for captures/promotions if late move and at low depth. STC https://tests.stockfishchess.org/tests/view/5fbff65067cbf42301d6b3ae LLR: 2.97 (-2.94,2.94) {-1.25,0.25} Total: 49088 W: 4607 L: 4555 D: 39926 Ptnml(0-2): 177, 3615, 16932, 3619, 201 LTC https://tests.stockfishchess.org/tests/view/5fc0902967cbf42301d6b3fc LLR: 2.99 (-2.94,2.94) {-0.75,0.25} Total: 160944 W: 6153 L: 6193 D: 148598 Ptnml(0-2): 90, 5525, 69294, 5461, 102 closes https://github.com/official-stockfish/Stockfish/pull/3248 bench: 3834568 --- src/search.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 99d1cb0e..52541868 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1222,10 +1222,6 @@ moves_loop: // When in check, search starts from here } else { - // Increase reduction for captures/promotions if late move and at low depth - if (depth < 8 && moveCount > 2) - r++; - // Unless giving check, this capture is likely bad if ( !givesCheck && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 210 * depth <= alpha) From 736400675746c6b84a0bdf131babce1b07ade0df Mon Sep 17 00:00:00 2001 From: SFisGOD Date: Sat, 28 Nov 2020 23:14:34 +0800 Subject: [PATCH 08/88] Update default net to nn-62ef826d1a6d.nnue Include scaling change as suggested by Dietrich Kappe, the one who trained net for Komodo. According to him, some nets may require different scaling in order to utilize its full strength. STC: LLR: 2.93 (-2.94,2.94) {-0.25,1.25} Total: 99856 W: 9669 L: 9401 D: 80786 Ptnml(0-2): 374, 7468, 34037, 7614, 435 https://tests.stockfishchess.org/tests/view/5fc2697642a050a89f02c8ec LTC: LLR: 2.96 (-2.94,2.94) {0.25,1.25} Total: 29840 W: 1220 L: 1081 D: 27539 Ptnml(0-2): 10, 969, 12827, 1100, 14 https://tests.stockfishchess.org/tests/view/5fc2ea5142a050a89f02c957 Bench: 3561701 --- src/evaluate.cpp | 2 +- src/evaluate.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 6ee53621..a1b04316 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1037,7 +1037,7 @@ Value Eval::evaluate(const Position& pos) { // Scale and shift NNUE for compatibility with search and classical evaluation auto adjusted_NNUE = [&](){ int mat = pos.non_pawn_material() + PawnValueMg * pos.count(); - return NNUE::evaluate(pos) * (720 + mat / 32) / 1024 + Tempo; + return NNUE::evaluate(pos) * (679 + mat / 32) / 1024 + Tempo; }; // If there is PSQ imbalance use classical eval, with small probability if it is small diff --git a/src/evaluate.h b/src/evaluate.h index 06c66f71..7dbc35de 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -36,7 +36,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-c3ca321c51c9.nnue" + #define EvalFileDefaultName "nn-62ef826d1a6d.nnue" namespace NNUE { From be7a03a957d5c2590a329f8f47acea8af2305adf Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 5 Dec 2020 04:00:41 +0300 Subject: [PATCH 09/88] Introduce static history The idea of this patch can be described as following: we update static history stats based on comparison of the static evaluations of the position before and after the move. If the move increases static evaluation it's assigned positive bonus, if it decreases static evaluation it's assigned negative bonus. These stats are used in movepicker to sort quiet moves. passed STC https://tests.stockfishchess.org/tests/view/5fca4c0842a050a89f02cd66 LLR: 3.00 (-2.94,2.94) {-0.25,1.25} Total: 78152 W: 7409 L: 7171 D: 63572 Ptnml(0-2): 303, 5695, 26873, 5871, 334 passed LTC https://tests.stockfishchess.org/tests/view/5fca6be442a050a89f02cd75 LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 40240 W: 1602 L: 1441 D: 37197 Ptnml(0-2): 19, 1306, 17305, 1475, 15 closes https://github.com/official-stockfish/Stockfish/pull/3253 bench 3845156 --- src/movepick.cpp | 9 +++++---- src/movepick.h | 3 +++ src/search.cpp | 11 +++++++++++ src/thread.cpp | 1 + src/thread.h | 1 + 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index f5e02385..9ca1a21f 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -54,9 +54,9 @@ namespace { /// ordering is at the current node. /// MovePicker constructor for the main search -MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, +MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const ButterflyHistory* sh, const LowPlyHistory* lp, const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl) - : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), + : pos(p), mainHistory(mh), staticHistory(sh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { assert(d > 0); @@ -66,9 +66,9 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist } /// MovePicker constructor for quiescence search -MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, +MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const ButterflyHistory* sh, const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs) - : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) { + : pos(p), mainHistory(mh), staticHistory(sh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) { assert(d <= 0); @@ -105,6 +105,7 @@ void MovePicker::score() { else if (Type == QUIETS) m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] + + (*staticHistory)[pos.side_to_move()][from_to(m)] + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] diff --git a/src/movepick.h b/src/movepick.h index 4c0ad551..7fe98e49 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -123,10 +123,12 @@ public: MovePicker& operator=(const MovePicker&) = delete; MovePicker(const Position&, Move, Value, const CapturePieceToHistory*); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, + const ButterflyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Square); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, + const ButterflyHistory*, const LowPlyHistory*, const CapturePieceToHistory*, const PieceToHistory**, @@ -143,6 +145,7 @@ private: const Position& pos; const ButterflyHistory* mainHistory; + const ButterflyHistory* staticHistory; const LowPlyHistory* lowPlyHistory; const CapturePieceToHistory* captureHistory; const PieceToHistory** continuationHistory; diff --git a/src/search.cpp b/src/search.cpp index 52541868..ab559696 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -807,6 +807,15 @@ namespace { tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } + // Update static history for previous move + if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) + { + int bonus = ss->staticEval > -(ss-1)->staticEval + 2 * Tempo ? -stat_bonus(depth) : + ss->staticEval < -(ss-1)->staticEval + 2 * Tempo ? stat_bonus(depth) : + 0; + thisThread->staticHistory[~us][from_to((ss-1)->currentMove)] << bonus; + } + // Step 7. Razoring (~1 Elo) if ( !rootNode // The required rootNode PV handling is not available in qsearch && depth == 1 @@ -964,6 +973,7 @@ moves_loop: // When in check, search starts from here Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, + &thisThread->staticHistory, &thisThread->lowPlyHistory, &captureHistory, contHist, @@ -1507,6 +1517,7 @@ moves_loop: // When in check, search starts from here // queen and checking knight promotions, and other checks(only if depth >= DEPTH_QS_CHECKS) // will be generated. MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, + &thisThread->staticHistory, &thisThread->captureHistory, contHist, to_sq((ss-1)->currentMove)); diff --git a/src/thread.cpp b/src/thread.cpp index 2fbf745d..bfcdb65e 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -57,6 +57,7 @@ void Thread::clear() { counterMoves.fill(MOVE_NONE); mainHistory.fill(0); + staticHistory.fill(0); lowPlyHistory.fill(0); captureHistory.fill(0); diff --git a/src/thread.h b/src/thread.h index 6a73423b..c05fa941 100644 --- a/src/thread.h +++ b/src/thread.h @@ -69,6 +69,7 @@ public: Depth rootDepth, completedDepth; CounterMoveHistory counterMoves; ButterflyHistory mainHistory; + ButterflyHistory staticHistory; LowPlyHistory lowPlyHistory; CapturePieceToHistory captureHistory; ContinuationHistory continuationHistory[2][2]; From 8630d03dd4e1ec7e492ddf6c40d9d9e4cdba2a58 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 1 Dec 2020 15:02:35 +0300 Subject: [PATCH 10/88] Add comments to uncommented parts of code https://github.com/official-stockfish/Stockfish/pull/3250 No functional change --- src/evaluate.cpp | 16 ++++++++++++++++ src/search.cpp | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a1b04316..ef33adf5 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -844,6 +844,8 @@ namespace { behind |= shift(behind); behind |= shift(behind); + // Compute space score based on the number of safe squares and number of our pieces + // increased with number of total blocked pawns in position. int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); int weight = pos.count(Us) - 3 + std::min(pe->blocked_count(), 9); Score score = make_score(bonus * weight * weight / 16, 0); @@ -905,24 +907,36 @@ namespace { { if (pos.opposite_bishops()) { + // For pure opposite colored bishops endgames use scale factor + // based on the number of passed pawns of the strong side. if ( pos.non_pawn_material(WHITE) == BishopValueMg && pos.non_pawn_material(BLACK) == BishopValueMg) sf = 18 + 4 * popcount(pe->passed_pawns(strongSide)); + // For every other opposite colored bishops endgames use scale factor + // based on the number of all pieces of the strong side. else sf = 22 + 3 * pos.count(strongSide); } + // For rook endgames with strong side not having overwhelming pawn number advantage + // and its pawns being on one flank and weak side protecting its pieces with a king + // use lower scale factor. else if ( pos.non_pawn_material(WHITE) == RookValueMg && pos.non_pawn_material(BLACK) == RookValueMg && pos.count(strongSide) - pos.count(~strongSide) <= 1 && bool(KingSide & pos.pieces(strongSide, PAWN)) != bool(QueenSide & pos.pieces(strongSide, PAWN)) && (attacks_bb(pos.square(~strongSide)) & pos.pieces(~strongSide, PAWN))) sf = 36; + // For queen vs no queen endgames use scale factor + // based on number of minors of side that doesn't have queen. else if (pos.count() == 1) sf = 37 + 3 * (pos.count(WHITE) == 1 ? pos.count(BLACK) + pos.count(BLACK) : pos.count(WHITE) + pos.count(WHITE)); + // In every other case use scale factor based on + // the number of pawns of the strong side reduced if pawns are on a single flank. else sf = std::min(sf, 36 + 7 * pos.count(strongSide)) - 4 * !pawnsOnBothFlanks; + // Reduce scale factor in case of pawns being on a single flank sf -= 4 * !pawnsOnBothFlanks; } @@ -1046,6 +1060,8 @@ Value Eval::evaluate(const Position& pos) { bool largePsq = psq * 16 > (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50; bool classical = largePsq || (psq > PawnValueMg / 4 && !(pos.this_thread()->nodes & 0xB)); + // Use classical evaluation for really low piece endgames. + // The most critical case is a bishop + A/H file pawn vs naked king draw. bool strongClassical = pos.non_pawn_material() < 2 * RookValueMg && pos.count() < 2; v = classical || strongClassical ? Evaluation(pos).value() : adjusted_NNUE(); diff --git a/src/search.cpp b/src/search.cpp index ab559696..ba9265dd 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -676,6 +676,7 @@ namespace { ss->ttPv = PvNode || (ss->ttHit && tte->is_pv()); formerPv = ss->ttPv && !PvNode; + // Update low ply history for previous move if we are near root and position is or has been in PV if ( ss->ttPv && depth > 12 && ss->ply - 1 < MAX_LPH @@ -700,6 +701,7 @@ namespace { { if (ttValue >= beta) { + // Bonus for a quiet ttMove that fails high if (!pos.capture_or_promotion(ttMove)) update_quiet_stats(pos, ss, ttMove, stat_bonus(depth), depth); @@ -716,6 +718,8 @@ namespace { } } + // Partial workaround for the graph history interaction problem + // For high rule50 counts don't produce transposition table cutoffs. if (pos.rule50_count() < 90) return ttValue; } @@ -789,6 +793,7 @@ namespace { if (eval == VALUE_NONE) ss->staticEval = eval = evaluate(pos); + // Randomize draw evaluation if (eval == VALUE_DRAW) eval = value_draw(thisThread); @@ -799,11 +804,14 @@ namespace { } else { + // In case of null move search use previous static eval with a different sign + // and addition of two tempos if ((ss-1)->currentMove != MOVE_NULL) ss->staticEval = eval = evaluate(pos); else ss->staticEval = eval = -(ss-1)->staticEval + 2 * Tempo; + // Save static evaluation into transposition table tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } @@ -822,6 +830,10 @@ namespace { && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); + // Set up improving flag that is used in various pruning heuristics + // We define position as improving if static evaluation of position is better + // Than the previous static evaluation at our turn + // In case of us being in check at our previous move we look at move prior to it improving = (ss-2)->staticEval == VALUE_NONE ? ss->staticEval > (ss-4)->staticEval || (ss-4)->staticEval == VALUE_NONE : ss->staticEval > (ss-2)->staticEval; @@ -1183,6 +1195,7 @@ moves_loop: // When in check, search starts from here if ((rootNode || !PvNode) && depth > 10 && thisThread->bestMoveChanges <= 2) r++; + // More reductions for late moves if position was not in previous PV if (moveCountPruning && !formerPv) r++; @@ -1258,6 +1271,7 @@ moves_loop: // When in check, search starts from here { value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); + // If the move passed LMR update its stats if (didLMR && !captureOrPromotion) { int bonus = value > alpha ? stat_bonus(newDepth) @@ -1309,8 +1323,7 @@ moves_loop: // When in check, search starts from here rm.pv.push_back(*m); // We record how often the best move has been changed in each - // iteration. This information is used for time management: when - // the best move changes frequently, we allocate some more time. + // iteration. This information is used for time management and LMR if (moveCount > 1) ++thisThread->bestMoveChanges; } @@ -1343,6 +1356,7 @@ moves_loop: // When in check, search starts from here } } + // If the move is worse than some previously searched move, remember it to update its stats later if (move != bestMove) { if (captureOrPromotion && captureCount < 32) @@ -1372,6 +1386,7 @@ moves_loop: // When in check, search starts from here bestValue = excludedMove ? alpha : ss->inCheck ? mated_in(ss->ply) : VALUE_DRAW; + // If there is a move which produces search value greater than alpha we update stats of searched moves else if (bestMove) update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, quietsSearched, quietCount, capturesSearched, captureCount, depth); @@ -1393,6 +1408,7 @@ moves_loop: // When in check, search starts from here else if (depth > 3) ss->ttPv = ss->ttPv && (ss+1)->ttPv; + // Write gathered information in transposition table if (!excludedMove && !(rootNode && thisThread->pvIdx)) tte->save(posKey, value_to_tt(bestValue, ss->ply), ss->ttPv, bestValue >= beta ? BOUND_LOWER : @@ -1488,6 +1504,8 @@ moves_loop: // When in check, search starts from here bestValue = ttValue; } else + // In case of null move search use previous static eval with a different sign + // and addition of two tempos ss->staticEval = bestValue = (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval + 2 * Tempo; @@ -1495,6 +1513,7 @@ moves_loop: // When in check, search starts from here // Stand pat. Return immediately if static value is at least beta if (bestValue >= beta) { + // Save gathered info in transposition table if (!ss->ttHit) tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_NONE, MOVE_NONE, ss->staticEval); @@ -1623,6 +1642,7 @@ moves_loop: // When in check, search starts from here return mated_in(ss->ply); // Plies to mate from the root } + // Save gathered info in transposition table tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, bestValue >= beta ? BOUND_LOWER : PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, @@ -1706,9 +1726,10 @@ moves_loop: // When in check, search starts from here if (!pos.capture_or_promotion(bestMove)) { + // Increase stats for the best move in case it was a quiet move update_quiet_stats(pos, ss, bestMove, bonus2, depth); - // Decrease all the non-best quiet moves + // Decrease stats for all non-best quiet moves for (int i = 0; i < quietCount; ++i) { thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bonus2; @@ -1716,14 +1737,16 @@ moves_loop: // When in check, search starts from here } } else + // Increase stats for the best move in case it was a capture move captureHistory[moved_piece][to_sq(bestMove)][captured] << bonus1; - // Extra penalty for a quiet early move that was not a TT move or main killer move in previous ply when it gets refuted + // Extra penalty for a quiet early move that was not a TT move or + // main killer move in previous ply when it gets refuted. if ( ((ss-1)->moveCount == 1 + (ss-1)->ttHit || ((ss-1)->currentMove == (ss-1)->killers[0])) && !pos.captured_piece()) update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -bonus1); - // Decrease all the non-best capture moves + // Decrease stats for all non-best capture moves for (int i = 0; i < captureCount; ++i) { moved_piece = pos.moved_piece(capturesSearched[i]); @@ -1740,6 +1763,7 @@ moves_loop: // When in check, search starts from here for (int i : {1, 2, 4, 6}) { + // Only update first 2 continuation histories if we are in check if (ss->inCheck && i > 2) break; if (is_ok((ss-i)->currentMove)) @@ -1752,6 +1776,7 @@ moves_loop: // When in check, search starts from here void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus, int depth) { + // Update killers if (ss->killers[0] != move) { ss->killers[1] = ss->killers[0]; @@ -1763,15 +1788,18 @@ moves_loop: // When in check, search starts from here thisThread->mainHistory[us][from_to(move)] << bonus; update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus); + // Penalty for reversed move in case of moved piece not being a pawn if (type_of(pos.moved_piece(move)) != PAWN) thisThread->mainHistory[us][from_to(reverse_move(move))] << -bonus; + // Update countermove history if (is_ok((ss-1)->currentMove)) { Square prevSq = to_sq((ss-1)->currentMove); thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move; } + // Update low ply history if (depth > 11 && ss->ply < MAX_LPH) thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 7); } From c7f0a768cb9d5972861baae0f215d69f9e86a626 Mon Sep 17 00:00:00 2001 From: Fanael Linithien Date: Mon, 7 Dec 2020 14:46:29 +0100 Subject: [PATCH 11/88] Use arithmetic right shift for sign extension in MMX and SSE2 paths This appears to be slightly faster than using a comparison against zero to compute the high bits, on both old (like Pentium III) and new (like Zen 2) hardware. closes https://github.com/official-stockfish/Stockfish/pull/3254 No functional change. --- src/nnue/layers/affine_transform.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index caf315b2..0e0515f9 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -680,9 +680,8 @@ namespace Eval::NNUE::Layers { for (IndexType j = 0; j < kNumChunks; ++j) { __m128i row_j = _mm_load_si128(&row[j]); __m128i input_j = _mm_load_si128(&input_vector[j]); - __m128i row_signs = _mm_cmpgt_epi8(kZeros, row_j); - __m128i extended_row_lo = _mm_unpacklo_epi8(row_j, row_signs); - __m128i extended_row_hi = _mm_unpackhi_epi8(row_j, row_signs); + __m128i extended_row_lo = _mm_srai_epi16(_mm_unpacklo_epi8(row_j, row_j), 8); + __m128i extended_row_hi = _mm_srai_epi16(_mm_unpackhi_epi8(row_j, row_j), 8); __m128i extended_input_lo = _mm_unpacklo_epi8(input_j, kZeros); __m128i extended_input_hi = _mm_unpackhi_epi8(input_j, kZeros); __m128i product_lo = _mm_madd_epi16(extended_row_lo, extended_input_lo); @@ -704,9 +703,8 @@ namespace Eval::NNUE::Layers { for (IndexType j = 0; j < kNumChunks; ++j) { __m64 row_j = row[j]; __m64 input_j = input_vector[j]; - __m64 row_signs = _mm_cmpgt_pi8(kZeros, row_j); - __m64 extended_row_lo = _mm_unpacklo_pi8(row_j, row_signs); - __m64 extended_row_hi = _mm_unpackhi_pi8(row_j, row_signs); + __m64 extended_row_lo = _mm_srai_pi16(_mm_unpacklo_pi8(row_j, row_j), 8); + __m64 extended_row_hi = _mm_srai_pi16(_mm_unpackhi_pi8(row_j, row_j), 8); __m64 extended_input_lo = _mm_unpacklo_pi8(input_j, kZeros); __m64 extended_input_hi = _mm_unpackhi_pi8(input_j, kZeros); __m64 product_lo = _mm_madd_pi16(extended_row_lo, extended_input_lo); From d706ae62d73d90c0f80cdccd58384a347295d549 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Mon, 7 Dec 2020 19:28:47 +0200 Subject: [PATCH 12/88] New Imbalance Tables Tweak Imbalance tables tweaked to contain MiddleGame and Endgame values, instead of a single value. The idea started from Fisherman, which requested my help to tune the values back in June/July, so I tuned the values back then, and we were able to accomplish good results, but not enough to pass both STC and LTC tests. So after the recent changes, I decided to give it another shot, and I am glad that it was a successful attempt. A special thanks goes also to mstembera, which notified me a simple way to let the patch perform a little better. Passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 115976 W: 23124 L: 22695 D: 70157 Ptnml(0-2): 2074, 13652, 26285, 13725, 2252 https://tests.stockfishchess.org/tests/view/5fc92d2d42a050a89f02ccc8 Passed LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 156304 W: 20617 L: 20024 D: 115663 Ptnml(0-2): 1138, 14647, 46084, 15050, 1233 https://tests.stockfishchess.org/tests/view/5fc9fee142a050a89f02cd3e closes https://github.com/official-stockfish/Stockfish/pull/3255 Bench: 4278746 --- src/evaluate.cpp | 2 +- src/material.cpp | 37 ++++++++++++++++++++----------------- src/material.h | 8 ++++---- src/pawns.cpp | 1 + 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ef33adf5..c507aa06 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -594,7 +594,7 @@ namespace { int kingFlankDefense = popcount(b3); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] // (~10 Elo) - + 185 * popcount(kingRing[Us] & weak) // (~15 Elo) + + 183 * popcount(kingRing[Us] & weak) // (~15 Elo) + 148 * popcount(unsafeChecks) // (~4 Elo) + 98 * popcount(pos.blockers_for_king(Us)) // (~2 Elo) + 69 * kingAttacksCount[Them] // (~0.5 Elo) diff --git a/src/material.cpp b/src/material.cpp index 870a5e11..f77972e3 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -25,31 +25,34 @@ using namespace std; namespace { + #define S(mg, eg) make_score(mg, eg) // Polynomial material imbalance parameters - constexpr int QuadraticOurs[][PIECE_TYPE_NB] = { + constexpr Score QuadraticOurs[][PIECE_TYPE_NB] = { // OUR PIECES // pair pawn knight bishop rook queen - {1438 }, // Bishop pair - { 40, 38 }, // Pawn - { 32, 255, -62 }, // Knight OUR PIECES - { 0, 104, 4, 0 }, // Bishop - { -26, -2, 47, 105, -208 }, // Rook - {-189, 24, 117, 133, -134, -6 } // Queen + {S(1419, 1455) }, // Bishop pair + {S( 101, 28), S( 37, 39) }, // Pawn + {S( 57, 64), S(249, 187), S(-49, -62) }, // Knight OUR PIECES + {S( 0, 0), S(118, 137), S( 10, 27), S( 0, 0) }, // Bishop + {S( -63, -68), S( -5, 3), S(100, 81), S(132, 118), S(-246, -244) }, // Rook + {S(-210, -211), S( 37, 14), S(147, 141), S(161, 105), S(-158, -174), S(-9,-31) } // Queen }; - constexpr int QuadraticTheirs[][PIECE_TYPE_NB] = { + constexpr Score QuadraticTheirs[][PIECE_TYPE_NB] = { // THEIR PIECES // pair pawn knight bishop rook queen - { }, // Bishop pair - { 36, }, // Pawn - { 9, 63, }, // Knight OUR PIECES - { 59, 65, 42, }, // Bishop - { 46, 39, 24, -24, }, // Rook - { 97, 100, -42, 137, 268, } // Queen + { }, // Bishop pair + {S( 33, 30) }, // Pawn + {S( 46, 18), S(106, 84) }, // Knight OUR PIECES + {S( 75, 35), S( 59, 44), S( 60, 15) }, // Bishop + {S( 26, 35), S( 6, 22), S( 38, 39), S(-12, -2) }, // Rook + {S( 97, 93), S(100, 163), S(-58, -91), S(112, 192), S(276, 225) } // Queen }; + #undef S + // Endgame evaluation and scaling functions are accessed directly and not through // the function maps because they correspond to more than one material hash key. Endgame EvaluateKXK[] = { Endgame(WHITE), Endgame(BLACK) }; @@ -82,11 +85,11 @@ namespace { /// piece type for both colors. template - int imbalance(const int pieceCount[][PIECE_TYPE_NB]) { + Score imbalance(const int pieceCount[][PIECE_TYPE_NB]) { constexpr Color Them = ~Us; - int bonus = 0; + Score bonus = SCORE_ZERO; // Second-degree polynomial material imbalance, by Tord Romstad for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1) @@ -213,7 +216,7 @@ Entry* probe(const Position& pos) { { pos.count(BLACK) > 1, pos.count(BLACK), pos.count(BLACK), pos.count(BLACK) , pos.count(BLACK), pos.count(BLACK) } }; - e->value = int16_t((imbalance(pieceCount) - imbalance(pieceCount)) / 16); + e->score = (imbalance(pieceCount) - imbalance(pieceCount)) / 16; return e; } diff --git a/src/material.h b/src/material.h index 80d01655..28da59db 100644 --- a/src/material.h +++ b/src/material.h @@ -37,8 +37,8 @@ namespace Material { struct Entry { - Score imbalance() const { return make_score(value, value); } - Phase game_phase() const { return gamePhase; } + Score imbalance() const { return score; } + Phase game_phase() const { return (Phase)gamePhase; } bool specialized_eval_exists() const { return evaluationFunction != nullptr; } Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); } @@ -57,9 +57,9 @@ struct Entry { const EndgameBase* evaluationFunction; const EndgameBase* scalingFunction[COLOR_NB]; // Could be one for each // side (e.g. KPKP, KBPsK) - int16_t value; + Score score; + int16_t gamePhase; uint8_t factor[COLOR_NB]; - Phase gamePhase; }; typedef HashTable Table; diff --git a/src/pawns.cpp b/src/pawns.cpp index b6d29003..16dbf27a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -66,6 +66,7 @@ namespace { { V(-17), V( -13), V( 100), V( 4), V( 9), V(-16), V(-31) } }; + // KingOnFile[semi-open Us][semi-open Them] contains bonuses/penalties // for king when the king is on a semi-open or open file. constexpr Score KingOnFile[2][2] = {{ S(-19,12), S(-6, 7) }, From d862ba40692797031ec5b0d95e46bcfc5a80f06c Mon Sep 17 00:00:00 2001 From: mstembera Date: Sat, 12 Dec 2020 14:18:38 -0800 Subject: [PATCH 13/88] AVX512, AVX2 and SSSE3 speedups Improves throughput by summing 2 intermediate dot products using 16 bit addition before upconverting to 32 bit. Potential saturation is detected and the code-path is avoided in this case. The saturation can't happen with the current nets, but nets can be constructed that trigger this check. STC https://tests.stockfishchess.org/tests/view/5fd40a861ac1691201888479 LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 25544 W: 2451 L: 2296 D: 20797 Ptnml(0-2): 92, 1761, 8925, 1888, 106 about 5% speedup closes https://github.com/official-stockfish/Stockfish/pull/3261 No functional change --- src/nnue/layers/affine_transform.h | 353 ++++++++++++++++------------- 1 file changed, 198 insertions(+), 155 deletions(-) diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index 0e0515f9..a715ca85 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -66,6 +66,53 @@ namespace Eval::NNUE::Layers { biases_[i] = read_little_endian(stream); for (std::size_t i = 0; i < kOutputDimensions * kPaddedInputDimensions; ++i) weights_[i] = read_little_endian(stream); + +#if defined (USE_SSSE3) + // Determine if quadruplets of weight and input products can be summed using 16bits + // without saturation. We assume worst case combinations of 0 and 127 for all inputs. + if (!stream.fail()) + { + auto can_saturate = [](const WeightType* w, int idx[4]) { + int pSum = 0, nSum = 0; + for (int p = 0; p < 4; ++p) + if (w[idx[p]] > 0) + pSum += w[idx[p]]; + else + nSum += w[idx[p]]; + + return pSum > 258 || nSum < -258; + }; + + for (IndexType i = 0; i < kOutputDimensions; ++i) + { + canSaturate16[i] = false; + const WeightType* w = &weights_[i * kPaddedInputDimensions]; +#if defined (USE_AVX512) + for (IndexType j = 0; j < (kPaddedInputDimensions & ~127) && !canSaturate16[i]; j += 128) + for (int k = 0; k < 64 && !canSaturate16[i]; k += 2) + { + int spacing[4] = { 0, 1, 64, 65 }; + canSaturate16[i] = can_saturate(&w[j + k], spacing); + } +#elif defined (USE_AVX2) + for (IndexType j = 0; j < (kPaddedInputDimensions & ~63) && !canSaturate16[i]; j += 64) + for (int k = 0; k < 32 && !canSaturate16[i]; k += 2) + { + int spacing[4] = { 0, 1, 32, 33 }; + canSaturate16[i] = can_saturate(&w[j + k], spacing); + } +#elif defined (USE_SSSE3) + for (IndexType j = 0; j < (kPaddedInputDimensions & ~31) && !canSaturate16[i]; j += 32) + for (int k = 0; k < 16 && !canSaturate16[i]; k += 2) + { + int spacing[4] = { 0, 1, 16, 17 }; + canSaturate16[i] = can_saturate(&w[j + k], spacing); + } +#endif + } + } +#endif + return !stream.fail(); } @@ -181,13 +228,26 @@ namespace Eval::NNUE::Layers { return _mm512_add_epi32(_mm512_permutexvar_epi32(indices, x), bias); }; -#if defined (USE_VNNI) [[maybe_unused]] auto m512_add_dpbusd_epi32 = [=](__m512i& acc, __m512i a, __m512i b) { +#if defined (USE_VNNI) acc = _mm512_dpbusd_epi32(acc, a, b); #else - [[maybe_unused]] auto m512_dpbusd_epi32 = [=](__m512i a, __m512i b) -> __m512i { __m512i product0 = _mm512_maddubs_epi16(a, b); - return _mm512_madd_epi16(product0, kOnes512); + product0 = _mm512_madd_epi16(product0, kOnes512); + acc = _mm512_add_epi32(acc, product0); +#endif + }; + + [[maybe_unused]] auto m512_add_dpbusd_epi32x2 = [=](__m512i& acc, __m512i a0, __m512i b0, __m512i a1, __m512i b1) { +#if defined (USE_VNNI) + acc = _mm512_dpbusd_epi32(acc, a0, b0); + acc = _mm512_dpbusd_epi32(acc, a1, b1); +#else + __m512i product0 = _mm512_maddubs_epi16(a0, b0); + __m512i product1 = _mm512_maddubs_epi16(a1, b1); + product0 = _mm512_adds_epi16(product0, product1); + product0 = _mm512_madd_epi16(product0, kOnes512); + acc = _mm512_add_epi32(acc, product0); #endif }; @@ -214,13 +274,27 @@ namespace Eval::NNUE::Layers { return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias); }; -#if defined (USE_VNNI) + [[maybe_unused]] auto m256_add_dpbusd_epi32 = [=](__m256i& acc, __m256i a, __m256i b) { +#if defined (USE_VNNI) acc = _mm256_dpbusd_epi32(acc, a, b); #else - [[maybe_unused]] auto m256_dpbusd_epi32 = [=](__m256i a, __m256i b) -> __m256i { __m256i product0 = _mm256_maddubs_epi16(a, b); - return _mm256_madd_epi16(product0, kOnes256); + product0 = _mm256_madd_epi16(product0, kOnes256); + acc = _mm256_add_epi32(acc, product0); +#endif + }; + + [[maybe_unused]] auto m256_add_dpbusd_epi32x2 = [=](__m256i& acc, __m256i a0, __m256i b0, __m256i a1, __m256i b1) { +#if defined (USE_VNNI) + acc = _mm256_dpbusd_epi32(acc, a0, b0); + acc = _mm256_dpbusd_epi32(acc, a1, b1); +#else + __m256i product0 = _mm256_maddubs_epi16(a0, b0); + __m256i product1 = _mm256_maddubs_epi16(a1, b1); + product0 = _mm256_adds_epi16(product0, product1); + product0 = _mm256_madd_epi16(product0, kOnes256); + acc = _mm256_add_epi32(acc, product0); #endif }; @@ -245,9 +319,18 @@ namespace Eval::NNUE::Layers { return _mm_add_epi32(sum0, bias); }; - [[maybe_unused]] auto m128_dpbusd_epi32 = [=](__m128i a, __m128i b) -> __m128i { + [[maybe_unused]] auto m128_add_dpbusd_epi32 = [=](__m128i& acc, __m128i a, __m128i b) { __m128i product0 = _mm_maddubs_epi16(a, b); - return _mm_madd_epi16(product0, kOnes128); + product0 = _mm_madd_epi16(product0, kOnes128); + acc = _mm_add_epi32(acc, product0); + }; + + [[maybe_unused]] auto m128_add_dpbusd_epi32x2 = [=](__m128i& acc, __m128i a0, __m128i b0, __m128i a1, __m128i b1) { + __m128i product0 = _mm_maddubs_epi16(a0, b0); + __m128i product1 = _mm_maddubs_epi16(a1, b1); + product0 = _mm_adds_epi16(product0, product1); + product0 = _mm_madd_epi16(product0, kOnes128); + acc = _mm_add_epi32(acc, product0); }; #endif @@ -291,6 +374,15 @@ namespace Eval::NNUE::Layers { const __m512i bias = *reinterpret_cast(&biases_[i]); __m512i* outptr = reinterpret_cast<__m512i*>(&output[i]); + __m512i sum01a = _mm512_setzero_si512(); + __m512i sum23a = _mm512_setzero_si512(); + __m512i sum45a = _mm512_setzero_si512(); + __m512i sum67a = _mm512_setzero_si512(); + __m512i sum01b = _mm512_setzero_si512(); + __m512i sum23b = _mm512_setzero_si512(); + __m512i sum45b = _mm512_setzero_si512(); + __m512i sum67b = _mm512_setzero_si512(); + const auto row01a = *reinterpret_cast(&weights_[offset01a]); const auto row23a = *reinterpret_cast(&weights_[offset23a]); const auto row45a = *reinterpret_cast(&weights_[offset45a]); @@ -303,16 +395,6 @@ namespace Eval::NNUE::Layers { const __m256i in256 = input_vector256[0]; const __m512i in = _mm512_inserti64x4(_mm512_castsi256_si512(in256), in256, 1); -#if defined (USE_VNNI) - __m512i sum01a = _mm512_setzero_si512(); - __m512i sum23a = _mm512_setzero_si512(); - __m512i sum45a = _mm512_setzero_si512(); - __m512i sum67a = _mm512_setzero_si512(); - __m512i sum01b = _mm512_setzero_si512(); - __m512i sum23b = _mm512_setzero_si512(); - __m512i sum45b = _mm512_setzero_si512(); - __m512i sum67b = _mm512_setzero_si512(); - m512_add_dpbusd_epi32(sum01a, in, row01a); m512_add_dpbusd_epi32(sum23a, in, row23a); m512_add_dpbusd_epi32(sum45a, in, row45a); @@ -321,16 +403,6 @@ namespace Eval::NNUE::Layers { m512_add_dpbusd_epi32(sum23b, in, row23b); m512_add_dpbusd_epi32(sum45b, in, row45b); m512_add_dpbusd_epi32(sum67b, in, row67b); -#else - __m512i sum01a = m512_dpbusd_epi32(in, row01a); - __m512i sum23a = m512_dpbusd_epi32(in, row23a); - __m512i sum45a = m512_dpbusd_epi32(in, row45a); - __m512i sum67a = m512_dpbusd_epi32(in, row67a); - __m512i sum01b = m512_dpbusd_epi32(in, row01b); - __m512i sum23b = m512_dpbusd_epi32(in, row23b); - __m512i sum45b = m512_dpbusd_epi32(in, row45b); - __m512i sum67b = m512_dpbusd_epi32(in, row67b); -#endif *outptr = m512_hadd256x16( sum01a, sum23a, sum45a, sum67a, @@ -351,80 +423,62 @@ namespace Eval::NNUE::Layers { if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) == 0) { + __m512i sum0 = _mm512_setzero_si512(); + __m512i sum1 = _mm512_setzero_si512(); + __m512i sum2 = _mm512_setzero_si512(); + __m512i sum3 = _mm512_setzero_si512(); + const auto row0 = reinterpret_cast(&weights_[offset0]); const auto row1 = reinterpret_cast(&weights_[offset1]); const auto row2 = reinterpret_cast(&weights_[offset2]); const auto row3 = reinterpret_cast(&weights_[offset3]); -#if defined (USE_VNNI) - __m512i sum0 = _mm512_setzero_si512(); - __m512i sum1 = _mm512_setzero_si512(); - __m512i sum2 = _mm512_setzero_si512(); - __m512i sum3 = _mm512_setzero_si512(); - const IndexType kStart = 0; -#else - __m512i sum0 = m512_dpbusd_epi32(input_vector512[0], row0[0]); - __m512i sum1 = m512_dpbusd_epi32(input_vector512[0], row1[0]); - __m512i sum2 = m512_dpbusd_epi32(input_vector512[0], row2[0]); - __m512i sum3 = m512_dpbusd_epi32(input_vector512[0], row3[0]); - const IndexType kStart = 1; -#endif + int j = 0; + if (!canSaturate16x4[i / 4]) + { + for (; j < (int)kNumChunks512 - 1; j += 2) + { + const __m512i in0 = input_vector512[j]; + const __m512i in1 = input_vector512[j + 1]; - for (IndexType j = kStart; j < kNumChunks512; ++j) + m512_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]); + m512_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]); + m512_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]); + m512_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]); + } + } + for (; j < (int)kNumChunks512; ++j) { const __m512i in = input_vector512[j]; -#if defined (USE_VNNI) m512_add_dpbusd_epi32(sum0, in, row0[j]); m512_add_dpbusd_epi32(sum1, in, row1[j]); m512_add_dpbusd_epi32(sum2, in, row2[j]); m512_add_dpbusd_epi32(sum3, in, row3[j]); -#else - sum0 = _mm512_add_epi32(sum0, m512_dpbusd_epi32(in, row0[j])); - sum1 = _mm512_add_epi32(sum1, m512_dpbusd_epi32(in, row1[j])); - sum2 = _mm512_add_epi32(sum2, m512_dpbusd_epi32(in, row2[j])); - sum3 = _mm512_add_epi32(sum3, m512_dpbusd_epi32(in, row3[j])); -#endif } *outptr = m512_haddx4(sum0, sum1, sum2, sum3, bias); } else { + __m256i sum0 = _mm256_setzero_si256(); + __m256i sum1 = _mm256_setzero_si256(); + __m256i sum2 = _mm256_setzero_si256(); + __m256i sum3 = _mm256_setzero_si256(); + const auto row0 = reinterpret_cast(&weights_[offset0]); const auto row1 = reinterpret_cast(&weights_[offset1]); const auto row2 = reinterpret_cast(&weights_[offset2]); const auto row3 = reinterpret_cast(&weights_[offset3]); -#if defined (USE_VNNI) - __m256i sum0 = _mm256_setzero_si256(); - __m256i sum1 = _mm256_setzero_si256(); - __m256i sum2 = _mm256_setzero_si256(); - __m256i sum3 = _mm256_setzero_si256(); - const IndexType kStart = 0; -#else - __m256i sum0 = m256_dpbusd_epi32(input_vector256[0], row0[0]); - __m256i sum1 = m256_dpbusd_epi32(input_vector256[0], row1[0]); - __m256i sum2 = m256_dpbusd_epi32(input_vector256[0], row2[0]); - __m256i sum3 = m256_dpbusd_epi32(input_vector256[0], row3[0]); - const IndexType kStart = 1; -#endif - - for (IndexType j = kStart; j < kNumChunks256; ++j) + for (IndexType j = 0; j < kNumChunks256; ++j) { const __m256i in = input_vector256[j]; -#if defined (USE_VNNI) m256_add_dpbusd_epi32(sum0, in, row0[j]); m256_add_dpbusd_epi32(sum1, in, row1[j]); m256_add_dpbusd_epi32(sum2, in, row2[j]); m256_add_dpbusd_epi32(sum3, in, row3[j]); -#else - sum0 = _mm256_add_epi32(sum0, m256_dpbusd_epi32(in, row0[j])); - sum1 = _mm256_add_epi32(sum1, m256_dpbusd_epi32(in, row1[j])); - sum2 = _mm256_add_epi32(sum2, m256_dpbusd_epi32(in, row2[j])); - sum3 = _mm256_add_epi32(sum3, m256_dpbusd_epi32(in, row3[j])); -#endif } *outptr = m256_haddx4(sum0, sum1, sum2, sum3, bias); @@ -435,50 +489,30 @@ namespace Eval::NNUE::Layers { { if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) == 0) { + __m512i sum0 = _mm512_setzero_si512(); + const auto row0 = reinterpret_cast(&weights_[0]); -#if defined (USE_VNNI) - __m512i sum0 = _mm512_setzero_si512(); - const IndexType kStart = 0; -#else - __m512i sum0 = m512_dpbusd_epi32(input_vector512[0], row0[0]); - const IndexType kStart = 1; -#endif - - for (IndexType j = kStart; j < kNumChunks512; ++j) + for (IndexType j = 0; j < kNumChunks512; ++j) { const __m512i in = input_vector512[j]; -#if defined (USE_VNNI) m512_add_dpbusd_epi32(sum0, in, row0[j]); -#else - sum0 = _mm512_add_epi32(sum0, m512_dpbusd_epi32(in, row0[j])); -#endif } output[0] = m512_hadd(sum0, biases_[0]); } else { + __m256i sum0 = _mm256_setzero_si256(); + const auto row0 = reinterpret_cast(&weights_[0]); -#if defined (USE_VNNI) - __m256i sum0 = _mm256_setzero_si256(); - const IndexType kStart = 0; -#else - __m256i sum0 = m256_dpbusd_epi32(input_vector256[0], row0[0]); - const IndexType kStart = 1; -#endif - - for (IndexType j = kStart; j < kNumChunks256; ++j) + for (IndexType j = 0; j < kNumChunks256; ++j) { const __m256i in = input_vector256[j]; -#if defined (USE_VNNI) m256_add_dpbusd_epi32(sum0, in, row0[j]); -#else - sum0 = _mm256_add_epi32(sum0, m256_dpbusd_epi32(in, row0[j])); -#endif } output[0] = m256_hadd(sum0, biases_[0]); @@ -512,40 +546,38 @@ namespace Eval::NNUE::Layers { const __m128i bias = *reinterpret_cast(&biases_[i]); __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]); + __m256i sum0 = _mm256_setzero_si256(); + __m256i sum1 = _mm256_setzero_si256(); + __m256i sum2 = _mm256_setzero_si256(); + __m256i sum3 = _mm256_setzero_si256(); + const auto row0 = reinterpret_cast(&weights_[offset0]); const auto row1 = reinterpret_cast(&weights_[offset1]); const auto row2 = reinterpret_cast(&weights_[offset2]); const auto row3 = reinterpret_cast(&weights_[offset3]); -#if defined (USE_VNNI) - __m256i sum0 = _mm256_setzero_si256(); - __m256i sum1 = _mm256_setzero_si256(); - __m256i sum2 = _mm256_setzero_si256(); - __m256i sum3 = _mm256_setzero_si256(); - const IndexType kStart = 0; -#else - __m256i sum0 = m256_dpbusd_epi32(input_vector[0], row0[0]); - __m256i sum1 = m256_dpbusd_epi32(input_vector[0], row1[0]); - __m256i sum2 = m256_dpbusd_epi32(input_vector[0], row2[0]); - __m256i sum3 = m256_dpbusd_epi32(input_vector[0], row3[0]); - const IndexType kStart = 1; -#endif - - for (IndexType j = kStart; j < kNumChunks; ++j) + int j = 0; + if (!canSaturate16x4[i / 4]) { - const __m256i in = input_vector[j]; + for (; j < (int)kNumChunks - 1; j += 2) + { + const __m256i in0 = input_vector[j]; + const __m256i in1 = input_vector[j + 1]; -#if defined (USE_VNNI) - m256_add_dpbusd_epi32(sum0, in, row0[j]); - m256_add_dpbusd_epi32(sum1, in, row1[j]); - m256_add_dpbusd_epi32(sum2, in, row2[j]); - m256_add_dpbusd_epi32(sum3, in, row3[j]); -#else - sum0 = _mm256_add_epi32(sum0, m256_dpbusd_epi32(in, row0[j])); - sum1 = _mm256_add_epi32(sum1, m256_dpbusd_epi32(in, row1[j])); - sum2 = _mm256_add_epi32(sum2, m256_dpbusd_epi32(in, row2[j])); - sum3 = _mm256_add_epi32(sum3, m256_dpbusd_epi32(in, row3[j])); -#endif + m256_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]); + m256_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]); + m256_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]); + m256_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]); + } + } + for (; j < (int)kNumChunks; ++j) + { + const __m256i in = input_vector[j]; + + m256_add_dpbusd_epi32(sum0, in, row0[j]); + m256_add_dpbusd_epi32(sum1, in, row1[j]); + m256_add_dpbusd_epi32(sum2, in, row2[j]); + m256_add_dpbusd_epi32(sum3, in, row3[j]); } *outptr = m256_haddx4(sum0, sum1, sum2, sum3, bias); @@ -553,25 +585,15 @@ namespace Eval::NNUE::Layers { } else if constexpr (kOutputDimensions == 1) { + __m256i sum0 = _mm256_setzero_si256(); + const auto row0 = reinterpret_cast(&weights_[0]); -#if defined (USE_VNNI) - __m256i sum0 = _mm256_setzero_si256(); - const IndexType kStart = 0; -#else - __m256i sum0 = m256_dpbusd_epi32(input_vector[0], row0[0]); - const IndexType kStart = 1; -#endif - - for (IndexType j = kStart; j < kNumChunks; ++j) + for (IndexType j = 0; j < kNumChunks; ++j) { - const __m256i in = input_vector[j]; + const __m256i in = input_vector[j]; -#if defined (USE_VNNI) - m256_add_dpbusd_epi32(sum0, in, row0[j]); -#else - sum0 = _mm256_add_epi32(sum0, m256_dpbusd_epi32(in, row0[j])); -#endif + m256_add_dpbusd_epi32(sum0, in, row0[j]); } output[0] = m256_hadd(sum0, biases_[0]); @@ -604,24 +626,38 @@ namespace Eval::NNUE::Layers { const __m128i bias = *reinterpret_cast(&biases_[i]); __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]); + __m128i sum0 = _mm_setzero_si128(); + __m128i sum1 = _mm_setzero_si128(); + __m128i sum2 = _mm_setzero_si128(); + __m128i sum3 = _mm_setzero_si128(); + const auto row0 = reinterpret_cast(&weights_[offset0]); const auto row1 = reinterpret_cast(&weights_[offset1]); const auto row2 = reinterpret_cast(&weights_[offset2]); const auto row3 = reinterpret_cast(&weights_[offset3]); - __m128i sum0 = m128_dpbusd_epi32(input_vector[0], row0[0]); - __m128i sum1 = m128_dpbusd_epi32(input_vector[0], row1[0]); - __m128i sum2 = m128_dpbusd_epi32(input_vector[0], row2[0]); - __m128i sum3 = m128_dpbusd_epi32(input_vector[0], row3[0]); - - for (int j = 1; j < (int)kNumChunks; ++j) + int j = 0; + if (!canSaturate16x4[i / 4]) { - const __m128i in = input_vector[j]; + for (; j < (int)kNumChunks - 1; j += 2) + { + const __m128i in0 = input_vector[j]; + const __m128i in1 = input_vector[j + 1]; - sum0 = _mm_add_epi32(sum0, m128_dpbusd_epi32(in, row0[j])); - sum1 = _mm_add_epi32(sum1, m128_dpbusd_epi32(in, row1[j])); - sum2 = _mm_add_epi32(sum2, m128_dpbusd_epi32(in, row2[j])); - sum3 = _mm_add_epi32(sum3, m128_dpbusd_epi32(in, row3[j])); + m128_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]); + m128_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]); + m128_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]); + m128_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]); + } + } + for (; j < (int)kNumChunks; ++j) + { + const __m128i in = input_vector[j]; + + m128_add_dpbusd_epi32(sum0, in, row0[j]); + m128_add_dpbusd_epi32(sum1, in, row1[j]); + m128_add_dpbusd_epi32(sum2, in, row2[j]); + m128_add_dpbusd_epi32(sum3, in, row3[j]); } *outptr = m128_haddx4(sum0, sum1, sum2, sum3, bias); @@ -629,12 +665,16 @@ namespace Eval::NNUE::Layers { } else if constexpr (kOutputDimensions == 1) { + __m128i sum0 = _mm_setzero_si128(); + const auto row0 = reinterpret_cast(&weights_[0]); - __m128i sum0 = m128_dpbusd_epi32(input_vector[0], row0[0]); + for (int j = 0; j < (int)kNumChunks; ++j) + { + const __m128i in = input_vector[j]; - for (int j = 1; j < (int)kNumChunks; ++j) - sum0 = _mm_add_epi32(sum0, m128_dpbusd_epi32(input_vector[j], row0[j])); + m128_add_dpbusd_epi32(sum0, in, row0[j]); + } output[0] = m128_hadd(sum0, biases_[0]); } @@ -751,8 +791,11 @@ namespace Eval::NNUE::Layers { PreviousLayer previous_layer_; alignas(kCacheLineSize) BiasType biases_[kOutputDimensions]; - alignas(kCacheLineSize) - WeightType weights_[kOutputDimensions * kPaddedInputDimensions]; + alignas(kCacheLineSize) WeightType weights_[kOutputDimensions * kPaddedInputDimensions]; + union { + uint32_t canSaturate16x4[(kOutputDimensions + 3) / 4]; + bool canSaturate16[kOutputDimensions]; + }; }; } // namespace Eval::NNUE::Layers From 16adcb5374a6847b52dd901e183d78c0c8c6cf8a Mon Sep 17 00:00:00 2001 From: pb00067 Date: Sun, 13 Dec 2020 21:23:30 +0100 Subject: [PATCH 14/88] Merge static history into main history, thus simplifying and reducing the memory footprint. I believe using static diff for better move ordering is more suited for low depths, so restrict writing to low depths. Todo: probably the condition for writing can be simplified LTC: LLR: 2.95 (-2.94,2.94) {-0.75,0.25} Total: 18752 W: 768 L: 705 D: 17279 Ptnml(0-2): 7, 635, 8034, 688, 12 https://tests.stockfishchess.org/tests/view/5fd631791ac169120188859e STC: LLR: 2.95 (-2.94,2.94) {-1.25,0.25} Total: 36504 W: 3380 L: 3313 D: 29811 Ptnml(0-2): 116, 2667, 12645, 2682, 142 https://tests.stockfishchess.org/tests/view/5fd5ed861ac1691201888569 closes https://github.com/official-stockfish/Stockfish/pull/3262 bench: 4018036 --- src/movepick.cpp | 9 ++++----- src/movepick.h | 3 --- src/search.cpp | 11 +++-------- src/thread.cpp | 1 - src/thread.h | 1 - 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 9ca1a21f..f5e02385 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -54,9 +54,9 @@ namespace { /// ordering is at the current node. /// MovePicker constructor for the main search -MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const ButterflyHistory* sh, const LowPlyHistory* lp, +MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl) - : pos(p), mainHistory(mh), staticHistory(sh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), + : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { assert(d > 0); @@ -66,9 +66,9 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist } /// MovePicker constructor for quiescence search -MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const ButterflyHistory* sh, +MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs) - : pos(p), mainHistory(mh), staticHistory(sh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) { + : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) { assert(d <= 0); @@ -105,7 +105,6 @@ void MovePicker::score() { else if (Type == QUIETS) m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - + (*staticHistory)[pos.side_to_move()][from_to(m)] + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] diff --git a/src/movepick.h b/src/movepick.h index 7fe98e49..4c0ad551 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -123,12 +123,10 @@ public: MovePicker& operator=(const MovePicker&) = delete; MovePicker(const Position&, Move, Value, const CapturePieceToHistory*); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, - const ButterflyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Square); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, - const ButterflyHistory*, const LowPlyHistory*, const CapturePieceToHistory*, const PieceToHistory**, @@ -145,7 +143,6 @@ private: const Position& pos; const ButterflyHistory* mainHistory; - const ButterflyHistory* staticHistory; const LowPlyHistory* lowPlyHistory; const CapturePieceToHistory* captureHistory; const PieceToHistory** continuationHistory; diff --git a/src/search.cpp b/src/search.cpp index ba9265dd..e825fce7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -815,13 +815,10 @@ namespace { tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } - // Update static history for previous move - if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) + if ((ss-1)->moveCount > 1 && is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture && depth < 7) { - int bonus = ss->staticEval > -(ss-1)->staticEval + 2 * Tempo ? -stat_bonus(depth) : - ss->staticEval < -(ss-1)->staticEval + 2 * Tempo ? stat_bonus(depth) : - 0; - thisThread->staticHistory[~us][from_to((ss-1)->currentMove)] << bonus; + int bonus = std::clamp(- (depth+1) * 2 * int((ss-1)->staticEval + ss->staticEval - 2 * Tempo), -1000, 1000); + thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus; } // Step 7. Razoring (~1 Elo) @@ -985,7 +982,6 @@ moves_loop: // When in check, search starts from here Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, - &thisThread->staticHistory, &thisThread->lowPlyHistory, &captureHistory, contHist, @@ -1536,7 +1532,6 @@ moves_loop: // When in check, search starts from here // queen and checking knight promotions, and other checks(only if depth >= DEPTH_QS_CHECKS) // will be generated. MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, - &thisThread->staticHistory, &thisThread->captureHistory, contHist, to_sq((ss-1)->currentMove)); diff --git a/src/thread.cpp b/src/thread.cpp index bfcdb65e..2fbf745d 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -57,7 +57,6 @@ void Thread::clear() { counterMoves.fill(MOVE_NONE); mainHistory.fill(0); - staticHistory.fill(0); lowPlyHistory.fill(0); captureHistory.fill(0); diff --git a/src/thread.h b/src/thread.h index c05fa941..6a73423b 100644 --- a/src/thread.h +++ b/src/thread.h @@ -69,7 +69,6 @@ public: Depth rootDepth, completedDepth; CounterMoveHistory counterMoves; ButterflyHistory mainHistory; - ButterflyHistory staticHistory; LowPlyHistory lowPlyHistory; CapturePieceToHistory captureHistory; ContinuationHistory continuationHistory[2][2]; From a88a38c3a91749181ffa5d6dc0af7314a70a1c41 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Mon, 14 Dec 2020 03:49:04 +0300 Subject: [PATCH 15/88] Increase reduction in case of stable best move The idea of this patch is pretty simple - we already do more reductions for non-PV and root nodes in case of stable best move for depth > 10. This patch makes us do so if root depth if > 10 instead, which is logical since best move changes (thus instability of it) is counted at root, so it makes a lot of sense to use depth of the root. passed STC https://tests.stockfishchess.org/tests/view/5fd643271ac16912018885c5 LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 13232 W: 1308 L: 1169 D: 10755 Ptnml(0-2): 39, 935, 4535, 1062, 45 passed LTC https://tests.stockfishchess.org/tests/view/5fd68db11ac16912018885f0 LLR: 2.96 (-2.94,2.94) {0.25,1.25} Total: 14024 W: 565 L: 463 D: 12996 Ptnml(0-2): 3, 423, 6062, 517, 7 closes https://github.com/official-stockfish/Stockfish/pull/3263 Bench: 4050630 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index e825fce7..cdbccb4c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1188,7 +1188,7 @@ moves_loop: // When in check, search starts from here r -= 2; // Increase reduction at root and non-PV nodes when the best move does not change frequently - if ((rootNode || !PvNode) && depth > 10 && thisThread->bestMoveChanges <= 2) + if ((rootNode || !PvNode) && thisThread->rootDepth > 10 && thisThread->bestMoveChanges <= 2) r++; // More reductions for late moves if position was not in previous PV From 66a7a8a0cc4a5958c91c46d32197dc04523cdb43 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Wed, 16 Dec 2020 15:35:39 +0200 Subject: [PATCH 16/88] Adjust definition of unsafeSquares and adjust related bonus values. The bonus is now not given whenever there is an enemy piece in front of the pawn. Passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 109472 W: 22097 L: 21673 D: 65702 Ptnml(0-2): 2111, 12800, 24482, 13240, 2103 https://tests.stockfishchess.org/tests/view/5fd8d3740c5870924361ffad Passed LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.25} Total: 39384 W: 5334 L: 4990 D: 29060 Ptnml(0-2): 279, 3648, 11535, 3910, 320 https://tests.stockfishchess.org/tests/view/5fd971ab0c5870924361fff0 closes https://github.com/official-stockfish/Stockfish/pull/3266 Bench: 4488955 --- src/evaluate.cpp | 8 ++++---- src/pawns.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c507aa06..dd5d23b2 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -237,11 +237,11 @@ namespace { // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { - S(0, 0), S(9, 28), S(15, 31), S(17, 39), S(64, 70), S(171, 177), S(277, 260) + S(0, 0), S(7, 27), S(16, 32), S(17, 40), S(64, 71), S(170, 174), S(278, 262) }; constexpr Score RookOnClosedFile = S(10, 5); - constexpr Score RookOnOpenFile[] = { S(19, 7), S(48, 27) }; + constexpr Score RookOnOpenFile[] = { S(19, 6), S(47, 26) }; // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to // which piece type attacks which one. Attacks on lesser pieces which are @@ -788,9 +788,9 @@ namespace { bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN); if (!(pos.pieces(Them) & bb)) - unsafeSquares &= attackedBy[Them][ALL_PIECES]; + unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); - // If there are no enemy attacks on passed pawn span, assign a big bonus. + // If there are no enemy pieces or attacks on passed pawn span, assign a big bonus. // Otherwise assign a smaller bonus if the path to queen is not attacked // and even smaller bonus if it is attacked but block square is not. int k = !unsafeSquares ? 35 : diff --git a/src/pawns.cpp b/src/pawns.cpp index 16dbf27a..ed83fde7 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -37,10 +37,10 @@ namespace { constexpr Score WeakUnopposed = S(13, 25); // Bonus for blocked pawns at 5th or 6th rank - constexpr Score BlockedPawn[2] = { S(-13, -4), S(-5, 2) }; + constexpr Score BlockedPawn[2] = { S(-15, -3), S(-6, 3) }; constexpr Score BlockedStorm[RANK_NB] = { - S(0, 0), S(0, 0), S(76, 78), S(-10, 15), S(-7, 10), S(-4, 6), S(-1, 2) + S(0, 0), S(0, 0), S(75, 78), S(-8, 16), S(-6, 10), S(-6, 6), S(0, 2) }; // Connected pawn bonus From 1f3b5b8b54fbf9d3b74bcba831466eeb1104b421 Mon Sep 17 00:00:00 2001 From: pb00067 Date: Mon, 14 Dec 2020 16:30:56 +0100 Subject: [PATCH 17/88] Simplify condition for assigning static-eval based bonus for quiet move ordering and simplify bonus formula. Due to clamping the bonus to relative low values the impact on high depths is minimal, thus the restriction to low depths seems not necessary. Also the condition of movecount in previous node seems to be not determinant. Passed STC: LLR: 2.95 (-2.94,2.94) {-1.25,0.25} Total: 14600 W: 1424 L: 1323 D: 11853 Ptnml(0-2): 55, 1033, 5020, 1140, 52 https://tests.stockfishchess.org/tests/view/5fd67b381ac16912018885ec Passed LTC: LLR: 2.95 (-2.94,2.94) {-0.75,0.25} Total: 85008 W: 3218 L: 3206 D: 78584 Ptnml(0-2): 49, 2840, 36700, 2880, 35 https://tests.stockfishchess.org/tests/view/5fd6af041ac16912018885f8 closes https://github.com/official-stockfish/Stockfish/pull/3265 bench: 4524994 --- src/search.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index cdbccb4c..e272c10b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -815,9 +815,10 @@ namespace { tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } - if ((ss-1)->moveCount > 1 && is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture && depth < 7) + // Use static evaluation difference to improve quiet move ordering + if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) { - int bonus = std::clamp(- (depth+1) * 2 * int((ss-1)->staticEval + ss->staticEval - 2 * Tempo), -1000, 1000); + int bonus = std::clamp(-depth * 4 * int((ss-1)->staticEval + ss->staticEval - 2 * Tempo), -1000, 1000); thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus; } From 45b05328b6d10b1f72786a59d78ae95c17ec40dd Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 20 Dec 2020 17:50:34 +0200 Subject: [PATCH 18/88] Tweak the formulas for unsafeSquares We give more bonus for a special case: If there are some enemy squares occupied or attacked by the enemy on the passed pawn span, but if they are all attacked by our pawn, use new intermediate factor 30. The main credit goes to Rocky for the idea, with additional tuning and tests. Passed STC: LLR: 2.95 (-2.94,2.94) {-0.25,1.25} Total: 96464 W: 19233 L: 18834 D: 58397 Ptnml(0-2): 1683, 11327, 21950, 11452, 1820 https://tests.stockfishchess.org/tests/view/5fdd21ab3932f79192d39357 Passed LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 81320 W: 10784 L: 10352 D: 60184 Ptnml(0-2): 602, 7524, 24044, 7820, 670 https://tests.stockfishchess.org/tests/view/5fddec983932f79192d393a4 closes https://github.com/official-stockfish/Stockfish/pull/3268 Bench: 4338972 --- src/evaluate.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index dd5d23b2..c945cf53 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -791,11 +791,13 @@ namespace { unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); // If there are no enemy pieces or attacks on passed pawn span, assign a big bonus. + // Or if there is some, but they are all attacked by our pawns, assign a bit smaller bonus. // Otherwise assign a smaller bonus if the path to queen is not attacked // and even smaller bonus if it is attacked but block square is not. - int k = !unsafeSquares ? 35 : - !(unsafeSquares & squaresToQueen) ? 20 : - !(unsafeSquares & blockSq) ? 9 : + int k = !unsafeSquares ? 36 : + !(unsafeSquares & ~attackedBy[Us][PAWN]) ? 30 : + !(unsafeSquares & squaresToQueen) ? 17 : + !(unsafeSquares & blockSq) ? 7 : 0 ; // Assign a larger bonus if the block square is defended From b06ef36ae5f23fa2d4188c9fe6d95c4f551ab035 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sun, 20 Dec 2020 22:28:23 +0100 Subject: [PATCH 19/88] Correct Outflanking calculations in classical eval Take signed value of rank difference between kings squares instead absolute value in outflanking calculation. This change correct evaluation of endgames with one king invading opponent last ranks. Passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 122240 W: 24326 L: 23896 D: 74018 Ptnml(0-2): 2101, 14139, 28236, 14517, 2127 https://tests.stockfishchess.org/tests/view/5fdfc33a3932f79192d394b8 Passed LTC: LLR: 2.97 (-2.94,2.94) {0.25,1.25} Total: 157416 W: 20870 L: 20292 D: 116254 Ptnml(0-2): 973, 13954, 48333, 14418, 1030 https://tests.stockfishchess.org/tests/view/5fe07a453932f79192d39502 closes https://github.com/official-stockfish/Stockfish/pull/3271 Bench: 4162769 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c945cf53..7671f605 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -867,7 +867,7 @@ namespace { Value Evaluation::winnable(Score score) const { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - - distance(pos.square(WHITE), pos.square(BLACK)); + + int(rank_of(pos.square(WHITE)) - rank_of(pos.square(BLACK))); bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); From 51deae899814bbbfd9db5686b824f23105ca8a39 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 25 Dec 2020 01:11:09 +0300 Subject: [PATCH 20/88] Do more LMR for captures This patch enables LMR for all captures at allNodes that were not in PV. Currently we do LMR for all captures at cutNodes so this is an expansion of this logic: now we do LMR for all captures almost at all non-pv nodes, excluding only allNodes that were in PV. passed STC https://tests.stockfishchess.org/tests/view/5fe50b9d3932f79192d3973c LLR: 2.95 (-2.94,2.94) {-0.25,1.25} Total: 83128 W: 7606 L: 7368 D: 68154 Ptnml(0-2): 292, 5905, 28939, 6129, 299 passed LTC https://tests.stockfishchess.org/tests/view/5fe552e43932f79192d39744 LLR: 2.92 (-2.94,2.94) {0.25,1.25} Total: 13968 W: 568 L: 466 D: 12934 Ptnml(0-2): 5, 418, 6043, 506, 12 closes https://github.com/official-stockfish/Stockfish/pull/3273 Bench: 4194835 --- src/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/search.cpp b/src/search.cpp index e272c10b..60a002a9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1172,6 +1172,7 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode + || (!PvNode && !formerPv) || thisThread->ttHitAverage < 432 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); From 4262461457d2227fa788ee9b238651d7ae498339 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Thu, 31 Dec 2020 01:45:37 +0100 Subject: [PATCH 21/88] Tweak capture LMR. Apply the recently added LMR condition for captures at nodes which are not PV or former PV nodes only if capture history is not too good. STC: LLR: 2.96 (-2.94,2.94) {-0.25,1.25} Total: 95296 W: 8917 L: 8660 D: 77719 Ptnml(0-2): 323, 6871, 33045, 7044, 365 https://tests.stockfishchess.org/tests/view/5feca7f46019e097de3ee9ae LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.25} Total: 29216 W: 1172 L: 1034 D: 27010 Ptnml(0-2): 11, 946, 12568, 1060, 23 https://tests.stockfishchess.org/tests/view/5fecf1786019e097de3ee9d5 closes https://github.com/official-stockfish/Stockfish/pull/3283 Bench: 4006138 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 60a002a9..c6db82ba 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1172,7 +1172,7 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || (!PvNode && !formerPv) + || (!PvNode && !formerPv && thisThread->captureHistory[movedPiece][to_sq(move)][type_of(pos.captured_piece())] < 4506) || thisThread->ttHitAverage < 432 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); From c57c71bf5c56665b0339fa983665bdef4bf8a099 Mon Sep 17 00:00:00 2001 From: Unai Corzo Date: Wed, 30 Dec 2020 15:38:25 +0100 Subject: [PATCH 22/88] Assorted parameter tweak Parameter tweak from various tunes and patches. STC https://tests.stockfishchess.org/tests/view/5fec2ae36019e097de3ee94a LLR: 2.97 (-2.94,2.94) {-0.25,1.25} Total: 41976 W: 4032 L: 3848 D: 34096 Ptnml(0-2): 147, 3086, 14341, 3264, 150 LTC https://tests.stockfishchess.org/tests/view/5fec5c3c6019e097de3ee973 LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 23936 W: 970 L: 844 D: 22122 Ptnml(0-2): 14, 749, 10319, 869, 17 closes https://github.com/official-stockfish/Stockfish/pull/3281 bench: 4354546 --- src/movepick.h | 2 +- src/search.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/movepick.h b/src/movepick.h index 4c0ad551..f8472c6e 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -84,7 +84,7 @@ enum StatsType { NoCaptures, Captures }; /// unsuccessful during the current search, and is used for reduction and move /// ordering decisions. It uses 2 tables (one for each color) indexed by /// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards -typedef Stats ButterflyHistory; +typedef Stats ButterflyHistory; /// At higher depths LowPlyHistory records successful quiet moves near the root /// and quiet moves which are/were in the PV (ttPv). It is cleared with each new diff --git a/src/search.cpp b/src/search.cpp index c6db82ba..5f545ef6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -82,7 +82,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return d > 13 ? 29 : 17 * d * d + 134 * d - 134; + return d > 14 ? 29 : 8 * d * d + 224 * d - 215; } // Add a small random component to draw evaluations to avoid 3fold-blindness @@ -838,7 +838,7 @@ namespace { // Step 8. Futility pruning: child node (~50 Elo) if ( !PvNode - && depth < 8 + && depth < 9 && eval - futility_margin(depth, improving) >= beta && eval < VALUE_KNOWN_WIN) // Do not return unproven wins return eval; @@ -893,7 +893,7 @@ namespace { } } - probCutBeta = beta + 183 - 49 * improving; + probCutBeta = beta + 194 - 49 * improving; // Step 10. ProbCut (~10 Elo) // If we have a good enough capture and a reduced search returns a value @@ -1058,11 +1058,11 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 7 && !ss->inCheck - && ss->staticEval + 266 + 170 * lmrDepth <= alpha + && ss->staticEval + 254 + 159 * lmrDepth <= alpha && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 27376) + + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 26394) continue; // Prune moves with negative SEE (~20 Elo) @@ -1078,7 +1078,7 @@ moves_loop: // When in check, search starts from here continue; // SEE based pruning - if (!pos.see_ge(move, Value(-213) * depth)) // (~25 Elo) + if (!pos.see_ge(move, Value(-218) * depth)) // (~25 Elo) continue; } } From 8985c210a1c40770fb81085bd908f757c486963c Mon Sep 17 00:00:00 2001 From: Unai Corzo Date: Sun, 27 Dec 2020 21:19:19 +0100 Subject: [PATCH 23/88] Simplify away late irreversible move extension Late irreversible move extension seems to be useless now. STC https://tests.stockfishchess.org/tests/view/5fe75c5c3932f79192d398ca LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 196192 W: 18111 L: 18278 D: 159803 Ptnml(0-2): 681, 14097, 68652, 14040, 626 LTC https://tests.stockfishchess.org/tests/view/5fe875e23932f79192d39952 LLR: 2.96 (-2.94,2.94) {-0.75,0.25} Total: 28080 W: 1105 L: 1053 D: 25922 Ptnml(0-2): 13, 904, 12158, 948, 17 closes https://github.com/official-stockfish/Stockfish/pull/3279 bench: 4144640 --- src/search.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 5f545ef6..b96efad0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1142,12 +1142,6 @@ moves_loop: // When in check, search starts from here && pos.non_pawn_material() <= 2 * RookValueMg) extension = 1; - // Late irreversible move extension - if ( move == ttMove - && pos.rule50_count() > 80 - && (captureOrPromotion || type_of(movedPiece) == PAWN)) - extension = 2; - // Add extension to new depth newDepth += extension; From 8ec97d161ed82b7c1d8f1f05c305e9a55d8ccff3 Mon Sep 17 00:00:00 2001 From: Unai Corzo Date: Sat, 26 Dec 2020 13:48:04 +0100 Subject: [PATCH 24/88] Remove razoring has become ineffective now. STC https://tests.stockfishchess.org/tests/view/5fe653403932f79192d3981a LLR: 2.95 (-2.94,2.94) {-1.25,0.25} Total: 63448 W: 5965 L: 5934 D: 51549 Ptnml(0-2): 230, 4738, 21769, 4745, 242 LTC https://tests.stockfishchess.org/tests/view/5fe6f0f03932f79192d39856 LLR: 2.93 (-2.94,2.94) {-0.75,0.25} Total: 65368 W: 2485 L: 2459 D: 60424 Ptnml(0-2): 33, 2186, 28230, 2192, 43 closes https://github.com/official-stockfish/Stockfish/pull/3278 bench: 4493379 --- src/search.cpp | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b96efad0..e2c3f584 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -62,8 +62,7 @@ namespace { constexpr uint64_t TtHitAverageWindow = 4096; constexpr uint64_t TtHitAverageResolution = 1024; - // Razor and futility margins - constexpr int RazorMargin = 510; + // Futility margin Value futility_margin(Depth d, bool improving) { return Value(234 * (d - improving)); } @@ -822,12 +821,6 @@ namespace { thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus; } - // Step 7. Razoring (~1 Elo) - if ( !rootNode // The required rootNode PV handling is not available in qsearch - && depth == 1 - && eval <= alpha - RazorMargin) - return qsearch(pos, ss, alpha, beta); - // Set up improving flag that is used in various pruning heuristics // We define position as improving if static evaluation of position is better // Than the previous static evaluation at our turn @@ -836,14 +829,14 @@ namespace { ? ss->staticEval > (ss-4)->staticEval || (ss-4)->staticEval == VALUE_NONE : ss->staticEval > (ss-2)->staticEval; - // Step 8. Futility pruning: child node (~50 Elo) + // Step 7. Futility pruning: child node (~50 Elo) if ( !PvNode && depth < 9 && eval - futility_margin(depth, improving) >= beta && eval < VALUE_KNOWN_WIN) // Do not return unproven wins return eval; - // Step 9. Null move search with verification search (~40 Elo) + // Step 8. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL && (ss-1)->statScore < 22977 @@ -895,7 +888,7 @@ namespace { probCutBeta = beta + 194 - 49 * improving; - // Step 10. ProbCut (~10 Elo) + // Step 9. ProbCut (~10 Elo) // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode @@ -968,7 +961,7 @@ namespace { ss->ttPv = ttPv; } - // Step 11. If the position is not in TT, decrease depth by 2 + // Step 10. If the position is not in TT, decrease depth by 2 if ( PvNode && depth >= 6 && !ttMove) @@ -997,7 +990,7 @@ moves_loop: // When in check, search starts from here // Mark this node as being searched ThreadHolding th(thisThread, posKey, ss->ply); - // Step 12. Loop through all pseudo-legal moves until no moves remain + // Step 11. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. while ((move = mp.next_move(moveCountPruning)) != MOVE_NONE) { @@ -1035,7 +1028,7 @@ moves_loop: // When in check, search starts from here // Calculate new depth for this move newDepth = depth - 1; - // Step 13. Pruning at shallow depth (~200 Elo) + // Step 12. Pruning at shallow depth (~200 Elo) if ( !rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) @@ -1083,7 +1076,7 @@ moves_loop: // When in check, search starts from here } } - // Step 14. Extensions (~75 Elo) + // Step 13. Extensions (~75 Elo) // Singular extension search (~70 Elo). If all moves but one fail low on a // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), @@ -1155,10 +1148,10 @@ moves_loop: // When in check, search starts from here [movedPiece] [to_sq(move)]; - // Step 15. Make the move + // Step 14. Make the move pos.do_move(move, st, givesCheck); - // Step 16. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be + // Step 15. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be // re-searched at full depth. if ( depth >= 3 && moveCount > 1 + 2 * rootNode @@ -1258,7 +1251,7 @@ moves_loop: // When in check, search starts from here didLMR = false; } - // Step 17. Full depth search when LMR is skipped or fails high + // Step 16. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) { value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); @@ -1285,12 +1278,12 @@ moves_loop: // When in check, search starts from here std::min(maxNextDepth, newDepth), false); } - // Step 18. Undo move + // Step 17. Undo move pos.undo_move(move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); - // Step 19. Check for a new best move + // Step 18. Check for a new best move // Finished searching the move. If a stop occurred, the return value of // the search cannot be trusted, and we return immediately without // updating best move, PV and TT. @@ -1367,7 +1360,7 @@ moves_loop: // When in check, search starts from here return VALUE_DRAW; */ - // Step 20. Check for mate and stalemate + // Step 19. Check for mate and stalemate // All legal moves have been searched and if there are no legal moves, it // must be a mate or a stalemate. If we are in a singular extension search then // return a fail low score. From d21e421ad74cff3b157d156d6ea8fdee3634e75b Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Fri, 25 Dec 2020 16:19:04 +0200 Subject: [PATCH 25/88] WeakUnopposed penalty for backwards on file A or H Do not give the WeakUnopposed penalty for backwards on file A or H The original idea comes from Lolligerhans, and a series of tunings and tests done by Fauzi. Passed STC: LLR: 2.96 (-2.94,2.94) {-0.25,1.25} Total: 140864 W: 28127 L: 27660 D: 85077 Ptnml(0-2): 2529, 16660, 31735, 16831, 2677 https://tests.stockfishchess.org/tests/view/5fe39dec3932f79192d39673 Passed LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.25} Total: 67568 W: 8993 L: 8590 D: 49985 Ptnml(0-2): 523, 6176, 19983, 6579, 523 https://tests.stockfishchess.org/tests/view/5fe3dd1b3932f79192d39693 closes https://github.com/official-stockfish/Stockfish/pull/3275 Bench: 4109336 --- src/pawns.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index ed83fde7..d3d2ea0f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -30,11 +30,11 @@ namespace { #define S(mg, eg) make_score(mg, eg) // Pawn penalties - constexpr Score Backward = S( 8, 25); - constexpr Score Doubled = S(10, 55); - constexpr Score Isolated = S( 3, 15); - constexpr Score WeakLever = S( 3, 55); - constexpr Score WeakUnopposed = S(13, 25); + constexpr Score Backward = S( 6, 23); + constexpr Score Doubled = S(13, 53); + constexpr Score Isolated = S( 2, 15); + constexpr Score WeakLever = S( 5, 57); + constexpr Score WeakUnopposed = S(16, 22); // Bonus for blocked pawns at 5th or 6th rank constexpr Score BlockedPawn[2] = { S(-15, -3), S(-6, 3) }; @@ -69,8 +69,8 @@ namespace { // KingOnFile[semi-open Us][semi-open Them] contains bonuses/penalties // for king when the king is on a semi-open or open file. - constexpr Score KingOnFile[2][2] = {{ S(-19,12), S(-6, 7) }, - { S( 0, 2), S( 6,-5) }}; + constexpr Score KingOnFile[2][2] = {{ S(-21,10), S(-7, 1) }, + { S( 0,-3), S( 9,-4) }}; #undef S #undef V @@ -172,7 +172,7 @@ namespace { else if (backward) score -= Backward - + WeakUnopposed * !opposed; + + WeakUnopposed * !opposed * bool(~(FileABB | FileHBB) & s); if (!support) score -= Doubled * doubled From 23c385ec36f9d5a9514ec5b0811ec99d08b45e90 Mon Sep 17 00:00:00 2001 From: MaximMolchanov Date: Wed, 6 Jan 2021 05:29:32 +0200 Subject: [PATCH 26/88] Affine transform refactoring. Reordered weights in such a way that accumulated sum fits to output. Weights are grouped in blocks of four elements because four int8 (weight type) corresponds to one int32 (output type). No horizontal additions. Grouped AVX512, AVX2 and SSSE3 implementations. Repeated code was removed. An earlier version passed STC: LLR: 2.97 (-2.94,2.94) {-0.25,1.25} Total: 15336 W: 1495 L: 1355 D: 12486 Ptnml(0-2): 44, 1054, 5350, 1158, 62 https://tests.stockfishchess.org/tests/view/5ff60e106019e097de3eefd5 Speedup depends on the architecture, up to 4% measured on a NNUE only bench. closes https://github.com/official-stockfish/Stockfish/pull/3287 No functional change --- src/nnue/layers/affine_transform.h | 633 +++++++---------------------- 1 file changed, 137 insertions(+), 496 deletions(-) diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index a715ca85..ab2beab7 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -41,6 +41,11 @@ namespace Eval::NNUE::Layers { static constexpr IndexType kOutputDimensions = OutputDimensions; static constexpr IndexType kPaddedInputDimensions = CeilToMultiple(kInputDimensions, kMaxSimdWidth); +#if defined (USE_AVX512) + static constexpr const IndexType kOutputSimdWidth = kSimdWidth / 2; +#elif defined (USE_SSSE3) + static constexpr const IndexType kOutputSimdWidth = kSimdWidth / 4; +#endif // Size of forward propagation buffer used in this layer static constexpr std::size_t kSelfBufferSize = @@ -65,51 +70,55 @@ namespace Eval::NNUE::Layers { for (std::size_t i = 0; i < kOutputDimensions; ++i) biases_[i] = read_little_endian(stream); for (std::size_t i = 0; i < kOutputDimensions * kPaddedInputDimensions; ++i) +#if !defined (USE_SSSE3) weights_[i] = read_little_endian(stream); +#else + weights_[ + (i / 4) % (kPaddedInputDimensions / 4) * kOutputDimensions * 4 + + i / kPaddedInputDimensions * 4 + + i % 4 + ] = read_little_endian(stream); -#if defined (USE_SSSE3) - // Determine if quadruplets of weight and input products can be summed using 16bits + // Determine if eights of weight and input products can be summed using 16bits // without saturation. We assume worst case combinations of 0 and 127 for all inputs. - if (!stream.fail()) + if (kOutputDimensions > 1 && !stream.fail()) { - auto can_saturate = [](const WeightType* w, int idx[4]) { - int pSum = 0, nSum = 0; - for (int p = 0; p < 4; ++p) - if (w[idx[p]] > 0) - pSum += w[idx[p]]; - else - nSum += w[idx[p]]; + canSaturate16.count = 0; +#if !defined(USE_VNNI) + for (IndexType i = 0; i < kPaddedInputDimensions; i += 16) + for (IndexType j = 0; j < kOutputDimensions; ++j) + for (int x = 0; x < 2; ++x) + { + WeightType* w = &weights_[i * kOutputDimensions + j * 4 + x * 2]; + int sum[2] = {0, 0}; + for (int k = 0; k < 8; ++k) + { + IndexType idx = k / 2 * kOutputDimensions * 4 + k % 2; + sum[w[idx] < 0] += w[idx]; + } + for (int sign : {-1, 1}) + while (sign * sum[sign == -1] > 258) + { + int maxK = 0, maxW = 0; + for (int k = 0; k < 8; ++k) + { + IndexType idx = k / 2 * kOutputDimensions * 4 + k % 2; + if (maxW < sign * w[idx]) + maxK = k, maxW = sign * w[idx]; + } - return pSum > 258 || nSum < -258; - }; + IndexType idx = maxK / 2 * kOutputDimensions * 4 + maxK % 2; + sum[sign == -1] -= w[idx]; + canSaturate16.add(j, i + maxK / 2 * 4 + maxK % 2 + x * 2, w[idx]); + w[idx] = 0; + } + } - for (IndexType i = 0; i < kOutputDimensions; ++i) - { - canSaturate16[i] = false; - const WeightType* w = &weights_[i * kPaddedInputDimensions]; -#if defined (USE_AVX512) - for (IndexType j = 0; j < (kPaddedInputDimensions & ~127) && !canSaturate16[i]; j += 128) - for (int k = 0; k < 64 && !canSaturate16[i]; k += 2) - { - int spacing[4] = { 0, 1, 64, 65 }; - canSaturate16[i] = can_saturate(&w[j + k], spacing); - } -#elif defined (USE_AVX2) - for (IndexType j = 0; j < (kPaddedInputDimensions & ~63) && !canSaturate16[i]; j += 64) - for (int k = 0; k < 32 && !canSaturate16[i]; k += 2) - { - int spacing[4] = { 0, 1, 32, 33 }; - canSaturate16[i] = can_saturate(&w[j + k], spacing); - } -#elif defined (USE_SSSE3) - for (IndexType j = 0; j < (kPaddedInputDimensions & ~31) && !canSaturate16[i]; j += 32) - for (int k = 0; k < 16 && !canSaturate16[i]; k += 2) - { - int spacing[4] = { 0, 1, 16, 17 }; - canSaturate16[i] = can_saturate(&w[j + k], spacing); - } + // Non functional optimization for faster more linear access + std::sort(canSaturate16.ids, canSaturate16.ids + canSaturate16.count, + [](const typename CanSaturate::Entry& e1, const typename CanSaturate::Entry& e2) + { return e1.in == e2.in ? e1.out < e2.out : e1.in < e2.in; }); #endif - } } #endif @@ -130,104 +139,6 @@ namespace Eval::NNUE::Layers { return _mm512_reduce_add_epi32(sum) + bias; }; - // This function takes - // sum0 = [xmm0a, xmm0b, xmm0c, xmm0d] - // sum1 = [xmm1a, xmm1b, xmm1c, xmm1d] - // sum2 = [xmm2a, xmm2b, xmm2c, xmm2d] - // sum3 = [xmm3a, xmm3b, xmm3c, xmm3d] - // and returns - // ret = [ - // reduce_add_epi32(xmm0a), reduce_add_epi32(xmm1a), reduce_add_epi32(xmm2a), reduce_add_epi32(xmm3a), - // reduce_add_epi32(xmm0b), reduce_add_epi32(xmm1b), reduce_add_epi32(xmm2b), reduce_add_epi32(xmm3b), - // reduce_add_epi32(xmm0c), reduce_add_epi32(xmm1c), reduce_add_epi32(xmm2c), reduce_add_epi32(xmm3c), - // reduce_add_epi32(xmm0d), reduce_add_epi32(xmm1d), reduce_add_epi32(xmm2d), reduce_add_epi32(xmm3d) - // ] - [[maybe_unused]] auto m512_hadd128x16_interleave = []( - __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3) -> __m512i { - - __m512i sum01a = _mm512_unpacklo_epi32(sum0, sum1); - __m512i sum01b = _mm512_unpackhi_epi32(sum0, sum1); - - __m512i sum23a = _mm512_unpacklo_epi32(sum2, sum3); - __m512i sum23b = _mm512_unpackhi_epi32(sum2, sum3); - - __m512i sum01 = _mm512_add_epi32(sum01a, sum01b); - __m512i sum23 = _mm512_add_epi32(sum23a, sum23b); - - __m512i sum0123a = _mm512_unpacklo_epi64(sum01, sum23); - __m512i sum0123b = _mm512_unpackhi_epi64(sum01, sum23); - - return _mm512_add_epi32(sum0123a, sum0123b); - }; - - [[maybe_unused]] auto m512_haddx4 = [m512_hadd128x16_interleave]( - __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3, __m128i bias) -> __m128i { - - __m512i sum = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3); - - __m256i sum256lo = _mm512_castsi512_si256(sum); - __m256i sum256hi = _mm512_extracti64x4_epi64(sum, 1); - - sum256lo = _mm256_add_epi32(sum256lo, sum256hi); - - __m128i sum128lo = _mm256_castsi256_si128(sum256lo); - __m128i sum128hi = _mm256_extracti128_si256(sum256lo, 1); - - return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias); - }; - - [[maybe_unused]] auto m512_haddx8 = [m512_hadd128x16_interleave]( - __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3, - __m512i sum4, __m512i sum5, __m512i sum6, __m512i sum7, __m256i bias) -> __m256i { - - __m512i suma = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3); - __m512i sumb = m512_hadd128x16_interleave(sum4, sum5, sum6, sum7); - - __m512i indices0 = _mm512_setr_epi64(0, 1, 8, 9, 4, 5, 12, 13); - __m512i indices1 = _mm512_setr_epi64(2, 3, 10, 11, 6, 7, 14, 15); - __m512i x = _mm512_add_epi32( - _mm512_permutex2var_epi64(suma, indices0, sumb), - _mm512_permutex2var_epi64(suma, indices1, sumb)); - - __m256i sum256lo = _mm512_castsi512_si256(x); - __m256i sum256hi = _mm512_extracti64x4_epi64(x, 1); - - return _mm256_add_epi32(_mm256_add_epi32(sum256lo, sum256hi), bias); - }; - - [[maybe_unused]] auto m512_hadd256x8 =[m512_hadd128x16_interleave]( - __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3, __m256i bias) -> __m256i { - - __m512i sum = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3); - - __m512i indices = _mm512_setr_epi32( - 0, 4, 8, 12, 2, 6, 10, 14, - 1, 5, 9, 13, 3, 7, 11, 15); - sum = _mm512_permutexvar_epi32(indices, sum); - - __m256i sum256lo = _mm512_castsi512_si256(sum); - __m256i sum256hi = _mm512_extracti64x4_epi64(sum, 1); - - return _mm256_add_epi32(_mm256_hadd_epi32(sum256lo, sum256hi), bias); - }; - - [[maybe_unused]] auto m512_hadd256x16 = [m512_hadd128x16_interleave]( - __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3, - __m512i sum4, __m512i sum5, __m512i sum6, __m512i sum7, __m512i bias) -> __m512i { - - __m512i suma = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3); - __m512i sumb = m512_hadd128x16_interleave(sum4, sum5, sum6, sum7); - - __m512i indices0 = _mm512_setr_epi64(0, 1, 8, 9, 4, 5, 12, 13); - __m512i indices1 = _mm512_setr_epi64(2, 3, 10, 11, 6, 7, 14, 15); - __m512i x = _mm512_add_epi32( - _mm512_permutex2var_epi64(suma, indices0, sumb), - _mm512_permutex2var_epi64(suma, indices1, sumb)); - - __m512i indices = _mm512_setr_epi32(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15); - return _mm512_add_epi32(_mm512_permutexvar_epi32(indices, x), bias); - }; - [[maybe_unused]] auto m512_add_dpbusd_epi32 = [=](__m512i& acc, __m512i a, __m512i b) { #if defined (USE_VNNI) acc = _mm512_dpbusd_epi32(acc, a, b); @@ -238,14 +149,21 @@ namespace Eval::NNUE::Layers { #endif }; - [[maybe_unused]] auto m512_add_dpbusd_epi32x2 = [=](__m512i& acc, __m512i a0, __m512i b0, __m512i a1, __m512i b1) { + [[maybe_unused]] auto m512_add_dpbusd_epi32x4 = [=](__m512i& acc, __m512i a0, __m512i b0, __m512i a1, __m512i b1, + __m512i a2, __m512i b2, __m512i a3, __m512i b3) { #if defined (USE_VNNI) acc = _mm512_dpbusd_epi32(acc, a0, b0); acc = _mm512_dpbusd_epi32(acc, a1, b1); + acc = _mm512_dpbusd_epi32(acc, a2, b2); + acc = _mm512_dpbusd_epi32(acc, a3, b3); #else __m512i product0 = _mm512_maddubs_epi16(a0, b0); __m512i product1 = _mm512_maddubs_epi16(a1, b1); - product0 = _mm512_adds_epi16(product0, product1); + __m512i product2 = _mm512_maddubs_epi16(a2, b2); + __m512i product3 = _mm512_maddubs_epi16(a3, b3); + product0 = _mm512_add_epi16(product0, product1); + product2 = _mm512_add_epi16(product2, product3); + product0 = _mm512_add_epi16(product0, product2); product0 = _mm512_madd_epi16(product0, kOnes512); acc = _mm512_add_epi32(acc, product0); #endif @@ -263,18 +181,6 @@ namespace Eval::NNUE::Layers { return _mm_cvtsi128_si32(sum128) + bias; }; - [[maybe_unused]] auto m256_haddx4 = [](__m256i sum0, __m256i sum1, __m256i sum2, __m256i sum3, __m128i bias) -> __m128i { - sum0 = _mm256_hadd_epi32(sum0, sum1); - sum2 = _mm256_hadd_epi32(sum2, sum3); - - sum0 = _mm256_hadd_epi32(sum0, sum2); - - __m128i sum128lo = _mm256_castsi256_si128(sum0); - __m128i sum128hi = _mm256_extracti128_si256(sum0, 1); - - return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias); - }; - [[maybe_unused]] auto m256_add_dpbusd_epi32 = [=](__m256i& acc, __m256i a, __m256i b) { #if defined (USE_VNNI) acc = _mm256_dpbusd_epi32(acc, a, b); @@ -285,21 +191,27 @@ namespace Eval::NNUE::Layers { #endif }; - [[maybe_unused]] auto m256_add_dpbusd_epi32x2 = [=](__m256i& acc, __m256i a0, __m256i b0, __m256i a1, __m256i b1) { + [[maybe_unused]] auto m256_add_dpbusd_epi32x4 = [=](__m256i& acc, __m256i a0, __m256i b0, __m256i a1, __m256i b1, + __m256i a2, __m256i b2, __m256i a3, __m256i b3) { #if defined (USE_VNNI) acc = _mm256_dpbusd_epi32(acc, a0, b0); acc = _mm256_dpbusd_epi32(acc, a1, b1); + acc = _mm256_dpbusd_epi32(acc, a2, b2); + acc = _mm256_dpbusd_epi32(acc, a3, b3); #else __m256i product0 = _mm256_maddubs_epi16(a0, b0); __m256i product1 = _mm256_maddubs_epi16(a1, b1); - product0 = _mm256_adds_epi16(product0, product1); + __m256i product2 = _mm256_maddubs_epi16(a2, b2); + __m256i product3 = _mm256_maddubs_epi16(a3, b3); + product0 = _mm256_add_epi16(product0, product1); + product2 = _mm256_add_epi16(product2, product3); + product0 = _mm256_add_epi16(product0, product2); product0 = _mm256_madd_epi16(product0, kOnes256); acc = _mm256_add_epi32(acc, product0); #endif }; #endif - #if defined (USE_SSSE3) [[maybe_unused]] const __m128i kOnes128 = _mm_set1_epi16(1); @@ -310,25 +222,21 @@ namespace Eval::NNUE::Layers { return _mm_cvtsi128_si32(sum) + bias; }; - [[maybe_unused]] auto m128_haddx4 = [](__m128i sum0, __m128i sum1, __m128i sum2, __m128i sum3, __m128i bias) -> __m128i { - sum0 = _mm_hadd_epi32(sum0, sum1); - sum2 = _mm_hadd_epi32(sum2, sum3); - - sum0 = _mm_hadd_epi32(sum0, sum2); - - return _mm_add_epi32(sum0, bias); - }; - [[maybe_unused]] auto m128_add_dpbusd_epi32 = [=](__m128i& acc, __m128i a, __m128i b) { __m128i product0 = _mm_maddubs_epi16(a, b); product0 = _mm_madd_epi16(product0, kOnes128); acc = _mm_add_epi32(acc, product0); }; - [[maybe_unused]] auto m128_add_dpbusd_epi32x2 = [=](__m128i& acc, __m128i a0, __m128i b0, __m128i a1, __m128i b1) { + [[maybe_unused]] auto m128_add_dpbusd_epi32x4 = [=](__m128i& acc, __m128i a0, __m128i b0, __m128i a1, __m128i b1, + __m128i a2, __m128i b2, __m128i a3, __m128i b3) { __m128i product0 = _mm_maddubs_epi16(a0, b0); __m128i product1 = _mm_maddubs_epi16(a1, b1); + __m128i product2 = _mm_maddubs_epi16(a2, b2); + __m128i product3 = _mm_maddubs_epi16(a3, b3); product0 = _mm_adds_epi16(product0, product1); + product2 = _mm_adds_epi16(product2, product3); + product0 = _mm_adds_epi16(product0, product2); product0 = _mm_madd_epi16(product0, kOnes128); acc = _mm_add_epi32(acc, product0); }; @@ -336,353 +244,77 @@ namespace Eval::NNUE::Layers { #endif #if defined (USE_AVX512) - - constexpr IndexType kNumChunks512 = kPaddedInputDimensions / (kSimdWidth * 2); - constexpr IndexType kNumChunks256 = kPaddedInputDimensions / kSimdWidth; - - const auto output = reinterpret_cast(buffer); - - // Since to saturate a zmm register it takes 64 bytes we - // cannot use AVX512 for the smaller affine transforms. - // Instead we fallback to a AVX2 implementation if the - // kInputDimensions isn't a multiple of 64. - // Note that this means that for example for - // kInputDimensions of 96 we fallback to AVX2 even though - // the first 64 elements could be processed with AVX512. - // This is caused by mixing the __m256 and __m512 variables - // required to better handle that case and it would - // require handling more cases statically not to lose performance. - // This should be revisited if such input dimensions are to be considered. - [[maybe_unused]] const auto input_vector512 = reinterpret_cast(input); - [[maybe_unused]] const auto input_vector256 = reinterpret_cast(input); - - // kOutputDimensions is either 1 or a multiple of kSimdWidth - // because then it is also an input dimension. - if constexpr (kOutputDimensions % 16 == 0 && kNumChunks256 == 1) - { - for (IndexType i = 0; i < kOutputDimensions; i += 16) - { - const IndexType offset01a = (i + 0) * kPaddedInputDimensions; - const IndexType offset23a = (i + 2) * kPaddedInputDimensions; - const IndexType offset45a = (i + 4) * kPaddedInputDimensions; - const IndexType offset67a = (i + 6) * kPaddedInputDimensions; - const IndexType offset01b = (i + 8) * kPaddedInputDimensions; - const IndexType offset23b = (i + 10) * kPaddedInputDimensions; - const IndexType offset45b = (i + 12) * kPaddedInputDimensions; - const IndexType offset67b = (i + 14) * kPaddedInputDimensions; - - const __m512i bias = *reinterpret_cast(&biases_[i]); - __m512i* outptr = reinterpret_cast<__m512i*>(&output[i]); - - __m512i sum01a = _mm512_setzero_si512(); - __m512i sum23a = _mm512_setzero_si512(); - __m512i sum45a = _mm512_setzero_si512(); - __m512i sum67a = _mm512_setzero_si512(); - __m512i sum01b = _mm512_setzero_si512(); - __m512i sum23b = _mm512_setzero_si512(); - __m512i sum45b = _mm512_setzero_si512(); - __m512i sum67b = _mm512_setzero_si512(); - - const auto row01a = *reinterpret_cast(&weights_[offset01a]); - const auto row23a = *reinterpret_cast(&weights_[offset23a]); - const auto row45a = *reinterpret_cast(&weights_[offset45a]); - const auto row67a = *reinterpret_cast(&weights_[offset67a]); - const auto row01b = *reinterpret_cast(&weights_[offset01b]); - const auto row23b = *reinterpret_cast(&weights_[offset23b]); - const auto row45b = *reinterpret_cast(&weights_[offset45b]); - const auto row67b = *reinterpret_cast(&weights_[offset67b]); - - const __m256i in256 = input_vector256[0]; - const __m512i in = _mm512_inserti64x4(_mm512_castsi256_si512(in256), in256, 1); - - m512_add_dpbusd_epi32(sum01a, in, row01a); - m512_add_dpbusd_epi32(sum23a, in, row23a); - m512_add_dpbusd_epi32(sum45a, in, row45a); - m512_add_dpbusd_epi32(sum67a, in, row67a); - m512_add_dpbusd_epi32(sum01b, in, row01b); - m512_add_dpbusd_epi32(sum23b, in, row23b); - m512_add_dpbusd_epi32(sum45b, in, row45b); - m512_add_dpbusd_epi32(sum67b, in, row67b); - - *outptr = m512_hadd256x16( - sum01a, sum23a, sum45a, sum67a, - sum01b, sum23b, sum45b, sum67b, bias); - } - } - else if constexpr (kOutputDimensions % 4 == 0) - { - for (IndexType i = 0; i < kOutputDimensions; i += 4) - { - const IndexType offset0 = (i + 0) * kPaddedInputDimensions; - const IndexType offset1 = (i + 1) * kPaddedInputDimensions; - const IndexType offset2 = (i + 2) * kPaddedInputDimensions; - const IndexType offset3 = (i + 3) * kPaddedInputDimensions; - - const __m128i bias = *reinterpret_cast(&biases_[i]); - __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]); - - if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) == 0) - { - __m512i sum0 = _mm512_setzero_si512(); - __m512i sum1 = _mm512_setzero_si512(); - __m512i sum2 = _mm512_setzero_si512(); - __m512i sum3 = _mm512_setzero_si512(); - - const auto row0 = reinterpret_cast(&weights_[offset0]); - const auto row1 = reinterpret_cast(&weights_[offset1]); - const auto row2 = reinterpret_cast(&weights_[offset2]); - const auto row3 = reinterpret_cast(&weights_[offset3]); - - int j = 0; - if (!canSaturate16x4[i / 4]) - { - for (; j < (int)kNumChunks512 - 1; j += 2) - { - const __m512i in0 = input_vector512[j]; - const __m512i in1 = input_vector512[j + 1]; - - m512_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]); - m512_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]); - m512_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]); - m512_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]); - } - } - for (; j < (int)kNumChunks512; ++j) - { - const __m512i in = input_vector512[j]; - - m512_add_dpbusd_epi32(sum0, in, row0[j]); - m512_add_dpbusd_epi32(sum1, in, row1[j]); - m512_add_dpbusd_epi32(sum2, in, row2[j]); - m512_add_dpbusd_epi32(sum3, in, row3[j]); - } - - *outptr = m512_haddx4(sum0, sum1, sum2, sum3, bias); - } - else - { - __m256i sum0 = _mm256_setzero_si256(); - __m256i sum1 = _mm256_setzero_si256(); - __m256i sum2 = _mm256_setzero_si256(); - __m256i sum3 = _mm256_setzero_si256(); - - const auto row0 = reinterpret_cast(&weights_[offset0]); - const auto row1 = reinterpret_cast(&weights_[offset1]); - const auto row2 = reinterpret_cast(&weights_[offset2]); - const auto row3 = reinterpret_cast(&weights_[offset3]); - - for (IndexType j = 0; j < kNumChunks256; ++j) - { - const __m256i in = input_vector256[j]; - - m256_add_dpbusd_epi32(sum0, in, row0[j]); - m256_add_dpbusd_epi32(sum1, in, row1[j]); - m256_add_dpbusd_epi32(sum2, in, row2[j]); - m256_add_dpbusd_epi32(sum3, in, row3[j]); - } - - *outptr = m256_haddx4(sum0, sum1, sum2, sum3, bias); - } - } - } - else if constexpr (kOutputDimensions == 1) - { - if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) == 0) - { - __m512i sum0 = _mm512_setzero_si512(); - - const auto row0 = reinterpret_cast(&weights_[0]); - - for (IndexType j = 0; j < kNumChunks512; ++j) - { - const __m512i in = input_vector512[j]; - - m512_add_dpbusd_epi32(sum0, in, row0[j]); - } - - output[0] = m512_hadd(sum0, biases_[0]); - } - else - { - __m256i sum0 = _mm256_setzero_si256(); - - const auto row0 = reinterpret_cast(&weights_[0]); - - for (IndexType j = 0; j < kNumChunks256; ++j) - { - const __m256i in = input_vector256[j]; - - m256_add_dpbusd_epi32(sum0, in, row0[j]); - } - - output[0] = m256_hadd(sum0, biases_[0]); - } - } - else - { - // This case can never happen because kOutputDimensions - // is always 1 or a multiple of kSimdWidth. - assert(false); - } - + using vec_t = __m512i; + #define vec_setzero _mm512_setzero_si512 + #define vec_set_32 _mm512_set1_epi32 + auto& vec_add_dpbusd_32 = m512_add_dpbusd_epi32; + auto& vec_add_dpbusd_32x4 = m512_add_dpbusd_epi32x4; + auto& vec_hadd = m512_hadd; #elif defined (USE_AVX2) + using vec_t = __m256i; + #define vec_setzero _mm256_setzero_si256 + #define vec_set_32 _mm256_set1_epi32 + auto& vec_add_dpbusd_32 = m256_add_dpbusd_epi32; + auto& vec_add_dpbusd_32x4 = m256_add_dpbusd_epi32x4; + auto& vec_hadd = m256_hadd; +#elif defined (USE_SSSE3) + using vec_t = __m128i; + #define vec_setzero _mm_setzero_si128 + #define vec_set_32 _mm_set1_epi32 + auto& vec_add_dpbusd_32 = m128_add_dpbusd_epi32; + auto& vec_add_dpbusd_32x4 = m128_add_dpbusd_epi32x4; + auto& vec_hadd = m128_hadd; +#endif - constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth; +#if defined (USE_SSSE3) const auto output = reinterpret_cast(buffer); - const auto input_vector = reinterpret_cast(input); + const auto input_vector = reinterpret_cast(input); + + static_assert(kOutputDimensions % kOutputSimdWidth == 0 || kOutputDimensions == 1); // kOutputDimensions is either 1 or a multiple of kSimdWidth // because then it is also an input dimension. - if constexpr (kOutputDimensions % 4 == 0) + if constexpr (kOutputDimensions % kOutputSimdWidth == 0) { - for (IndexType i = 0; i < kOutputDimensions; i += 4) - { - const IndexType offset0 = (i + 0) * kPaddedInputDimensions; - const IndexType offset1 = (i + 1) * kPaddedInputDimensions; - const IndexType offset2 = (i + 2) * kPaddedInputDimensions; - const IndexType offset3 = (i + 3) * kPaddedInputDimensions; + constexpr IndexType kNumChunks = kPaddedInputDimensions / 4; - const __m128i bias = *reinterpret_cast(&biases_[i]); - __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]); + const auto input32 = reinterpret_cast(input); + vec_t* outptr = reinterpret_cast(output); + std::memcpy(output, biases_, kOutputDimensions * sizeof(OutputType)); - __m256i sum0 = _mm256_setzero_si256(); - __m256i sum1 = _mm256_setzero_si256(); - __m256i sum2 = _mm256_setzero_si256(); - __m256i sum3 = _mm256_setzero_si256(); - - const auto row0 = reinterpret_cast(&weights_[offset0]); - const auto row1 = reinterpret_cast(&weights_[offset1]); - const auto row2 = reinterpret_cast(&weights_[offset2]); - const auto row3 = reinterpret_cast(&weights_[offset3]); - - int j = 0; - if (!canSaturate16x4[i / 4]) + for (int i = 0; i < (int)kNumChunks - 3; i += 4) { - for (; j < (int)kNumChunks - 1; j += 2) - { - const __m256i in0 = input_vector[j]; - const __m256i in1 = input_vector[j + 1]; - - m256_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]); - m256_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]); - m256_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]); - m256_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]); - } + const vec_t in0 = vec_set_32(input32[i + 0]); + const vec_t in1 = vec_set_32(input32[i + 1]); + const vec_t in2 = vec_set_32(input32[i + 2]); + const vec_t in3 = vec_set_32(input32[i + 3]); + const auto col0 = reinterpret_cast(&weights_[(i + 0) * kOutputDimensions * 4]); + const auto col1 = reinterpret_cast(&weights_[(i + 1) * kOutputDimensions * 4]); + const auto col2 = reinterpret_cast(&weights_[(i + 2) * kOutputDimensions * 4]); + const auto col3 = reinterpret_cast(&weights_[(i + 3) * kOutputDimensions * 4]); + for (int j = 0; j * kOutputSimdWidth < kOutputDimensions; ++j) + vec_add_dpbusd_32x4(outptr[j], in0, col0[j], in1, col1[j], in2, col2[j], in3, col3[j]); } - for (; j < (int)kNumChunks; ++j) - { - const __m256i in = input_vector[j]; - - m256_add_dpbusd_epi32(sum0, in, row0[j]); - m256_add_dpbusd_epi32(sum1, in, row1[j]); - m256_add_dpbusd_epi32(sum2, in, row2[j]); - m256_add_dpbusd_epi32(sum3, in, row3[j]); - } - - *outptr = m256_haddx4(sum0, sum1, sum2, sum3, bias); - } + for (int i = 0; i < canSaturate16.count; ++i) + output[canSaturate16.ids[i].out] += input[canSaturate16.ids[i].in] * canSaturate16.ids[i].w; } else if constexpr (kOutputDimensions == 1) { - __m256i sum0 = _mm256_setzero_si256(); + constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth; - const auto row0 = reinterpret_cast(&weights_[0]); + vec_t sum0 = vec_setzero(); - for (IndexType j = 0; j < kNumChunks; ++j) - { - const __m256i in = input_vector[j]; + const auto row0 = reinterpret_cast(&weights_[0]); - m256_add_dpbusd_epi32(sum0, in, row0[j]); - } - - output[0] = m256_hadd(sum0, biases_[0]); - } - else - { - // This case can never happen because kOutputDimensions - // is always 1 or a multiple of kSimdWidth. - assert(false); - } - -#elif defined (USE_SSSE3) - - constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth; - - auto output = reinterpret_cast(buffer); - const auto input_vector = reinterpret_cast(input); - - // kOutputDimensions is either 1 or a multiple of kSimdWidth - // because then it is also an input dimension. - if constexpr (kOutputDimensions % 4 == 0) - { - for (IndexType i = 0; i < kOutputDimensions; i += 4) - { - const IndexType offset0 = (i + 0) * kPaddedInputDimensions; - const IndexType offset1 = (i + 1) * kPaddedInputDimensions; - const IndexType offset2 = (i + 2) * kPaddedInputDimensions; - const IndexType offset3 = (i + 3) * kPaddedInputDimensions; - - const __m128i bias = *reinterpret_cast(&biases_[i]); - __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]); - - __m128i sum0 = _mm_setzero_si128(); - __m128i sum1 = _mm_setzero_si128(); - __m128i sum2 = _mm_setzero_si128(); - __m128i sum3 = _mm_setzero_si128(); - - const auto row0 = reinterpret_cast(&weights_[offset0]); - const auto row1 = reinterpret_cast(&weights_[offset1]); - const auto row2 = reinterpret_cast(&weights_[offset2]); - const auto row3 = reinterpret_cast(&weights_[offset3]); - - int j = 0; - if (!canSaturate16x4[i / 4]) + for (int j = 0; j < (int)kNumChunks; ++j) { - for (; j < (int)kNumChunks - 1; j += 2) - { - const __m128i in0 = input_vector[j]; - const __m128i in1 = input_vector[j + 1]; + const vec_t in = input_vector[j]; - m128_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]); - m128_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]); - m128_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]); - m128_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]); - } - } - for (; j < (int)kNumChunks; ++j) - { - const __m128i in = input_vector[j]; - - m128_add_dpbusd_epi32(sum0, in, row0[j]); - m128_add_dpbusd_epi32(sum1, in, row1[j]); - m128_add_dpbusd_epi32(sum2, in, row2[j]); - m128_add_dpbusd_epi32(sum3, in, row3[j]); + vec_add_dpbusd_32(sum0, in, row0[j]); } - *outptr = m128_haddx4(sum0, sum1, sum2, sum3, bias); - } - } - else if constexpr (kOutputDimensions == 1) - { - __m128i sum0 = _mm_setzero_si128(); - - const auto row0 = reinterpret_cast(&weights_[0]); - - for (int j = 0; j < (int)kNumChunks; ++j) - { - const __m128i in = input_vector[j]; - - m128_add_dpbusd_epi32(sum0, in, row0[j]); - } - - output[0] = m128_hadd(sum0, biases_[0]); - } - else - { - // This case can never happen because kOutputDimensions - // is always 1 or a multiple of kSimdWidth. - assert(false); + output[0] = vec_hadd(sum0, biases_[0]); } #else @@ -693,11 +325,7 @@ namespace Eval::NNUE::Layers { #if defined(USE_SSE2) constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth; -#ifndef USE_SSSE3 const __m128i kZeros = _mm_setzero_si128(); -#else - const __m128i kOnes = _mm_set1_epi16(1); -#endif const auto input_vector = reinterpret_cast(input); #elif defined(USE_MMX) @@ -792,10 +420,23 @@ namespace Eval::NNUE::Layers { alignas(kCacheLineSize) BiasType biases_[kOutputDimensions]; alignas(kCacheLineSize) WeightType weights_[kOutputDimensions * kPaddedInputDimensions]; - union { - uint32_t canSaturate16x4[(kOutputDimensions + 3) / 4]; - bool canSaturate16[kOutputDimensions]; - }; +#if defined (USE_SSSE3) + struct CanSaturate { + int count; + struct Entry { + uint16_t out; + uint16_t in; + int8_t w; + } ids[kPaddedInputDimensions * kOutputDimensions * 3 / 4]; + + void add(int i, int j, int8_t w) { + ids[count].out = i; + ids[count].in = j; + ids[count].w = w; + ++count; + } + } canSaturate16; +#endif }; } // namespace Eval::NNUE::Layers From 2c1be0be8ec51005befcd4fc422e88b6e32cef45 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 1 Jan 2021 12:59:35 +0300 Subject: [PATCH 27/88] Reorder conditions in LMR and pruning Make code logic somewhat easier to follow. closes https://github.com/official-stockfish/Stockfish/pull/3285 No functional change. --- src/search.cpp | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index e2c3f584..9ea77b3a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1039,8 +1039,20 @@ moves_loop: // When in check, search starts from here // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); - if ( !captureOrPromotion - && !givesCheck) + if ( captureOrPromotion + || givesCheck) + { + // Capture history based pruning when the move doesn't give check + if ( !givesCheck + && lmrDepth < 1 + && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) + continue; + + // SEE based pruning + if (!pos.see_ge(move, Value(-218) * depth)) // (~25 Elo) + continue; + } + else { // Countermoves based pruning (~20 Elo) if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) @@ -1062,18 +1074,6 @@ moves_loop: // When in check, search starts from here if (!pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else - { - // Capture history based pruning when the move doesn't give check - if ( !givesCheck - && lmrDepth < 1 - && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) - continue; - - // SEE based pruning - if (!pos.see_ge(move, Value(-218) * depth)) // (~25 Elo) - continue; - } } // Step 13. Extensions (~75 Elo) @@ -1192,7 +1192,14 @@ moves_loop: // When in check, search starts from here if (singularQuietLMR) r--; - if (!captureOrPromotion) + if (captureOrPromotion) + { + // Unless giving check, this capture is likely bad + if ( !givesCheck + && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 210 * depth <= alpha) + r++; + } + else { // Increase reduction if ttMove is a capture (~5 Elo) if (ttCapture) @@ -1228,13 +1235,6 @@ moves_loop: // When in check, search starts from here // Decrease/increase reduction for moves with a good/bad history (~30 Elo) r -= ss->statScore / 14884; } - else - { - // Unless giving check, this capture is likely bad - if ( !givesCheck - && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 210 * depth <= alpha) - r++; - } Depth d = std::clamp(newDepth - r, 1, newDepth); From c4d67d77c99b99c9ac387ab622773a320f8d5cc3 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 8 Jan 2021 17:04:23 +0100 Subject: [PATCH 28/88] Update copyright years No functional change --- src/benchmark.cpp | 2 +- src/bitbase.cpp | 2 +- src/bitboard.cpp | 2 +- src/bitboard.h | 2 +- src/endgame.cpp | 2 +- src/endgame.h | 2 +- src/evaluate.cpp | 2 +- src/evaluate.h | 2 +- src/main.cpp | 2 +- src/material.cpp | 2 +- src/material.h | 2 +- src/misc.cpp | 2 +- src/misc.h | 2 +- src/movegen.cpp | 2 +- src/movegen.h | 2 +- src/movepick.cpp | 2 +- src/movepick.h | 2 +- src/nnue/architectures/halfkp_256x2-32-32.h | 2 +- src/nnue/evaluate_nnue.cpp | 2 +- src/nnue/evaluate_nnue.h | 2 +- src/nnue/features/feature_set.h | 2 +- src/nnue/features/features_common.h | 2 +- src/nnue/features/half_kp.cpp | 2 +- src/nnue/features/half_kp.h | 2 +- src/nnue/features/index_list.h | 2 +- src/nnue/layers/affine_transform.h | 2 +- src/nnue/layers/clipped_relu.h | 2 +- src/nnue/layers/input_slice.h | 2 +- src/nnue/nnue_accumulator.h | 2 +- src/nnue/nnue_architecture.h | 2 +- src/nnue/nnue_common.h | 2 +- src/nnue/nnue_feature_transformer.h | 2 +- src/pawns.cpp | 2 +- src/pawns.h | 2 +- src/position.cpp | 2 +- src/position.h | 2 +- src/psqt.cpp | 2 +- src/search.cpp | 2 +- src/search.h | 2 +- src/syzygy/tbprobe.cpp | 2 +- src/syzygy/tbprobe.h | 2 +- src/thread.cpp | 2 +- src/thread.h | 2 +- src/thread_win32_osx.h | 2 +- src/timeman.cpp | 2 +- src/timeman.h | 2 +- src/tt.cpp | 2 +- src/tt.h | 2 +- src/tune.cpp | 2 +- src/tune.h | 2 +- src/types.h | 2 +- src/uci.cpp | 2 +- src/uci.h | 2 +- src/ucioption.cpp | 2 +- 54 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index ffb631a2..7cb04382 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/bitbase.cpp b/src/bitbase.cpp index bbe8e9a7..b640eabb 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 80206b58..841aa0b6 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/bitboard.h b/src/bitboard.h index 29d8f66d..95591fc4 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/endgame.cpp b/src/endgame.cpp index 7e005a28..1489a36b 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/endgame.h b/src/endgame.h index 1351d88a..860cc863 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7671f605..c137fab5 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/evaluate.h b/src/evaluate.h index 7dbc35de..8beca2d0 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/main.cpp b/src/main.cpp index e6dff918..ef46d0b5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/material.cpp b/src/material.cpp index f77972e3..36b6132c 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/material.h b/src/material.h index 28da59db..be26425f 100644 --- a/src/material.h +++ b/src/material.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/misc.cpp b/src/misc.cpp index f2bce6b0..48e20a39 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/misc.h b/src/misc.h index 682ef816..7b551ade 100644 --- a/src/misc.h +++ b/src/misc.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movegen.cpp b/src/movegen.cpp index cc1518a0..e017d8fe 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movegen.h b/src/movegen.h index fb616d00..85887a64 100644 --- a/src/movegen.h +++ b/src/movegen.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movepick.cpp b/src/movepick.cpp index f5e02385..8bface8a 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movepick.h b/src/movepick.h index f8472c6e..98629783 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/architectures/halfkp_256x2-32-32.h b/src/nnue/architectures/halfkp_256x2-32-32.h index 9216bd41..a0fe2e0a 100644 --- a/src/nnue/architectures/halfkp_256x2-32-32.h +++ b/src/nnue/architectures/halfkp_256x2-32-32.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index 382d8ff9..fb4a5021 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/evaluate_nnue.h b/src/nnue/evaluate_nnue.h index 6cacf37e..c30d7c01 100644 --- a/src/nnue/evaluate_nnue.h +++ b/src/nnue/evaluate_nnue.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/features/feature_set.h b/src/nnue/features/feature_set.h index 975824b6..77d2220f 100644 --- a/src/nnue/features/feature_set.h +++ b/src/nnue/features/feature_set.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/features/features_common.h b/src/nnue/features/features_common.h index d00a35df..b0073b8b 100644 --- a/src/nnue/features/features_common.h +++ b/src/nnue/features/features_common.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/features/half_kp.cpp b/src/nnue/features/half_kp.cpp index 29322f04..b52a45f2 100644 --- a/src/nnue/features/half_kp.cpp +++ b/src/nnue/features/half_kp.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/features/half_kp.h b/src/nnue/features/half_kp.h index 708fd7ea..d203dc22 100644 --- a/src/nnue/features/half_kp.h +++ b/src/nnue/features/half_kp.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/features/index_list.h b/src/nnue/features/index_list.h index d9ad680a..ca3ebee5 100644 --- a/src/nnue/features/index_list.h +++ b/src/nnue/features/index_list.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index ab2beab7..34777ef6 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/layers/clipped_relu.h b/src/nnue/layers/clipped_relu.h index 7f6d67bf..3ed41ee5 100644 --- a/src/nnue/layers/clipped_relu.h +++ b/src/nnue/layers/clipped_relu.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/layers/input_slice.h b/src/nnue/layers/input_slice.h index afca14c8..efdf0725 100644 --- a/src/nnue/layers/input_slice.h +++ b/src/nnue/layers/input_slice.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_accumulator.h b/src/nnue/nnue_accumulator.h index a357d835..6b4390f9 100644 --- a/src/nnue/nnue_accumulator.h +++ b/src/nnue/nnue_accumulator.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_architecture.h b/src/nnue/nnue_architecture.h index 91cdc4bd..ad5be006 100644 --- a/src/nnue/nnue_architecture.h +++ b/src/nnue/nnue_architecture.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_common.h b/src/nnue/nnue_common.h index f9ff2bc8..33e58745 100644 --- a/src/nnue/nnue_common.h +++ b/src/nnue/nnue_common.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index 85bc2bc8..2641321e 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/pawns.cpp b/src/pawns.cpp index d3d2ea0f..de47570e 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/pawns.h b/src/pawns.h index 5499826e..888bf990 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/position.cpp b/src/position.cpp index 07ce0a7c..837847b4 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/position.h b/src/position.h index 02156448..8509029d 100644 --- a/src/position.h +++ b/src/position.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/psqt.cpp b/src/psqt.cpp index eb36e75e..bf87237a 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/search.cpp b/src/search.cpp index 9ea77b3a..d2a64176 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/search.h b/src/search.h index 72d43c31..3bf3e9ae 100644 --- a/src/search.h +++ b/src/search.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 4d682f1a..97d848a2 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/syzygy/tbprobe.h b/src/syzygy/tbprobe.h index b998989b..cefd39ce 100644 --- a/src/syzygy/tbprobe.h +++ b/src/syzygy/tbprobe.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thread.cpp b/src/thread.cpp index 2fbf745d..a12c0bcc 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thread.h b/src/thread.h index 6a73423b..585f2088 100644 --- a/src/thread.h +++ b/src/thread.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thread_win32_osx.h b/src/thread_win32_osx.h index 75ef5d9a..a0e4d199 100644 --- a/src/thread_win32_osx.h +++ b/src/thread_win32_osx.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/timeman.cpp b/src/timeman.cpp index da08f12d..fc4fbaac 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/timeman.h b/src/timeman.h index 5ad72b32..55a68de4 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tt.cpp b/src/tt.cpp index dea7c712..d1ba9ebb 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tt.h b/src/tt.h index 6aa066c5..5f9525a6 100644 --- a/src/tt.h +++ b/src/tt.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tune.cpp b/src/tune.cpp index e94f67f8..424bdac8 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tune.h b/src/tune.h index 1489fa32..ef418968 100644 --- a/src/tune.h +++ b/src/tune.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/types.h b/src/types.h index 8506b06e..1832b302 100644 --- a/src/types.h +++ b/src/types.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/uci.cpp b/src/uci.cpp index b63e55ad..b3017e91 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/uci.h b/src/uci.h index eb0b390b..edcfcade 100644 --- a/src/uci.h +++ b/src/uci.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/ucioption.cpp b/src/ucioption.cpp index bb0b8311..03f377b3 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From 4d30438400932d18c095a8b85c3e51789d5f0feb Mon Sep 17 00:00:00 2001 From: bmc4 Date: Sun, 10 Jan 2021 03:30:40 -0300 Subject: [PATCH 29/88] Remove Condition from Generate_Move Loop it seems it's faster to handle blockers_for_king(~Us) outside loops Passed STC: LLR: 2.96 (-2.94,2.94) {-0.25,1.25} Total: 22184 W: 2063 L: 1919 D: 18202 Ptnml(0-2): 63, 1485, 7855, 1623, 66 https://tests.stockfishchess.org/tests/view/5ffbee2f6019e097de3ef18d closes https://github.com/official-stockfish/Stockfish/pull/3299 No functional change --- AUTHORS | 1 + src/movegen.cpp | 31 ++++++++++++++----------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/AUTHORS b/AUTHORS index b31a36e9..d170364e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,6 +33,7 @@ Bill Henry (VoyagerOne) Bojun Guo (noobpwnftw, Nooby) braich Brian Sheppard (SapphireBrand, briansheppard-toast) +Bruno de Melo Costa (BM123499) Bryan Cross (crossbr) candirufish Chess13234 diff --git a/src/movegen.cpp b/src/movegen.cpp index e017d8fe..855a203e 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -175,25 +175,19 @@ namespace { } - template - ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) { + template + ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard piecesToMove, Bitboard target) { static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); - Bitboard bb = pos.pieces(Us, Pt); + Bitboard bb = piecesToMove & pos.pieces(Pt); while (bb) { Square from = pop_lsb(&bb); - if (Checks) - { - if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) - && !(attacks_bb(from) & target & pos.check_squares(Pt))) - continue; - - if (pos.blockers_for_king(~Us) & from) - continue; - } + if (Checks && (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) + && !(attacks_bb(from) & target & pos.check_squares(Pt))) + continue; Bitboard b = attacks_bb(from, pos.pieces()) & target; @@ -211,7 +205,10 @@ namespace { template ExtMove* generate_all(const Position& pos, ExtMove* moveList) { constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations - Bitboard target; + Bitboard target, piecesToMove = pos.pieces(Us); + + if(Type == QUIET_CHECKS) + piecesToMove &= ~pos.blockers_for_king(~Us); switch (Type) { @@ -236,10 +233,10 @@ namespace { } moveList = generate_pawn_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, piecesToMove, target); + moveList = generate_moves(pos, moveList, piecesToMove, target); + moveList = generate_moves< ROOK, Checks>(pos, moveList, piecesToMove, target); + moveList = generate_moves< QUEEN, Checks>(pos, moveList, piecesToMove, target); if (Type != QUIET_CHECKS && Type != EVASIONS) { From 303713b560e356a902c1830bce205716cef54a44 Mon Sep 17 00:00:00 2001 From: MaximMolchanov Date: Mon, 11 Jan 2021 07:49:41 +0200 Subject: [PATCH 30/88] Affine transform robust implementation Size of the weights in the last layer is less than 512 bits. It leads to wrong data access for AVX512. There is no error because in current implementation it is guaranteed that there is an array of zeros after weights so zero multiplied by something is returned and sum is correct. It is a mistake that can lead to unexpected bugs in the future. Used AVX2 instructions for smaller input size. No measurable slowdown on avx512. closes https://github.com/official-stockfish/Stockfish/pull/3298 No functional change. --- src/nnue/layers/affine_transform.h | 40 ++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index 34777ef6..adf152ee 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -301,20 +301,40 @@ namespace Eval::NNUE::Layers { } else if constexpr (kOutputDimensions == 1) { - constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth; - - vec_t sum0 = vec_setzero(); - - const auto row0 = reinterpret_cast(&weights_[0]); - - for (int j = 0; j < (int)kNumChunks; ++j) +#if defined (USE_AVX512) + if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) != 0) { - const vec_t in = input_vector[j]; + constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth; + const auto input_vector256 = reinterpret_cast(input); - vec_add_dpbusd_32(sum0, in, row0[j]); + __m256i sum0 = _mm256_setzero_si256(); + const auto row0 = reinterpret_cast(&weights_[0]); + + for (int j = 0; j < (int)kNumChunks; ++j) + { + const __m256i in = input_vector256[j]; + m256_add_dpbusd_epi32(sum0, in, row0[j]); + } + output[0] = m256_hadd(sum0, biases_[0]); } + else +#endif + { +#if defined (USE_AVX512) + constexpr IndexType kNumChunks = kPaddedInputDimensions / (kSimdWidth * 2); +#else + constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth; +#endif + vec_t sum0 = vec_setzero(); + const auto row0 = reinterpret_cast(&weights_[0]); - output[0] = vec_hadd(sum0, biases_[0]); + for (int j = 0; j < (int)kNumChunks; ++j) + { + const vec_t in = input_vector[j]; + vec_add_dpbusd_32(sum0, in, row0[j]); + } + output[0] = vec_hadd(sum0, biases_[0]); + } } #else From b1bb376c3cc9a2e197759b3e6f0d365c8aae7e72 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sun, 10 Jan 2021 20:24:37 +0300 Subject: [PATCH 31/88] Small code cleanup in LMR In a recent patch we added comparing capture history to a number for LMR of captures. Calling it via thisThread-> is not needed since capture history was already declared by this time - so removing makes code slightly shorter and easier to follow. closes https://github.com/official-stockfish/Stockfish/pull/3297 No functional change. --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index d2a64176..e405a373 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1159,7 +1159,7 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || (!PvNode && !formerPv && thisThread->captureHistory[movedPiece][to_sq(move)][type_of(pos.captured_piece())] < 4506) + || (!PvNode && !formerPv && captureHistory[movedPiece][to_sq(move)][type_of(pos.captured_piece())] < 4506) || thisThread->ttHitAverage < 432 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); From 87586b3d0c8961c2fc9330e2f8ac2f8c3fe79018 Mon Sep 17 00:00:00 2001 From: Dieter Dobbelaere Date: Sat, 9 Jan 2021 16:46:06 +0100 Subject: [PATCH 32/88] Use correct chess terms + fix spelling. - "discovered check" (instead of "discovery check") - "en passant" (instead of "en-passant") - "pseudo-legal" before a noun (instead of "pseudo legal") - "3-fold" (instead of "3fold") closes https://github.com/official-stockfish/Stockfish/pull/3294 No functional change. --- AUTHORS | 1 + src/movegen.cpp | 8 ++++---- src/movepick.cpp | 2 +- src/movepick.h | 4 ++-- src/position.cpp | 16 ++++++++-------- src/position.h | 6 +++--- src/search.cpp | 6 +++--- src/types.h | 4 ++-- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/AUTHORS b/AUTHORS index d170364e..f3ae5f09 100644 --- a/AUTHORS +++ b/AUTHORS @@ -46,6 +46,7 @@ Dariusz Orzechowski (dorzechowski) David Zar Daylen Yang (daylen) Deshawn Mohan-Smith (GoldenRare) +Dieter Dobbelaere (ddobbelaere) DiscanX Dominik Schlösser (domschl) double-beep diff --git a/src/movegen.cpp b/src/movegen.cpp index 855a203e..5ce2de7c 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -85,7 +85,7 @@ namespace { // Add pawn pushes which give discovered check. This is possible only // if the pawn is not on the same file as the enemy king, because we - // don't generate captures. Note that a possible discovery check + // don't generate captures. Note that a possible discovered check // promotion has been already generated amongst the captures. Bitboard dcCandidateQuiets = pos.blockers_for_king(Them) & pawnsNotOn7; if (dcCandidateQuiets) @@ -134,7 +134,7 @@ namespace { moveList = make_promotions(moveList, pop_lsb(&b3), ksq); } - // Standard and en-passant captures + // Standard and en passant captures if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) { Bitboard b1 = shift(pawnsNotOn7) & enemies; @@ -167,7 +167,7 @@ namespace { assert(b1); while (b1) - *moveList++ = make(pop_lsb(&b1), pos.ep_square()); + *moveList++ = make(pop_lsb(&b1), pos.ep_square()); } } @@ -355,7 +355,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { moveList = pos.checkers() ? generate(pos, moveList) : generate(pos, moveList); while (cur != moveList) - if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT) + if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT) && !pos.legal(*cur)) *cur = (--moveList)->move; else diff --git a/src/movepick.cpp b/src/movepick.cpp index 8bface8a..9cb8447f 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -142,7 +142,7 @@ Move MovePicker::select(Pred filter) { } /// MovePicker::next_move() is the most important method of the MovePicker class. It -/// returns a new pseudo legal move every time it is called until there are no more +/// returns a new pseudo-legal move every time it is called until there are no more /// moves left, picking the move with the highest score from a list of generated moves. Move MovePicker::next_move(bool skipQuiets) { diff --git a/src/movepick.h b/src/movepick.h index 98629783..5232ee4d 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -108,9 +108,9 @@ typedef Stats PieceToHistory; typedef Stats ContinuationHistory; -/// MovePicker class is used to pick one pseudo legal move at a time from the +/// MovePicker class is used to pick one pseudo-legal move at a time from the /// current position. The most important method is next_move(), which returns a -/// new pseudo legal move each time it is called, until there are no moves left, +/// new pseudo-legal move each time it is called, until there are no moves left, /// when MOVE_NONE is returned. In order to improve the efficiency of the alpha /// beta algorithm, MovePicker attempts to return the moves which are most likely /// to get a cut-off first. diff --git a/src/position.cpp b/src/position.cpp index 837847b4..12b1bd9a 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -505,7 +505,7 @@ bool Position::legal(Move m) const { // En passant captures are a tricky special case. Because they are rather // uncommon, we do it simply by testing whether the king is attacked after // the move is made. - if (type_of(m) == ENPASSANT) + if (type_of(m) == EN_PASSANT) { Square ksq = square(us); Square capsq = to - pawn_push(us); @@ -655,7 +655,7 @@ bool Position::gives_check(Move m) const { // of direct checks and ordinary discovered check, so the only case we // need to handle is the unusual case of a discovered check through // the captured pawn. - case ENPASSANT: + case EN_PASSANT: { Square capsq = make_square(file_of(to), rank_of(from)); Bitboard b = (pieces() ^ from ^ capsq) | to; @@ -716,7 +716,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { Square from = from_sq(m); Square to = to_sq(m); Piece pc = piece_on(from); - Piece captured = type_of(m) == ENPASSANT ? make_piece(them, PAWN) : piece_on(to); + Piece captured = type_of(m) == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to); assert(color_of(pc) == us); assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us)); @@ -742,7 +742,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { // update non-pawn material. if (type_of(captured) == PAWN) { - if (type_of(m) == ENPASSANT) + if (type_of(m) == EN_PASSANT) { capsq -= pawn_push(us); @@ -769,7 +769,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { // Update board and piece lists remove_piece(capsq); - if (type_of(m) == ENPASSANT) + if (type_of(m) == EN_PASSANT) board[capsq] = NO_PIECE; // Update material hash key and prefetch access to materialTable @@ -815,7 +815,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { // If the moving piece is a pawn do some special extra work if (type_of(pc) == PAWN) { - // Set en-passant square if the moved pawn can be captured + // Set en passant square if the moved pawn can be captured if ( (int(to) ^ int(from)) == 16 && (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN))) { @@ -938,7 +938,7 @@ void Position::undo_move(Move m) { { Square capsq = to; - if (type_of(m) == ENPASSANT) + if (type_of(m) == EN_PASSANT) { capsq -= pawn_push(us); @@ -1042,7 +1042,7 @@ void Position::undo_null_move() { /// Position::key_after() computes the new hash key after the given move. Needed /// for speculative prefetch. It doesn't recognize special moves like castling, -/// en-passant and promotions. +/// en passant and promotions. Key Position::key_after(Move m) const { diff --git a/src/position.h b/src/position.h index 8509029d..93e0f91d 100644 --- a/src/position.h +++ b/src/position.h @@ -113,7 +113,7 @@ public: Bitboard blockers_for_king(Color c) const; Bitboard check_squares(PieceType pt) const; Bitboard pinners(Color c) const; - bool is_discovery_check_on_king(Color c, Move m) const; + bool is_discovered_check_on_king(Color c, Move m) const; // Attacks to/from a given square Bitboard attackers_to(Square s) const; @@ -304,7 +304,7 @@ inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSquares[pt]; } -inline bool Position::is_discovery_check_on_king(Color c, Move m) const { +inline bool Position::is_discovered_check_on_king(Color c, Move m) const { return st->blockersForKing[c] & from_sq(m); } @@ -371,7 +371,7 @@ inline bool Position::capture_or_promotion(Move m) const { inline bool Position::capture(Move m) const { assert(is_ok(m)); // Castling is encoded as "king captures rook" - return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT; + return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == EN_PASSANT; } inline Piece Position::captured_piece() const { diff --git a/src/search.cpp b/src/search.cpp index e405a373..3da3d04e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -84,7 +84,7 @@ namespace { return d > 14 ? 29 : 8 * d * d + 224 * d - 215; } - // Add a small random component to draw evaluations to avoid 3fold-blindness + // Add a small random component to draw evaluations to avoid 3-fold blindness Value value_draw(Thread* thisThread) { return VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); } @@ -1127,7 +1127,7 @@ moves_loop: // When in check, search starts from here // Check extension (~2 Elo) else if ( givesCheck - && (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move))) + && (pos.is_discovered_check_on_king(~us, move) || pos.see_ge(move))) extension = 1; // Last captures extension @@ -1541,7 +1541,7 @@ moves_loop: // When in check, search starts from here && futilityBase > -VALUE_KNOWN_WIN && !pos.advanced_pawn_push(move)) { - assert(type_of(move) != ENPASSANT); // Due to !pos.advanced_pawn_push + assert(type_of(move) != EN_PASSANT); // Due to !pos.advanced_pawn_push // moveCount pruning if (moveCount > 2) diff --git a/src/types.h b/src/types.h index 1832b302..d270384e 100644 --- a/src/types.h +++ b/src/types.h @@ -113,7 +113,7 @@ constexpr int MAX_PLY = 246; /// bit 6-11: origin square (from 0 to 63) /// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2) /// bit 14-15: special move flag: promotion (1), en passant (2), castling (3) -/// NOTE: EN-PASSANT bit is set only when a pawn can be captured +/// NOTE: en passant bit is set only when a pawn can be captured /// /// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in /// any normal move destination square is always different from origin square @@ -127,7 +127,7 @@ enum Move : int { enum MoveType { NORMAL, PROMOTION = 1 << 14, - ENPASSANT = 2 << 14, + EN_PASSANT = 2 << 14, CASTLING = 3 << 14 }; From 0266e702970640df693a8e572dd3cb9d227cdfc6 Mon Sep 17 00:00:00 2001 From: Dieter Dobbelaere Date: Sun, 10 Jan 2021 12:22:52 +0100 Subject: [PATCH 33/88] Fix static_assert. With a hard-coded true, this declaration has no effect. closes https://github.com/official-stockfish/Stockfish/pull/3295 No functional change. --- src/movegen.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 5ce2de7c..aaa1ff88 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -204,6 +204,9 @@ namespace { template ExtMove* generate_all(const Position& pos, ExtMove* moveList) { + + static_assert(Type != LEGAL, "Unsupported type in generate_all()"); + constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations Bitboard target, piecesToMove = pos.pieces(Us); @@ -228,8 +231,6 @@ namespace { case NON_EVASIONS: target = ~pos.pieces(Us); break; - default: - static_assert(true, "Unsupported type in generate_all()"); } moveList = generate_pawn_moves(pos, moveList, target); From 5f222f1d98c9b4cb07aa2303f085c2064e7ea77a Mon Sep 17 00:00:00 2001 From: BM123499 <48841672+BM123499@users.noreply.github.com> Date: Fri, 8 Jan 2021 14:03:26 -0300 Subject: [PATCH 34/88] Rethink En Passant Evasion Capture It now checks if it were a discovery attack instead of the attacking piece is the double-moved pawn. As a side effect, certain illegal fens have different, and slightly more logical move generation. There is no intend to maintain particular behavior for such non-reachable fens. Passed STC: LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 47912 W: 4327 L: 4285 D: 39300 Ptnml(0-2): 144, 3312, 17012, 3334, 154 https://tests.stockfishchess.org/tests/view/5ff890946019e097de3ef0a5 closes https://github.com/official-stockfish/Stockfish/pull/3292 closes / fixes https://github.com/official-stockfish/Stockfish/issues/3270 No functional change --- src/movegen.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index aaa1ff88..fafa65ee 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -156,10 +156,8 @@ namespace { { assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6)); - // An en passant capture can be an evasion only if the checking piece - // is the double pushed pawn and so is in the target. Otherwise this - // is a discovery check and we are forced to do otherwise. - if (Type == EVASIONS && !(target & (pos.ep_square() - Up))) + // An en passant capture cannot resolve a discovered check. + if (Type == EVASIONS && (target & (pos.ep_square() + Up))) return moveList; b1 = pawnsNotOn7 & pawn_attacks_bb(Them, pos.ep_square()); From 37c2b5685efa8a0c3de04604c73e19f6e82dd6e8 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 9 Jan 2021 17:42:58 +0300 Subject: [PATCH 35/88] Refine stat based reductions This patch separates stat based reductions for quiet moves in case of being in check and in case of not being in check. We will be using sum of first continuation history and main history (similar to movepicker) instead of statScore for the first case. passed STC https://tests.stockfishchess.org/tests/view/5ff87b2f6019e097de3ef09b LLR: 2.93 (-2.94,2.94) {-0.25,1.25} Total: 63992 W: 5887 L: 5678 D: 52427 Ptnml(0-2): 201, 4561, 22305, 4686, 243 passed LTC https://tests.stockfishchess.org/tests/view/5ff8b6206019e097de3ef0b2 LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 81216 W: 3127 L: 2880 D: 75209 Ptnml(0-2): 46, 2544, 35176, 2801, 41 closes https://github.com/official-stockfish/Stockfish/pull/3293 bench 4395984 --- src/search.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 3da3d04e..7abffb87 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1233,7 +1233,13 @@ moves_loop: // When in check, search starts from here r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 14884; + // If we are not in check use statScore, if we are in check + // use sum of main history and first continuation history with an offset + if (ss->inCheck) + r -= (thisThread->mainHistory[us][from_to(move)] + + (*contHist[0])[movedPiece][to_sq(move)] - 4333) / 16384; + else + r -= ss->statScore / 14884; } Depth d = std::clamp(newDepth - r, 1, newDepth); From ee3f7b6b6e1a1051b32cedb38ac89b3458ff4ab2 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 10 Jan 2021 01:31:09 +0200 Subject: [PATCH 36/88] Bad Outpost Pawn Scale Changed name from Bad Outpost to Uncontested Outpost Scale Uncontested Outpost with number of pawns + Decrease Bishop PSQT values and general tuning Credits for the decrease of the Bishop PSQT values: Fauzi Credits for scaling Uncontested Outpost with number of pawns: Lolligerhans Credits for the tunings: Fauzi Passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 32040 W: 6593 L: 6281 D: 19166 Ptnml(0-2): 596, 3713, 7095, 4015, 601 https://tests.stockfishchess.org/tests/view/5ffa43026019e097de3ef0f2 Passed LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.25} Total: 84376 W: 11395 L: 10950 D: 62031 Ptnml(0-2): 652, 7930, 24623, 8287, 696 https://tests.stockfishchess.org/tests/view/5ffa6e7b6019e097de3ef0fd closes https://github.com/official-stockfish/Stockfish/pull/3296 Bench: 4287509 --- src/evaluate.cpp | 10 +++++----- src/psqt.cpp | 16 ++++++++-------- src/search.cpp | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c137fab5..76266937 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -225,7 +225,7 @@ namespace { // BishopPawns[distance from edge] contains a file-dependent penalty for pawns on // squares of the same color as our bishop. constexpr Score BishopPawns[int(FILE_NB) / 2] = { - S(3, 8), S(3, 9), S(1, 8), S(3, 7) + S(3, 8), S(3, 9), S(2, 8), S(3, 8) }; // KingProtector[knight/bishop] contains penalty for each distance unit to own king @@ -233,7 +233,7 @@ namespace { // Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a // pawn protected square on rank 4 to 6 which is also safe from a pawn attack. - constexpr Score Outpost[] = { S(56, 34), S(31, 23) }; + constexpr Score Outpost[] = { S(57, 38), S(31, 24) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { @@ -255,7 +255,7 @@ namespace { }; // Assorted bonuses and penalties - constexpr Score BadOutpost = S( -7, 36); + constexpr Score UncontestedOutpost = S( 1, 10); constexpr Score BishopOnKingRing = S( 24, 0); constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); @@ -428,7 +428,7 @@ namespace { if (Pt == BISHOP || Pt == KNIGHT) { // Bonus if the piece is on an outpost square or can reach one - // Reduced bonus for knights (BadOutpost) if few relevant targets + // Bonus for knights (UncontestedOutpost) if few relevant targets bb = OutpostRanks & (attackedBy[Us][PAWN] | shift(pos.pieces(PAWN))) & ~pe->pawn_attacks_span(Them); Bitboard targets = pos.pieces(Them) & ~pos.pieces(PAWN); @@ -437,7 +437,7 @@ namespace { && bb & s & ~CenterFiles // on a side outpost && !(b & targets) // no relevant attacks && (!more_than_one(targets & (s & QueenSide ? QueenSide : KingSide)))) - score += BadOutpost; + score += UncontestedOutpost * popcount(pos.pieces(PAWN) & (s & QueenSide ? QueenSide : KingSide)); else if (bb & s) score += Outpost[Pt == BISHOP]; else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) diff --git a/src/psqt.cpp b/src/psqt.cpp index bf87237a..e2107240 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -43,14 +43,14 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { S(-201,-100), S(-83,-88), S(-56,-56), S(-26,-17) } }, { // Bishop - { S(-53,-57), S( -5,-30), S( -8,-37), S(-23,-12) }, - { S(-15,-37), S( 8,-13), S( 19,-17), S( 4, 1) }, - { S( -7,-16), S( 21, -1), S( -5, -2), S( 17, 10) }, - { S( -5,-20), S( 11, -6), S( 25, 0), S( 39, 17) }, - { S(-12,-17), S( 29, -1), S( 22,-14), S( 31, 15) }, - { S(-16,-30), S( 6, 6), S( 1, 4), S( 11, 6) }, - { S(-17,-31), S(-14,-20), S( 5, -1), S( 0, 1) }, - { S(-48,-46), S( 1,-42), S(-14,-37), S(-23,-24) } + { S(-37,-40), S(-4 ,-21), S( -6,-26), S(-16, -8) }, + { S(-11,-26), S( 6, -9), S( 13,-12), S( 3, 1) }, + { S(-5 ,-11), S( 15, -1), S( -4, -1), S( 12, 7) }, + { S(-4 ,-14), S( 8, -4), S( 18, 0), S( 27, 12) }, + { S(-8 ,-12), S( 20, -1), S( 15,-10), S( 22, 11) }, + { S(-11,-21), S( 4, 4), S( 1, 3), S( 8, 4) }, + { S(-12,-22), S(-10,-14), S( 4, -1), S( 0, 1) }, + { S(-34,-32), S( 1,-29), S(-10,-26), S(-16,-17) } }, { // Rook { S(-31, -9), S(-20,-13), S(-14,-10), S(-5, -9) }, diff --git a/src/search.cpp b/src/search.cpp index 7abffb87..6cc115fc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1233,10 +1233,10 @@ moves_loop: // When in check, search starts from here r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - // If we are not in check use statScore, if we are in check + // If we are not in check use statScore, if we are in check // use sum of main history and first continuation history with an offset if (ss->inCheck) - r -= (thisThread->mainHistory[us][from_to(move)] + r -= (thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] - 4333) / 16384; else r -= ss->statScore / 14884; From 6dddcecb09df268d93810a1a38deb116f97672af Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Sun, 10 Jan 2021 03:30:40 -0300 Subject: [PATCH 37/88] Optimize generate_moves This change simplifies control flow in the generate_moves function which ensures the compiler doesn't duplicate work due to possibly not resolving pureness of the function calls. Also the biggest change is the removal of the unnecessary condition checking for empty b in a convoluted way. The rationale for removal of this condition is that computing attacks_bb with occupancy is not much more costly than computing pseudo attacks and overall the condition (also being likely unpredictable) is a pessimisation. This is inspired by previous changes by @BM123499. Passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 88040 W: 8172 L: 7931 D: 71937 Ptnml(0-2): 285, 6128, 30957, 6361, 289 https://tests.stockfishchess.org/tests/view/5ffc28386019e097de3ef1c7 closes https://github.com/official-stockfish/Stockfish/pull/3300 No functional change. --- src/movegen.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index fafa65ee..88c31cfa 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -180,17 +180,17 @@ namespace { Bitboard bb = piecesToMove & pos.pieces(Pt); + if (!bb) + return moveList; + + [[maybe_unused]] const Bitboard checkSquares = pos.check_squares(Pt); + while (bb) { Square from = pop_lsb(&bb); - if (Checks && (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) - && !(attacks_bb(from) & target & pos.check_squares(Pt))) - continue; - Bitboard b = attacks_bb(from, pos.pieces()) & target; - - if (Checks) - b &= pos.check_squares(Pt); + if constexpr (Checks) + b &= checkSquares; while (b) *moveList++ = make_move(from, pop_lsb(&b)); From 77eeea407c9d10cf6dbca6f4e07efbbe836c4fb0 Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Tue, 12 Jan 2021 14:30:25 +0100 Subject: [PATCH 38/88] Add penalty for doubled pawns in agile structure Give an additional penalty of S(20, 10) for any doubled pawn if none of the opponent's pawns is facing any of our - pawns or - pawn attacks; that means, each of their pawns can push at least one square without being captured. This ignores their non-pawns pieces and attacks. One possible justification: Their pawns' ability to push freely provides options to react to our threats by changing their pawn structure. Our doubled pawns however will likely lead to an exploitable weakness, even if the pawn structure is not yet fixed. Note that the notion of "their pawns not being fixed" is symmetric for both players: If all of their pawns can push freely so can ours. All pawns being freely pushable might just be an early-game-indicator. However, it can trigger during endgame pawns races, where doubled pawns are especially hindering, too. LTC LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 134976 W: 17964 L: 17415 D: 99597 Ptnml(0-2): 998, 12702, 39619, 13091, 1078 https://tests.stockfishchess.org/tests/view/5ffdd5316019e097de3ef281 STC LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 35640 W: 7219 L: 6904 D: 21517 Ptnml(0-2): 645, 4096, 8084, 4289, 706 https://tests.stockfishchess.org/tests/view/5ffda4a16019e097de3ef265 closes https://github.com/official-stockfish/Stockfish/pull/3302 Bench: 4363873 --- src/pawns.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pawns.cpp b/src/pawns.cpp index de47570e..5d6770ed 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -32,6 +32,7 @@ namespace { // Pawn penalties constexpr Score Backward = S( 6, 23); constexpr Score Doubled = S(13, 53); + constexpr Score DoubledEarly = S(20, 10); constexpr Score Isolated = S( 2, 15); constexpr Score WeakLever = S( 5, 57); constexpr Score WeakUnopposed = S(16, 22); @@ -86,6 +87,7 @@ namespace { constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); + constexpr Direction Down = -Up; Bitboard neighbours, stoppers, support, phalanx, opposed; Bitboard lever, leverPush, blocked; @@ -123,6 +125,13 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); + if (doubled) + { + // Additional doubled penalty if none of their pawns is fixed + if (!(ourPawns & shift(theirPawns | pawn_attacks_bb(theirPawns)))) + score -= DoubledEarly; + } + // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. backward = !(neighbours & forward_ranks_bb(Them, s + Up)) From 329ef2a6aa362f4d831bdde4b31da40f3547985d Mon Sep 17 00:00:00 2001 From: Krystian Kuzniarek Date: Thu, 31 Dec 2020 17:00:39 +0100 Subject: [PATCH 39/88] Change lock type No additional features of std::unique_lock has been previously used so it's better to use a lighter lock. closes https://github.com/official-stockfish/Stockfish/pull/3284 No functional change. --- AUTHORS | 1 + src/syzygy/tbprobe.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index f3ae5f09..d2b26469 100644 --- a/AUTHORS +++ b/AUTHORS @@ -100,6 +100,7 @@ Ken Takusagawa kinderchocolate Kiran Panditrao (Krgp) Kojirion +Krystian Kuzniarek (kuzkry) Leonardo Ljubičić (ICCF World Champion) Leonid Pechenik (lp--) Linus Arver (listx) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 97d848a2..36234786 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -1141,7 +1141,7 @@ void* mapped(TBTable& e, const Position& pos) { if (e.ready.load(std::memory_order_acquire)) return e.baseAddress; // Could be nullptr if file does not exist - std::unique_lock lk(mutex); + std::scoped_lock lk(mutex); if (e.ready.load(std::memory_order_relaxed)) // Recheck under lock return e.baseAddress; From b7f643fe391d00fd9088587e8ef0ca520fa1480f Mon Sep 17 00:00:00 2001 From: Rod Johnson Date: Mon, 4 Jan 2021 22:59:55 +1100 Subject: [PATCH 40/88] Add .gitignore add files produced during the build to a newly added .gitignore closes https://github.com/official-stockfish/Stockfish/pull/3286 No functional change --- .gitignore | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8981efca --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Files from build +**/*.o +**/*.s +src/.depend + +# Built binary +src/stockfish* +src/-lstdc++.res + +# Neural network for the NNUE evaluation +**/*.nnue + From 1188141aa78d01c361582daaa73de5154b6d09b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Thu, 21 Jan 2021 18:53:29 +0100 Subject: [PATCH 41/88] Improve play for closed positions This patch give a small bonus to incite the attacking side to keep more pawns on the board. A consequence of this bonus is that Stockfish will tend to play positions slightly more closed on average than master, especially when it believes that it has an advantage. To lower the risk of blockades where Stockfish start shuffling without progress, we also implement a progressive decrease of the evaluation value with the 50 moves counter (along with the necessary aging of the transposition table to reduce the impact of the Graph History Interaction problem): since the evaluation decreases during shuffling phases, the engine will tend to examine the consequences of pawn breaks faster during the search. Passed STC: LLR: 2.96 (-2.94,2.94) {-0.25,1.25} Total: 26184 W: 2406 L: 2252 D: 21526 Ptnml(0-2): 85, 1784, 9223, 1892, 108 https://tests.stockfishchess.org/tests/view/600cc08b735dd7f0f0352c06 Passed LCT: LLR: 2.95 (-2.94,2.94) {0.25,1.25} Total: 199768 W: 7695 L: 7191 D: 184882 Ptnml(0-2): 85, 6478, 86269, 6952, 100 https://tests.stockfishchess.org/tests/view/600ccd28735dd7f0f0352c10 Closes https://github.com/official-stockfish/Stockfish/pull/3321 Bench: 3988915 --- src/evaluate.cpp | 4 ++-- src/position.cpp | 2 +- src/position.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 76266937..6bd3c08b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1052,8 +1052,8 @@ Value Eval::evaluate(const Position& pos) { { // Scale and shift NNUE for compatibility with search and classical evaluation auto adjusted_NNUE = [&](){ - int mat = pos.non_pawn_material() + PawnValueMg * pos.count(); - return NNUE::evaluate(pos) * (679 + mat / 32) / 1024 + Tempo; + int mat = pos.non_pawn_material() + 2 * PawnValueMg * pos.count(); + return NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo; }; // If there is PSQ imbalance use classical eval, with small probability if it is small diff --git a/src/position.cpp b/src/position.cpp index 12b1bd9a..8c97160b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1017,7 +1017,7 @@ void Position::do_null_move(StateInfo& newSt) { } st->key ^= Zobrist::side; - prefetch(TT.first_entry(st->key)); + prefetch(TT.first_entry(key())); ++st->rule50; st->pliesFromNull = 0; diff --git a/src/position.h b/src/position.h index 93e0f91d..928366bc 100644 --- a/src/position.h +++ b/src/position.h @@ -322,7 +322,8 @@ inline int Position::pawns_on_same_color_squares(Color c, Square s) const { } inline Key Position::key() const { - return st->key; + return st->rule50 < 14 ? st->key + : st->key ^ make_key((st->rule50 - 14) / 8); } inline Key Position::pawn_key() const { From 70a818cbd6784ccfa8503d94bc31dd1dc16dd1ff Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Tue, 12 Jan 2021 14:59:51 +0100 Subject: [PATCH 42/88] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/3301 No functional change --- src/evaluate.cpp | 29 +++++++++++++++-------------- src/main.cpp | 7 ++----- src/material.cpp | 14 ++++++++------ src/movegen.cpp | 8 ++++---- src/movepick.h | 6 +++--- src/position.cpp | 2 +- src/position.h | 5 +---- src/psqt.cpp | 40 +++++++++++++++++++++++----------------- src/psqt.h | 38 ++++++++++++++++++++++++++++++++++++++ src/syzygy/tbprobe.cpp | 4 ++-- src/tune.h | 6 +++--- 11 files changed, 100 insertions(+), 59 deletions(-) create mode 100644 src/psqt.h diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 6bd3c08b..0b211261 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -37,12 +37,13 @@ #include "incbin/incbin.h" -// Macro to embed the default NNUE file data in the engine binary (using incbin.h, by Dale Weiler). +// Macro to embed the default efficiently updatable neural network (NNUE) file +// data in the engine binary (using incbin.h, by Dale Weiler). // This macro invocation will declare the following three variables // const unsigned char gEmbeddedNNUEData[]; // a pointer to the embedded data // const unsigned char *const gEmbeddedNNUEEnd; // a marker to the end // const unsigned int gEmbeddedNNUESize; // the size of the embedded file -// Note that this does not work in Microsof Visual Studio. +// Note that this does not work in Microsoft Visual Studio. #if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF) INCBIN(EmbeddedNNUE, EvalFileDefaultName); #else @@ -60,9 +61,9 @@ namespace Eval { bool useNNUE; string eval_file_loaded = "None"; - /// NNUE::init() tries to load a nnue network at startup time, or when the engine + /// NNUE::init() tries to load a NNUE network at startup time, or when the engine /// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue" - /// The name of the nnue network is always retrieved from the EvalFile option. + /// The name of the NNUE network is always retrieved from the EvalFile option. /// We search the given network in three locations: internally (the default /// network may be embedded in the binary), in the active working directory and /// in the engine directory. Distro packagers may define the DEFAULT_NNUE_DIRECTORY @@ -450,7 +451,7 @@ namespace { // Penalty if the piece is far from the king score -= KingProtector[Pt == BISHOP] * distance(pos.square(Us), s); - if (Pt == BISHOP) + if constexpr (Pt == BISHOP) { // Penalty according to the number of our pawns on the same color square as the // bishop, bigger when the center files are blocked with pawns and smaller @@ -482,7 +483,7 @@ namespace { } } - if (Pt == ROOK) + if constexpr (Pt == ROOK) { // Bonuses for rook on a (semi-)open or closed file if (pos.is_on_semiopen_file(Us, s)) @@ -509,7 +510,7 @@ namespace { } } - if (Pt == QUEEN) + if constexpr (Pt == QUEEN) { // Penalty if any relative pin or discovered attack against the queen Bitboard queenPinners; @@ -517,7 +518,7 @@ namespace { score -= WeakQueen; } } - if (T) + if constexpr (T) Trace::add(Pt, Us, score); return score; @@ -617,7 +618,7 @@ namespace { // Penalty if king flank is under attack, potentially moving toward the king score -= FlankAttacks * kingFlankAttack; - if (T) + if constexpr (T) Trace::add(KING, Us, score); return score; @@ -718,7 +719,7 @@ namespace { score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]) * (1 + queenImbalance); } - if (T) + if constexpr (T) Trace::add(THREAT, Us, score); return score; @@ -811,7 +812,7 @@ namespace { score += bonus - PassedFile * edge_distance(file_of(s)); } - if (T) + if constexpr (T) Trace::add(PASSED, Us, score); return score; @@ -852,7 +853,7 @@ namespace { int weight = pos.count(Us) - 3 + std::min(pe->blocked_count(), 9); Score score = make_score(bonus * weight * weight / 16, 0); - if (T) + if constexpr (T) Trace::add(SPACE, Us, score); return score; @@ -947,7 +948,7 @@ namespace { + eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL; v /= PHASE_MIDGAME; - if (T) + if constexpr (T) { Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score))); Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL)); @@ -1019,7 +1020,7 @@ make_v: Value v = winnable(score); // In case of tracing add all remaining individual evaluation terms - if (T) + if constexpr (T) { Trace::add(MATERIAL, pos.psq_score()); Trace::add(IMBALANCE, me->imbalance()); diff --git a/src/main.cpp b/src/main.cpp index ef46d0b5..ef662468 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,15 +21,12 @@ #include "bitboard.h" #include "endgame.h" #include "position.h" +#include "psqt.h" #include "search.h" +#include "syzygy/tbprobe.h" #include "thread.h" #include "tt.h" #include "uci.h" -#include "syzygy/tbprobe.h" - -namespace PSQT { - void init(); -} int main(int argc, char* argv[]) { diff --git a/src/material.cpp b/src/material.cpp index 36b6132c..e76641d1 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -29,23 +29,25 @@ namespace { // Polynomial material imbalance parameters + // One Score parameter for each pair (our piece, another of our pieces) constexpr Score QuadraticOurs[][PIECE_TYPE_NB] = { - // OUR PIECES - // pair pawn knight bishop rook queen + // OUR PIECE 2 + // bishop pair pawn knight bishop rook queen {S(1419, 1455) }, // Bishop pair {S( 101, 28), S( 37, 39) }, // Pawn - {S( 57, 64), S(249, 187), S(-49, -62) }, // Knight OUR PIECES + {S( 57, 64), S(249, 187), S(-49, -62) }, // Knight OUR PIECE 1 {S( 0, 0), S(118, 137), S( 10, 27), S( 0, 0) }, // Bishop {S( -63, -68), S( -5, 3), S(100, 81), S(132, 118), S(-246, -244) }, // Rook {S(-210, -211), S( 37, 14), S(147, 141), S(161, 105), S(-158, -174), S(-9,-31) } // Queen }; + // One Score parameter for each pair (our piece, their piece) constexpr Score QuadraticTheirs[][PIECE_TYPE_NB] = { - // THEIR PIECES - // pair pawn knight bishop rook queen + // THEIR PIECE + // bishop pair pawn knight bishop rook queen { }, // Bishop pair {S( 33, 30) }, // Pawn - {S( 46, 18), S(106, 84) }, // Knight OUR PIECES + {S( 46, 18), S(106, 84) }, // Knight OUR PIECE {S( 75, 35), S( 59, 44), S( 60, 15) }, // Bishop {S( 26, 35), S( 6, 22), S( 38, 39), S(-12, -2) }, // Rook {S( 97, 93), S(100, 163), S(-58, -91), S(112, 192), S(276, 225) } // Queen diff --git a/src/movegen.cpp b/src/movegen.cpp index 88c31cfa..14df1f05 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -205,7 +205,7 @@ namespace { static_assert(Type != LEGAL, "Unsupported type in generate_all()"); - constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations + constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations Bitboard target, piecesToMove = pos.pieces(Us); if(Type == QUIET_CHECKS) @@ -257,7 +257,7 @@ namespace { /// Generates all pseudo-legal captures plus queen and checking knight promotions -/// Generates all pseudo-legal non-captures and underpromotions(except checking knight) +/// Generates all pseudo-legal non-captures and underpromotions (except checking knight) /// Generates all pseudo-legal captures and non-captures /// /// Returns a pointer to the end of the move list. @@ -280,8 +280,8 @@ template ExtMove* generate(const Position&, ExtMove*); template ExtMove* generate(const Position&, ExtMove*); -/// generate generates all pseudo-legal non-captures. -/// Returns a pointer to the end of the move list. +/// generate generates all pseudo-legal non-captures giving check, +/// except castling. Returns a pointer to the end of the move list. template<> ExtMove* generate(const Position& pos, ExtMove* moveList) { diff --git a/src/movepick.h b/src/movepick.h index 5232ee4d..ea599cda 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -111,9 +111,9 @@ typedef Stats ContinuationHistory /// MovePicker class is used to pick one pseudo-legal move at a time from the /// current position. The most important method is next_move(), which returns a /// new pseudo-legal move each time it is called, until there are no moves left, -/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha -/// beta algorithm, MovePicker attempts to return the moves which are most likely -/// to get a cut-off first. +/// when MOVE_NONE is returned. In order to improve the efficiency of the +/// alpha-beta algorithm, MovePicker attempts to return the moves which are most +/// likely to get a cut-off first. class MovePicker { enum PickType { Next, Best }; diff --git a/src/position.cpp b/src/position.cpp index 8c97160b..6a5d09ee 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1067,7 +1067,7 @@ bool Position::see_ge(Move m, Value threshold) const { assert(is_ok(m)); - // Only deal with normal moves, assume others pass a simple see + // Only deal with normal moves, assume others pass a simple SEE if (type_of(m) != NORMAL) return VALUE_ZERO >= threshold; diff --git a/src/position.h b/src/position.h index 928366bc..3624e29e 100644 --- a/src/position.h +++ b/src/position.h @@ -26,6 +26,7 @@ #include "bitboard.h" #include "evaluate.h" +#include "psqt.h" #include "types.h" #include "nnue/nnue_accumulator.h" @@ -200,10 +201,6 @@ private: bool chess960; }; -namespace PSQT { - extern Score psq[PIECE_NB][SQUARE_NB]; -} - extern std::ostream& operator<<(std::ostream& os, const Position& pos); inline Color Position::side_to_move() const { diff --git a/src/psqt.cpp b/src/psqt.cpp index e2107240..46605d52 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -16,19 +16,22 @@ along with this program. If not, see . */ + +#include "psqt.h" + #include -#include "types.h" #include "bitboard.h" +#include "types.h" -namespace PSQT { -#define S(mg, eg) make_score(mg, eg) +namespace +{ -// Bonus[PieceType][Square / 2] contains Piece-Square scores. For each piece -// type on a given square a (middlegame, endgame) score pair is assigned. Table -// is defined for files A..D and white side: it is symmetric for black side and -// second half of the files. +auto constexpr S = make_score; + +// 'Bonus' contains Piece-Square parameters. +// Scores are explicit for files A to D, implicitly mirrored for E to H. constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { }, { }, @@ -95,11 +98,14 @@ constexpr Score PBonus[RANK_NB][FILE_NB] = { S( -7, 0), S( 7,-11), S( -3, 12), S(-13, 21), S( 5, 25), S(-16, 19), S( 10, 4), S( -8, 7) } }; -#undef S +} // namespace + + +namespace PSQT +{ Score psq[PIECE_NB][SQUARE_NB]; - // PSQT::init() initializes piece-square tables: the white halves of the tables are // copied from Bonus[] and PBonus[], adding the piece value, then the black halves of // the tables are initialized by flipping and changing the sign of the white scores. @@ -107,15 +113,15 @@ void init() { for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING}) { - Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]); + Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]); - for (Square s = SQ_A1; s <= SQ_H8; ++s) - { - File f = File(edge_distance(file_of(s))); - psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] - : Bonus[pc][rank_of(s)][f]); - psq[~pc][flip_rank(s)] = -psq[pc][s]; - } + for (Square s = SQ_A1; s <= SQ_H8; ++s) + { + File f = File(edge_distance(file_of(s))); + psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] + : Bonus[pc][rank_of(s)][f]); + psq[~pc][flip_rank(s)] = -psq[pc][s]; + } } } diff --git a/src/psqt.h b/src/psqt.h new file mode 100644 index 00000000..8b4fd6eb --- /dev/null +++ b/src/psqt.h @@ -0,0 +1,38 @@ +/* + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + + Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifndef PSQT_H_INCLUDED +#define PSQT_H_INCLUDED + + +#include "types.h" + + +namespace PSQT +{ + +extern Score psq[PIECE_NB][SQUARE_NB]; + +// Fill psqt array from a set of internally linked parameters +extern void init(); + +} // namespace PSQT + + +#endif // PSQT_H_INCLUDED diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 36234786..115815e1 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -1000,7 +1000,7 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) { // so that d->lowestSym[i] >= d->lowestSym[i+1] (when read as LittleEndian). // Starting from this we compute a base64[] table indexed by symbol length // and containing 64 bit values so that d->base64[i] >= d->base64[i+1]. - // See http://www.eecs.harvard.edu/~michaelm/E210/huffman.pdf + // See https://en.wikipedia.org/wiki/Huffman_coding for (int i = d->base64.size() - 2; i >= 0; --i) { d->base64[i] = (d->base64[i + 1] + number(&d->lowestSym[i]) - number(&d->lowestSym[i + 1])) / 2; @@ -1440,7 +1440,7 @@ WDLScore Tablebases::probe_wdl(Position& pos, ProbeState* result) { // If n = 100 immediately after a capture or pawn move, then the position // is also certainly a win, and during the whole phase until the next // capture or pawn move, the inequality to be preserved is -// dtz + 50-movecounter <= 100. +// dtz + 50-move-counter <= 100. // // In short, if a move is available resulting in dtz + 50-move-counter <= 99, // then do not accept moves leading to dtz + 50-move-counter == 100. diff --git a/src/tune.h b/src/tune.h index ef418968..c2cd0c97 100644 --- a/src/tune.h +++ b/src/tune.h @@ -130,9 +130,9 @@ class Tune { SetRange range; }; - // Our facilty to fill the container, each Entry corresponds to a parameter to tune. - // We use variadic templates to deal with an unspecified number of entries, each one - // of a possible different type. + // Our facility to fill the container, each Entry corresponds to a parameter + // to tune. We use variadic templates to deal with an unspecified number of + // entries, each one of a possible different type. static std::string next(std::string& names, bool pop = true); int add(const SetRange&, std::string&&) { return 0; } From 7d0a16e06d968c81f17140b0123db9768ce02a82 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Sat, 16 Jan 2021 01:44:11 -0300 Subject: [PATCH 43/88] Avoid more expensive legality check speedup of the code, enough to pass STC, failed LTC. Passed STC: LLR: 2.93 (-2.94,2.94) {-0.25,1.25} Total: 68928 W: 6334 L: 6122 D: 56472 Ptnml(0-2): 233, 4701, 24369, 4943, 218 https://tests.stockfishchess.org/tests/view/6002747f6019e097de3ef8dc Failed LTC: LLR: -2.96 (-2.94,2.94) {0.25,1.25} Total: 44560 W: 1702 L: 1675 D: 41183 Ptnml(0-2): 25, 1383, 19438, 1408, 26 https://tests.stockfishchess.org/tests/view/6002a4836019e097de3ef8e3 About 1% speedup: Result of 50 runs ================== base (...kfish.master) = 2237500 +/- 7428 test (...ckfish.patch) = 2267003 +/- 7017 diff = +29503 +/- 4774 speedup = +0.0132 P(speedup > 0) = 1.0000 closes https://github.com/official-stockfish/Stockfish/pull/3304 No functional change. --- src/position.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/position.cpp b/src/position.cpp index 6a5d09ee..ad1865f0 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -564,8 +564,10 @@ bool Position::pseudo_legal(const Move m) const { Piece pc = moved_piece(m); // Use a slower but simpler function for uncommon cases + // yet we skip the legality check of MoveList(). if (type_of(m) != NORMAL) - return MoveList(*this).contains(m); + return checkers() ? MoveList< EVASIONS>(*this).contains(m) + : MoveList(*this).contains(m); // Is not a promotion, so promotion piece must be empty if (promotion_type(m) - KNIGHT != NO_PIECE_TYPE) From befbcffb4e4c5d2ebfb9504b059a337ae4a60ece Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 18 Jan 2021 17:03:43 -0300 Subject: [PATCH 44/88] Clean Up Castling in gives_check There is no need to add rto or kto on the Bitboard which represents the pieces. STC: LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 57064 W: 5096 L: 5067 D: 46901 Ptnml(0-2): 202, 3862, 20355, 3931, 182 https://tests.stockfishchess.org/tests/view/6005ea2c6019e097de3efa55 LTC: LLR: 2.92 (-2.94,2.94) {-0.75,0.25} Total: 30088 W: 1094 L: 1052 D: 27942 Ptnml(0-2): 10, 882, 13217, 926, 9 https://tests.stockfishchess.org/tests/view/6006115a6019e097de3efa6e closes https://github.com/official-stockfish/Stockfish/pull/3311 No functional change. --- src/position.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index ad1865f0..954e5ffd 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -665,19 +665,15 @@ bool Position::gives_check(Move m) const { return (attacks_bb< ROOK>(square(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK)) | (attacks_bb(square(~sideToMove), b) & pieces(sideToMove, QUEEN, BISHOP)); } - case CASTLING: + default: //CASTLING { - Square kfrom = from; - Square rfrom = to; // Castling is encoded as 'king captures the rook' - Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1); - Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1); + // Castling is encoded as 'king captures the rook' + Square ksq = square(~sideToMove); + Square rto = relative_square(sideToMove, to > from ? SQ_F1 : SQ_D1); - return (attacks_bb(rto) & square(~sideToMove)) - && (attacks_bb(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square(~sideToMove)); + return (attacks_bb(rto) & ksq) + && (attacks_bb(rto, pieces() ^ from ^ to) & ksq); } - default: - assert(false); - return false; } } From 0db374777e793f60bb897d078b3ab641613112ad Mon Sep 17 00:00:00 2001 From: bmc4 Date: Tue, 19 Jan 2021 09:21:59 -0300 Subject: [PATCH 45/88] Speed Up Perft Search It speeds up generate, and thus perft, roughly by 2-3%. closes https://github.com/official-stockfish/Stockfish/pull/3312 No functional change --- src/movegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 14df1f05..c9d6a90d 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -354,7 +354,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { moveList = pos.checkers() ? generate(pos, moveList) : generate(pos, moveList); while (cur != moveList) - if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT) + if ( ((pinned && pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT) && !pos.legal(*cur)) *cur = (--moveList)->move; else From dd9609521437dc839236c36d35bdb8cb633ba19f Mon Sep 17 00:00:00 2001 From: bmc4 Date: Sun, 17 Jan 2021 15:21:45 -0300 Subject: [PATCH 46/88] Simplify Chess 960 castling a little cleanup, and small speedup (about 0.3%) for Chess 960. Verified with perft on a large set of chess960 positions. Closes https://github.com/official-stockfish/Stockfish/pull/3317 No functional change --- src/position.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 954e5ffd..826e847f 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -533,11 +533,9 @@ bool Position::legal(Move m) const { if (attackers_to(s) & pieces(~us)) return false; - // In case of Chess960, verify that when moving the castling rook we do - // not discover some hidden checker. + // In case of Chess960, verify if the Rook blocks some checks // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. - return !chess960 - || !(attacks_bb(to, pieces() ^ to_sq(m)) & pieces(~us, ROOK, QUEEN)); + return !chess960 || !(blockers_for_king(us) & to_sq(m)); } // If the moving piece is a king, check whether the destination square is From 6617ad6e033fc636e82453e121469f10e4f31a1a Mon Sep 17 00:00:00 2001 From: bmc4 Date: Sun, 31 Jan 2021 00:05:39 -0300 Subject: [PATCH 47/88] Tune ordering of moves at internal nodes We change the relative weights of the function used to order quiet moves in our MovePicker class. Passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 32184 W: 2936 L: 2773 D: 26475 Ptnml(0-2): 115, 2196, 11328, 2317, 136 https://tests.stockfishchess.org/tests/view/60161ee1735dd7f0f03530f8 Passed LTC: LLR: 2.93 (-2.94,2.94) {0.25,1.25} Total: 33088 W: 1292 L: 1149 D: 30647 Ptnml(0-2): 14, 1030, 14318, 1163, 19 https://tests.stockfishchess.org/tests/view/60163146735dd7f0f03530ff The new weight were chosen after the following SPSA session: https://tests.stockfishchess.org/tests/view/60136857735dd7f0f0352f6c Closes https://github.com/official-stockfish/Stockfish/pull/3331 Bench: 4398803 --- src/movepick.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 9cb8447f..f5b27496 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -106,8 +106,8 @@ void MovePicker::score() { else if (Type == QUIETS) m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] - + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] - + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] + + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] + (ply < MAX_LPH ? std::min(4, depth / 3) * (*lowPlyHistory)[ply][from_to(m)] : 0); @@ -117,8 +117,8 @@ void MovePicker::score() { m.value = PieceValue[MG][pos.piece_on(to_sq(m))] - Value(type_of(pos.moved_piece(m))); else - m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] + + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] - (1 << 28); } } From 9f8058bd26df1c3ca37b85f811026f1eb82e6524 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Sun, 31 Jan 2021 10:12:32 -0300 Subject: [PATCH 48/88] Simplify En Passant simplifies the handling of en passant during search, needs a little more care in initialization. Passed STC: LLR: 2.95 (-2.94,2.94) {-1.25,0.25} Total: 72608 W: 6569 L: 6559 D: 59480 Ptnml(0-2): 233, 5117, 25629, 5057, 268 https://tests.stockfishchess.org/tests/view/600f1363735dd7f0f0352ce7 Passed LTC: LLR: 2.92 (-2.94,2.94) {-0.75,0.25} Total: 24328 W: 913 L: 864 D: 22551 Ptnml(0-2): 10, 731, 10633, 780, 10 https://tests.stockfishchess.org/tests/view/600f2e93735dd7f0f0352cf6 closes https://github.com/official-stockfish/Stockfish/pull/3330 No functional change. --- src/position.cpp | 55 +++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 826e847f..35e307ef 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -249,6 +249,8 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th set_castling_right(c, rsq); } + set_state(st); + // 4. En passant square. // Ignore if square is invalid or not on side to move relative rank 6. bool enpassant = false; @@ -262,12 +264,24 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th // a) side to move have a pawn threatening epSquare // b) there is an enemy pawn in front of epSquare // c) there is no piece on epSquare or behind epSquare + // d) enemy pawn didn't block a check of its own color by moving forward enpassant = pawn_attacks_bb(~sideToMove, st->epSquare) & pieces(sideToMove, PAWN) && (pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove))) - && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove)))); + && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove)))) + && (file_of(square(sideToMove)) == file_of(st->epSquare) + || !(blockers_for_king(sideToMove) & (st->epSquare + pawn_push(~sideToMove)))); } - if (!enpassant) + // It's necessary for st->previous to be intialized in this way because legality check relies on its existence + if (enpassant) { + st->previous = new StateInfo(); + remove_piece(st->epSquare - pawn_push(sideToMove)); + st->previous->checkersBB = attackers_to(square(~sideToMove)) & pieces(sideToMove); + st->previous->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square(WHITE), st->previous->pinners[BLACK]); + st->previous->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square(BLACK), st->previous->pinners[WHITE]); + put_piece(make_piece(~sideToMove, PAWN), st->epSquare - pawn_push(sideToMove)); + } + else st->epSquare = SQ_NONE; // 5-6. Halfmove clock and fullmove number @@ -279,7 +293,6 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th chess960 = isChess960; thisThread = th; - set_state(st); st->accumulator.state[WHITE] = Eval::NNUE::INIT; st->accumulator.state[BLACK] = Eval::NNUE::INIT; @@ -502,23 +515,11 @@ bool Position::legal(Move m) const { assert(color_of(moved_piece(m)) == us); assert(piece_on(square(us)) == make_piece(us, KING)); - // En passant captures are a tricky special case. Because they are rather - // uncommon, we do it simply by testing whether the king is attacked after - // the move is made. + // st->previous->blockersForKing consider capsq as empty. + // If pinned, it has to move along the king ray. if (type_of(m) == EN_PASSANT) - { - Square ksq = square(us); - Square capsq = to - pawn_push(us); - Bitboard occupied = (pieces() ^ from ^ capsq) | to; - - assert(to == ep_square()); - assert(moved_piece(m) == make_piece(us, PAWN)); - assert(piece_on(capsq) == make_piece(~us, PAWN)); - assert(piece_on(to) == NO_PIECE); - - return !(attacks_bb< ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK)) - && !(attacks_bb(ksq, occupied) & pieces(~us, QUEEN, BISHOP)); - } + return !(st->previous->blockersForKing[sideToMove] & from) || + aligned(from, to, square(us)); // Castling moves generation does not check if the castling path is clear of // enemy attacks, it is delayed at a later time: now! @@ -651,18 +652,14 @@ bool Position::gives_check(Move m) const { case PROMOTION: return attacks_bb(promotion_type(m), to, pieces() ^ from) & square(~sideToMove); - // En passant capture with check? We have already handled the case - // of direct checks and ordinary discovered check, so the only case we - // need to handle is the unusual case of a discovered check through - // the captured pawn. + // The double-pushed pawn blocked a check? En Passant will remove the blocker. + // The only discovery check that wasn't handle is through capsq and fromsq + // So the King must be in the same rank as fromsq to consider this possibility. + // st->previous->blockersForKing consider capsq as empty. case EN_PASSANT: - { - Square capsq = make_square(file_of(to), rank_of(from)); - Bitboard b = (pieces() ^ from ^ capsq) | to; + return st->previous->checkersBB || (rank_of(square(~sideToMove)) == rank_of(from) + && st->previous->blockersForKing[~sideToMove] & from); - return (attacks_bb< ROOK>(square(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK)) - | (attacks_bb(square(~sideToMove), b) & pieces(sideToMove, QUEEN, BISHOP)); - } default: //CASTLING { // Castling is encoded as 'king captures the rook' From 5ebdc40f8301745b4f8023e595ca2ddde74aa647 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 7 Feb 2021 13:44:11 +0200 Subject: [PATCH 49/88] Pawns Tuning A simple tuning of Pawns parameters, and some PSQT changes. Passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 219424 W: 43681 L: 43103 D: 132640 Ptnml(0-2): 4014, 25760, 49669, 26172, 4097 https://tests.stockfishchess.org/tests/view/601bce167f517a561bc491eb Passed LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 317312 W: 42525 L: 41579 D: 233208 Ptnml(0-2): 2447, 30157, 92636, 30835, 2581 https://tests.stockfishchess.org/tests/view/601c21557f517a561bc49227 closes https://github.com/official-stockfish/Stockfish/pull/3337 Bench: 4154473 --- src/pawns.cpp | 16 ++++++++-------- src/psqt.cpp | 18 +++++++++--------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 5d6770ed..cd4d4e45 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -30,22 +30,22 @@ namespace { #define S(mg, eg) make_score(mg, eg) // Pawn penalties - constexpr Score Backward = S( 6, 23); - constexpr Score Doubled = S(13, 53); - constexpr Score DoubledEarly = S(20, 10); - constexpr Score Isolated = S( 2, 15); - constexpr Score WeakLever = S( 5, 57); - constexpr Score WeakUnopposed = S(16, 22); + constexpr Score Backward = S( 9, 22); + constexpr Score Doubled = S(13, 51); + constexpr Score DoubledEarly = S(20, 7); + constexpr Score Isolated = S( 3, 15); + constexpr Score WeakLever = S( 4, 58); + constexpr Score WeakUnopposed = S(13, 24); // Bonus for blocked pawns at 5th or 6th rank - constexpr Score BlockedPawn[2] = { S(-15, -3), S(-6, 3) }; + constexpr Score BlockedPawn[2] = { S(-17, -6), S(-9, 2) }; constexpr Score BlockedStorm[RANK_NB] = { S(0, 0), S(0, 0), S(75, 78), S(-8, 16), S(-6, 10), S(-6, 6), S(0, 2) }; // Connected pawn bonus - constexpr int Connected[RANK_NB] = { 0, 5, 7, 11, 24, 48, 86 }; + constexpr int Connected[RANK_NB] = { 0, 5, 7, 11, 23, 48, 87 }; // Strength of pawn shelter for our king by [distance from edge][rank]. // RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king. diff --git a/src/psqt.cpp b/src/psqt.cpp index 46605d52..cfade295 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -67,13 +67,13 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { }, { // Queen { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) }, - { S(-3,-55), S( 5,-31), S( 8,-22), S(12, -4) }, + { S(-3,-54), S( 5,-31), S( 8,-22), S(12, -4) }, { S(-3,-39), S( 6,-18), S(13, -9), S( 7, 3) }, { S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) }, { S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) }, - { S(-4,-38), S(10,-18), S( 6,-12), S( 8, 1) }, + { S(-4,-38), S(10,-18), S( 6,-11), S( 8, 1) }, { S(-5,-50), S( 6,-27), S(10,-24), S( 8, -8) }, - { S(-2,-75), S(-2,-52), S( 1,-43), S(-2,-36) } + { S(-2,-74), S(-2,-52), S( 1,-43), S(-2,-34) } }, { // King { S(271, 1), S(327, 45), S(271, 85), S(198, 76) }, @@ -90,12 +90,12 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { constexpr Score PBonus[RANK_NB][FILE_NB] = { // Pawn (asymmetric distribution) { }, - { S( 3,-10), S( 3, -6), S( 10, 10), S( 19, 0), S( 16, 14), S( 19, 7), S( 7, -5), S( -5,-19) }, - { S( -9,-10), S(-15,-10), S( 11,-10), S( 15, 4), S( 32, 4), S( 22, 3), S( 5, -6), S(-22, -4) }, - { S( -4, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S( -8, -9) }, - { S( 13, 10), S( 0, 5), S(-13, 4), S( 1, -5), S( 11, -5), S( -2, -5), S(-13, 14), S( 5, 9) }, - { S( 5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S( -8, 13) }, - { S( -7, 0), S( 7,-11), S( -3, 12), S(-13, 21), S( 5, 25), S(-16, 19), S( 10, 4), S( -8, 7) } + { S( 2, -8), S( 4, -6), S( 11, 9), S( 18, 5), S( 16, 16), S( 21, 6), S( 9, -6), S( -3,-18) }, + { S( -9, -9), S(-15, -7), S( 11,-10), S( 15, 5), S( 31, 2), S( 23, 3), S( 6, -8), S(-20, -5) }, + { S( -3, 7), S(-20, 1), S( 8, -8), S( 19, -2), S( 39,-14), S( 17,-13), S( 2,-11), S( -5, -6) }, + { S( 11, 12), S( -4, 6), S(-11, 2), S( 2, -6), S( 11, -5), S( 0, -4), S(-12, 14), S( 5, 9) }, + { S( 3, 27), S(-11, 18), S( -6, 19), S( 22, 29), S( -8, 30), S( -5, 9), S(-14, 8), S(-11, 14) }, + { S( -7, -1), S( 6,-14), S( -2, 13), S(-11, 22), S( 4, 24), S(-14, 17), S( 10, 7), S( -9, 7) } }; } // namespace From 29ed22de8cd347cacb0ba826ee43fa587985a98d Mon Sep 17 00:00:00 2001 From: bmc4 Date: Thu, 4 Feb 2021 21:50:22 -0300 Subject: [PATCH 50/88] Search Parameters Tuning A simple tuning on search.cpp. based SPSA test: https://tests.stockfishchess.org/tests/view/601f2a787f517a561bc493cd passed STC: LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 117840 W: 10796 L: 10508 D: 96536 Ptnml(0-2): 422, 8381, 41041, 8639, 437 https://tests.stockfishchess.org/tests/view/602144c37f517a561bc494ae passed LTC: LLR: 2.96 (-2.94,2.94) {0.25,1.25} Total: 25024 W: 972 L: 847 D: 23205 Ptnml(0-2): 7, 767, 10847, 876, 15 https://tests.stockfishchess.org/tests/view/602156877f517a561bc494be closes https://github.com/official-stockfish/Stockfish/pull/3340 Bench: 3974098 --- src/search.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6cc115fc..80c3e4c2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -81,7 +81,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return d > 14 ? 29 : 8 * d * d + 224 * d - 215; + return d > 14 ? 66 : 6 * d * d + 231 * d - 206; } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -839,10 +839,10 @@ namespace { // Step 8. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 22977 + && (ss-1)->statScore < 22661 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 30 * depth - 28 * improving + 84 * ss->ttPv + 168 + && ss->staticEval >= beta - 24 * depth - 34 * improving + 162 * ss->ttPv + 159 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -850,7 +850,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = (1015 + 85 * depth) / 256 + std::min(int(eval - beta) / 191, 3); + Depth R = (1062 + 68 * depth) / 256 + std::min(int(eval - beta) / 190, 3); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -886,7 +886,7 @@ namespace { } } - probCutBeta = beta + 194 - 49 * improving; + probCutBeta = beta + 209 - 44 * improving; // Step 9. ProbCut (~10 Elo) // If we have a good enough capture and a reduced search returns a value @@ -1063,11 +1063,11 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 7 && !ss->inCheck - && ss->staticEval + 254 + 159 * lmrDepth <= alpha + && ss->staticEval + 174 + 157 * lmrDepth <= alpha && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 26394) + + (*contHist[5])[movedPiece][to_sq(move)] / 3 < 26237) continue; // Prune moves with negative SEE (~20 Elo) @@ -1223,13 +1223,13 @@ moves_loop: // When in check, search starts from here + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - - 5287; + - 5337; // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) - if (ss->statScore >= -105 && (ss-1)->statScore < -103) + if (ss->statScore >= -89 && (ss-1)->statScore < -116) r--; - else if ((ss-1)->statScore >= -122 && ss->statScore < -129) + else if ((ss-1)->statScore >= -112 && ss->statScore < -100) r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) @@ -1237,9 +1237,9 @@ moves_loop: // When in check, search starts from here // use sum of main history and first continuation history with an offset if (ss->inCheck) r -= (thisThread->mainHistory[us][from_to(move)] - + (*contHist[0])[movedPiece][to_sq(move)] - 4333) / 16384; + + (*contHist[0])[movedPiece][to_sq(move)] - 4341) / 16384; else - r -= ss->statScore / 14884; + r -= ss->statScore / 14382; } Depth d = std::clamp(newDepth - r, 1, newDepth); @@ -1711,8 +1711,8 @@ moves_loop: // When in check, search starts from here PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); bonus1 = stat_bonus(depth + 1); - bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus - : stat_bonus(depth); // smaller bonus + bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : std::min(bonus1, stat_bonus(depth)); // smaller bonus if (!pos.capture_or_promotion(bestMove)) { From 1f87a9eb6c2cd51be5a2f28d8b5694d931408a66 Mon Sep 17 00:00:00 2001 From: Andy Pilate Date: Mon, 8 Feb 2021 22:02:42 +0100 Subject: [PATCH 51/88] Fixes FreeBSD compilation when using Clang closes https://github.com/official-stockfish/Stockfish/pull/3342 No functional change --- src/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Makefile b/src/Makefile index 87203547..55139a1f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -366,9 +366,11 @@ ifeq ($(COMP),clang) ifneq ($(KERNEL),Darwin) ifneq ($(KERNEL),OpenBSD) + ifneq ($(KERNEL),FreeBSD) LDFLAGS += -latomic endif endif + endif ifeq ($(arch),$(filter $(arch),armv7 armv8)) ifeq ($(OS),Android) From b15e3b3fa9a4fb5da6e30685c0813a62cee5dd3f Mon Sep 17 00:00:00 2001 From: Gian-Carlo Pascutto Date: Tue, 9 Feb 2021 14:05:35 +0100 Subject: [PATCH 52/88] Disable ThinLTO when using Clang. Benchmarking with current Clang 12 shows that and ThinLTO is a pessimization, see issue #3341. closes https://github.com/official-stockfish/Stockfish/pull/3345 No functional change. --- src/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 55139a1f..827ce6bb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -590,7 +590,7 @@ endif ifeq ($(optimize),yes) ifeq ($(debug), no) ifeq ($(comp),clang) - CXXFLAGS += -flto=thin + CXXFLAGS += -flto ifneq ($(findstring MINGW,$(KERNEL)),) CXXFLAGS += -fuse-ld=lld else ifneq ($(findstring MSYS,$(KERNEL)),) @@ -610,7 +610,7 @@ ifeq ($(debug), no) LDFLAGS += -save-temps endif else - CXXFLAGS += -flto=thin + CXXFLAGS += -flto LDFLAGS += $(CXXFLAGS) endif From 550fed3343089357dc89ecf78ce8eb4b35bcab88 Mon Sep 17 00:00:00 2001 From: Gian-Carlo Pascutto Date: Tue, 9 Feb 2021 17:38:58 +0100 Subject: [PATCH 53/88] Enable New Pass Manager for Clang. It's about 1% speedup for Stockfish. Result of 100 runs ================== base (...fish_clang12) = 1946851 +/- 3717 test (./stockfish ) = 1967276 +/- 3408 diff = +20425 +/- 2438 speedup = +0.0105 P(speedup > 0) = 1.0000 Thanks to David Major for making me aware of this part of LLVM development. closes https://github.com/official-stockfish/Stockfish/pull/3346 No functional change --- src/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Makefile b/src/Makefile index 827ce6bb..1ff03f83 100644 --- a/src/Makefile +++ b/src/Makefile @@ -481,6 +481,10 @@ ifeq ($(optimize),yes) CXXFLAGS += -mdynamic-no-pic endif endif + + ifeq ($(comp),clang) + CXXFLAGS += -fexperimental-new-pass-manager + endif endif ### 3.4 Bits From 573f0e364ff4c1e5928be2ca947f65c5d4e177d5 Mon Sep 17 00:00:00 2001 From: mattginsberg Date: Thu, 11 Feb 2021 22:29:28 +0100 Subject: [PATCH 54/88] Better code for hash table generation This patch removes some magic numbers in TT bit management and introduce proper constants in the code, to improve documentation and ease further modifications. No function change --- AUTHORS | 1 + src/tt.cpp | 15 ++++++++------- src/tt.h | 8 +++++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index d2b26469..5f21c048 100644 --- a/AUTHORS +++ b/AUTHORS @@ -113,6 +113,7 @@ Maciej Żenczykowski (zenczykowski) Malcolm Campbell (xoto10) Mark Tenzer (31m059) marotear +Matt Ginsberg (mattginsberg) Matthew Lai (matthewlai) Matthew Sullivan (Matt14916) Maxim Molchanov (Maxim) diff --git a/src/tt.cpp b/src/tt.cpp index d1ba9ebb..cb5af5c8 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -123,7 +123,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { for (int i = 0; i < ClusterSize; ++i) if (tte[i].key16 == key16 || !tte[i].depth8) { - tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & 0x7)); // Refresh + tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & (GENERATION_DELTA - 1))); // Refresh return found = (bool)tte[i].depth8, &tte[i]; } @@ -132,11 +132,12 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { TTEntry* replace = tte; for (int i = 1; i < ClusterSize; ++i) // Due to our packed storage format for generation and its cyclic - // nature we add 263 (256 is the modulus plus 7 to keep the unrelated - // lowest three bits from affecting the result) to calculate the entry - // age correctly even after generation8 overflows into the next cycle. - if ( replace->depth8 - ((263 + generation8 - replace->genBound8) & 0xF8) - > tte[i].depth8 - ((263 + generation8 - tte[i].genBound8) & 0xF8)) + // nature we add GENERATION_CYCLE (256 is the modulus, plus what + // is needed to keep the unrelated lowest n bits from affecting + // the result) to calculate the entry age correctly even after + // generation8 overflows into the next cycle. + if ( replace->depth8 - ((GENERATION_CYCLE + generation8 - replace->genBound8) & GENERATION_MASK) + > tte[i].depth8 - ((GENERATION_CYCLE + generation8 - tte[i].genBound8) & GENERATION_MASK)) replace = &tte[i]; return found = false, replace; @@ -151,7 +152,7 @@ int TranspositionTable::hashfull() const { int cnt = 0; for (int i = 0; i < 1000; ++i) for (int j = 0; j < ClusterSize; ++j) - cnt += table[i].entry[j].depth8 && (table[i].entry[j].genBound8 & 0xF8) == generation8; + cnt += table[i].entry[j].depth8 && (table[i].entry[j].genBound8 & GENERATION_MASK) == generation8; return cnt / ClusterSize; } diff --git a/src/tt.h b/src/tt.h index 5f9525a6..a750b6c4 100644 --- a/src/tt.h +++ b/src/tt.h @@ -72,9 +72,15 @@ class TranspositionTable { static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size"); + // Constants used to refresh the hash table periodically + static constexpr unsigned GENERATION_BITS = 3; // nb of bits reserved for other things + static constexpr int GENERATION_DELTA = (1 << GENERATION_BITS); // increment for generation field + static constexpr int GENERATION_CYCLE = 255 + (1 << GENERATION_BITS); // cycle length + static constexpr int GENERATION_MASK = (0xFF << GENERATION_BITS) & 0xFF; // mask to pull out generation number + public: ~TranspositionTable() { aligned_large_pages_free(table); } - void new_search() { generation8 += 8; } // Lower 3 bits are used by PV flag and Bound + void new_search() { generation8 += GENERATION_DELTA; } // Lower bits are used for other things TTEntry* probe(const Key key, bool& found) const; int hashfull() const; void resize(size_t mbSize); From 76daa88cf878b12a03755dc0550b3fa8e4d19cb1 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Thu, 11 Feb 2021 10:45:16 +0300 Subject: [PATCH 55/88] PV-Nodes likely to fail low Do not decrease reduction at pv-nodes which are likely to fail low. The idea of this patch can be described as following: during the search, if a node on the principal variation was re-searched in non-pv search and this re-search got a value which was much lower than alpha, then we can assume that this pv-node is likely to fail low again, and we can reduce more aggressively at this node. Passed STC https://tests.stockfishchess.org/tests/view/6023a5fa7f517a561bc49638 LLR: 2.95 (-2.94,2.94) {-0.25,1.25} Total: 70288 W: 6443 L: 6223 D: 57622 Ptnml(0-2): 239, 5022, 24436, 5174, 273 Passed LTC https://tests.stockfishchess.org/tests/view/6023f2617f517a561bc49661 LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 105656 W: 4048 L: 3748 D: 97860 Ptnml(0-2): 67, 3312, 45761, 3630, 58 Closes https://github.com/official-stockfish/Stockfish/pull/3349 Bench: 3766422 --- src/search.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 80c3e4c2..d77ab691 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1025,6 +1025,14 @@ moves_loop: // When in check, search starts from here movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); + // Indicate PvNodes that will probably fail low if node was searched with non-PV search + // at depth equal or greater to current depth and result of this search was far below alpha + bool likelyFailLow = PvNode + && ttMove + && (tte->bound() & BOUND_UPPER) + && ttValue < alpha + 200 + 100 * depth + && tte->depth() >= depth; + // Calculate new depth for this move newDepth = depth - 1; @@ -1172,8 +1180,9 @@ moves_loop: // When in check, search starts from here if (th.marked()) r++; - // Decrease reduction if position is or has been on the PV (~10 Elo) - if (ss->ttPv) + // Decrease reduction if position is or has been on the PV + // and node is not likely to fail low (~10 Elo) + if (ss->ttPv && !likelyFailLow) r -= 2; // Increase reduction at root and non-PV nodes when the best move does not change frequently From b46813f9b74c9edcb830b32d877469ed428072ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Mon, 15 Feb 2021 23:58:03 +0100 Subject: [PATCH 56/88] Update Top CPU Contributors No functional change --- Top CPU Contributors.txt | 358 ++++++++++++++++++++------------------- 1 file changed, 187 insertions(+), 171 deletions(-) diff --git a/Top CPU Contributors.txt b/Top CPU Contributors.txt index 482e9000..f5347ea1 100644 --- a/Top CPU Contributors.txt +++ b/Top CPU Contributors.txt @@ -1,173 +1,189 @@ -Contributors with >10,000 CPU hours as of Sept 2, 2020 +Contributors to Fishtest with >10,000 CPU hours, as of Feb 15, 2021. Thank you! -Username CPU Hours Games played --------------------------------------------------- -noobpwnftw 19352969 1231459677 -mlang 957168 61657446 -dew 949885 56893432 -mibere 703817 46865007 -crunchy 427035 27344275 -cw 416006 27521077 -JojoM 415904 24479564 -fastgm 404873 23953472 -CSU_Dynasty 335774 22850550 -tvijlbrief 335199 21871270 -Fisherman 325053 21786603 -gvreuls 311480 20751516 -ctoks 275877 18710423 -velislav 241267 15596372 -glinscott 217799 13780820 -nordlandia 211692 13484886 -bcross 206213 14934233 -bking_US 198894 11876016 -leszek 189170 11446821 -mgrabiak 183896 11778092 -drabel 181408 12489478 -TueRens 181349 12192000 -Thanar 179852 12365359 -vdv 175171 9881246 -robal 166948 10702862 -spams 157128 10319326 -marrco 149947 9376421 -sqrt2 147963 9724586 -vdbergh 137041 8926915 -CoffeeOne 136294 5004100 -malala 136182 8002293 -mhoram 128934 8177193 -davar 122092 7960001 -dsmith 122059 7570238 -xoto 119696 8222144 -grandphish2 116481 7582197 -Data 113305 8220352 -BrunoBanani 112960 7436849 -ElbertoOne 99028 7023771 -MaZePallas 98571 6362619 -brabos 92118 6186135 -psk 89957 5984901 -sunu 88463 6007033 -sterni1971 86948 5613788 -Vizvezdenec 83752 5343724 -BRAVONE 81239 5054681 -nssy 76497 5259388 -teddybaer 75125 5407666 -Pking_cda 73776 5293873 -jromang 70695 4940891 -solarlight 70517 5028306 -dv8silencer 70287 3883992 -Bobo1239 68515 4652287 -racerschmacer 67468 4935996 -manap 66273 4121774 -tinker 63458 4213726 -linrock 59082 4516053 -robnjr 57262 4053117 -Freja 56938 3733019 -ttruscott 56005 3679485 -renouve 53811 3501516 -cuistot 52532 3014920 -finfish 51360 3370515 -eva42 51272 3599691 -rkl 50759 3840947 -rap 49985 3219146 -pb00067 49727 3298270 -ronaldjerum 47654 3240695 -bigpen0r 47278 3291647 -biffhero 46564 3111352 -VoyagerOne 45386 3445881 -speedycpu 43842 3003273 -jbwiebe 43305 2805433 -Antihistamine 41788 2761312 -mhunt 41735 2691355 -eastorwest 40387 2812173 -homyur 39893 2850481 -gri 39871 2515779 -oryx 38228 2941656 -0x3C33 37773 2529097 -SC 37290 2731014 -csnodgrass 36207 2688994 -jmdana 36108 2205261 -strelock 34716 2074055 -Garf 33800 2747562 -EthanOConnor 33370 2090311 -slakovv 32915 2021889 -Spprtr 32591 2139601 -Prcuvu 30377 2170122 -anst 30301 2190091 -jkiiski 30136 1904470 -hyperbolic.tom 29840 2017394 -Pyafue 29650 1902349 -OuaisBla 27629 1578000 -chriswk 26902 1868317 -achambord 26582 1767323 -Patrick_G 26276 1801617 -yorkman 26193 1992080 -SFTUser 25182 1675689 -nabildanial 24942 1519409 -Sharaf_DG 24765 1786697 -ncfish1 24411 1520927 -agg177 23890 1395014 -JanErik 23408 1703875 -Isidor 23388 1680691 -Norabor 22976 1587862 -cisco2015 22880 1759669 -Zirie 22542 1472937 -team-oh 22272 1636708 -MazeOfGalious 21978 1629593 -sg4032 21945 1643065 -ianh2105 21725 1632562 -xor12 21628 1680365 -dex 21612 1467203 -nesoneg 21494 1463031 -horst.prack 20878 1465656 -0xB00B1ES 20590 1208666 -j3corre 20405 941444 -Adrian.Schmidt123 20316 1281436 -wei 19973 1745989 -rstoesser 19569 1293588 -eudhan 19274 1283717 -Ente 19070 1373058 -jundery 18445 1115855 -iisiraider 18247 1101015 -ville 17883 1384026 -chris 17698 1487385 -purplefishies 17595 1092533 -DragonLord 17014 1162790 -dju 16515 929427 -IgorLeMasson 16064 1147232 -ako027ako 15671 1173203 -Nikolay.IT 15154 1068349 -Andrew Grant 15114 895539 -yurikvelo 15027 1165616 -OssumOpossum 14857 1007129 -enedene 14476 905279 -bpfliegel 14298 884523 -jpulman 13982 870599 -joster 13794 950160 -Nesa92 13786 1114691 -Dark_wizzie 13422 1007152 -Hjax 13350 900887 -Fifis 13313 965473 -mabichito 12903 749391 -thijsk 12886 722107 -crocogoat 12876 1048802 -AdrianSA 12860 804972 -Flopzee 12698 894821 -fatmurphy 12547 853210 -SapphireBrand 12416 969604 -modolief 12386 896470 -scuzzi 12362 833465 -pgontarz 12151 848794 -stocky 11954 699440 -mschmidt 11941 803401 -infinity 11470 727027 -torbjo 11387 728873 -Thomas A. Anderson 11372 732094 -snicolet 11106 869170 -amicic 10779 733593 -rpngn 10712 688203 -d64 10680 771144 -basepi 10637 744851 -jjoshua2 10559 670905 -dzjp 10343 732529 -ols 10259 570669 -lbraesch 10252 647825 +Username CPU Hours Games played +---------------------------------------------------- +noobpwnftw 23930906 1560559941 +dew 1169948 70333008 +mlang 957168 61657446 +mibere 703840 46867607 +tvijlbrief 517888 33379462 +JojoM 515404 30334272 +cw 443276 29385549 +crunchy 427035 27344275 +grandphish2 425794 26347253 +fastgm 414133 24519696 +gvreuls 377843 24708884 +CSU_Dynasty 338718 23030006 +Fisherman 326795 21820747 +TueRens 313730 19490246 +ctoks 298442 20052551 +velislav 270519 17355456 +bcross 241064 17196165 +glinscott 217799 13780820 +nordlandia 211692 13484886 +bking_US 198894 11876016 +drabel 191096 13129722 +leszek 189170 11446821 +mgrabiak 187153 12013300 +robal 181389 11539242 +Thanar 179852 12365359 +vdv 175274 9889046 +spams 157128 10319326 +marrco 150292 9401741 +sqrt2 147963 9724586 +CoffeeOne 137086 5022516 +vdbergh 137041 8926915 +malala 136182 8002293 +mhoram 132780 8398229 +xoto 124729 8652088 +davar 122092 7960001 +dsmith 122059 7570238 +Data 113305 8220352 +BrunoBanani 112960 7436849 +pemo 109598 5036441 +Dantist 106768 6431396 +MaZePallas 102741 6630419 +ElbertoOne 99028 7023771 +brabos 92118 6186135 +linrock 90903 6708639 +psk 89957 5984901 +sunu 88614 6020673 +sterni1971 86948 5613788 +Vizvezdenec 83761 5344740 +BRAVONE 81239 5054681 +nssy 76497 5259388 +cuistot 76366 4370584 +racerschmacer 75753 5442626 +teddybaer 75125 5407666 +Pking_cda 73776 5293873 +0x3C33 73133 4670293 +jromang 72117 5054915 +solarlight 70517 5028306 +dv8silencer 70287 3883992 +Bobo1239 68515 4652287 +manap 66273 4121774 +tinker 64321 4268390 +robnjr 57262 4053117 +Freja 56938 3733019 +ttruscott 56010 3680085 +rkl 54986 4150767 +renouve 53811 3501516 +finfish 51360 3370515 +eva42 51272 3599691 +rap 49985 3219146 +pb00067 49727 3298270 +amicic 49691 3042481 +ronaldjerum 47654 3240695 +bigpen0r 47278 3291647 +biffhero 46564 3111352 +VoyagerOne 45476 3452465 +eastorwest 45033 3071805 +speedycpu 43842 3003273 +jbwiebe 43305 2805433 +Antihistamine 41788 2761312 +mhunt 41735 2691355 +homyur 39893 2850481 +gri 39871 2515779 +oryx 38282 2944400 +Spprtr 38157 2470529 +SC 37290 2731014 +csnodgrass 36207 2688994 +jmdana 36157 2210661 +strelock 34716 2074055 +Garf 33800 2747562 +skiminki 33515 2055584 +EthanOConnor 33370 2090311 +slakovv 32915 2021889 +yurikvelo 32600 2255966 +Prcuvu 30377 2170122 +manapbk 30326 1770143 +anst 30301 2190091 +jkiiski 30136 1904470 +hyperbolic.tom 29840 2017394 +Pyafue 29650 1902349 +qurashee 27758 1509620 +OuaisBla 27636 1578800 +chriswk 26902 1868317 +achambord 26582 1767323 +Fifis 26376 1776853 +Patrick_G 26276 1801617 +yorkman 26193 1992080 +SFTUser 25182 1675689 +nabildanial 24942 1519409 +Sharaf_DG 24765 1786697 +ncfish1 24411 1520927 +agg177 23890 1395014 +JanErik 23408 1703875 +Isidor 23388 1680691 +Norabor 23164 1591830 +cisco2015 22895 1762069 +Zirie 22542 1472937 +team-oh 22272 1636708 +MazeOfGalious 21978 1629593 +sg4032 21945 1643065 +ianh2105 21725 1632562 +xor12 21628 1680365 +dex 21612 1467203 +nesoneg 21494 1463031 +jjoshua2 20997 1422689 +horst.prack 20878 1465656 +0xB00B1ES 20590 1208666 +sphinx 20515 1352368 +j3corre 20405 941444 +Adrian.Schmidt123 20316 1281436 +Ente 20017 1432602 +wei 19973 1745989 +rstoesser 19569 1293588 +eudhan 19274 1283717 +jundery 18445 1115855 +iisiraider 18247 1101015 +ville 17883 1384026 +chris 17698 1487385 +purplefishies 17595 1092533 +DMBK 17357 1279152 +DragonLord 17014 1162790 +dju 16515 929427 +IgorLeMasson 16064 1147232 +ako027ako 15671 1173203 +Nikolay.IT 15154 1068349 +Andrew Grant 15114 895539 +OssumOpossum 14857 1007129 +enedene 14476 905279 +bpfliegel 14298 884523 +jpulman 13982 870599 +joster 13794 950160 +Nesa92 13786 1114691 +crocogoat 13753 1114622 +Hjax 13535 915487 +Dark_wizzie 13422 1007152 +mpx86 12941 693640 +mabichito 12903 749391 +thijsk 12886 722107 +AdrianSA 12860 804972 +Flopzee 12698 894821 +fatmurphy 12547 853210 +scuzzi 12511 845761 +Karby 12429 735880 +SapphireBrand 12416 969604 +modolief 12386 896470 +pgontarz 12151 848794 +stocky 11954 699440 +mschmidt 11941 803401 +infinity 11470 727027 +torbjo 11395 729145 +Thomas A. Anderson 11372 732094 +d64 11263 789184 +Maxim 11129 804704 +snicolet 11106 869170 +MooTheCow 11008 694942 +savage84 10965 641068 +Rudolphous 10915 741268 +Wolfgang 10809 580032 +rpngn 10712 688203 +basepi 10637 744851 +michaelrpg 10409 735127 +dzjp 10343 732529 +ali-al-zhrani 10324 726502 +ols 10259 570669 +lbraesch 10252 647825 From 40cb0f076a62115af030c4524825d9ba73d61023 Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Sun, 31 Jan 2021 13:46:05 +0100 Subject: [PATCH 57/88] Small trivial clean-ups, February 2021 Closes https://github.com/official-stockfish/Stockfish/pull/3329 No functional change --- src/Makefile | 4 +--- src/evaluate.cpp | 1 - src/movepick.cpp | 4 ++-- src/position.cpp | 17 +++++++++-------- src/search.cpp | 14 +++++++------- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/Makefile b/src/Makefile index 1ff03f83..eb32758f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,5 @@ # Stockfish, a UCI chess playing engine derived from Glaurung 2.1 -# Copyright (C) 2004-2008 Tord Romstad (Glaurung author) -# Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad -# Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad +# Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) # # Stockfish is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0b211261..d55ef695 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -423,7 +423,6 @@ namespace { score += BishopOnKingRing; int mob = popcount(b & mobilityArea[Us]); - mobility[Us] += MobilityBonus[Pt - 2][mob]; if (Pt == BISHOP || Pt == KNIGHT) diff --git a/src/movepick.cpp b/src/movepick.cpp index f5b27496..0ceeb8ea 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -99,11 +99,11 @@ void MovePicker::score() { static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); for (auto& m : *this) - if (Type == CAPTURES) + if constexpr (Type == CAPTURES) m.value = int(PieceValue[MG][pos.piece_on(to_sq(m))]) * 6 + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; - else if (Type == QUIETS) + else if constexpr (Type == QUIETS) m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] diff --git a/src/position.cpp b/src/position.cpp index 35e307ef..2eb30ca0 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -268,8 +268,8 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th enpassant = pawn_attacks_bb(~sideToMove, st->epSquare) & pieces(sideToMove, PAWN) && (pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove))) && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove)))) - && (file_of(square(sideToMove)) == file_of(st->epSquare) - || !(blockers_for_king(sideToMove) & (st->epSquare + pawn_push(~sideToMove)))); + && ( file_of(square(sideToMove)) == file_of(st->epSquare) + || !(blockers_for_king(sideToMove) & (st->epSquare + pawn_push(~sideToMove)))); } // It's necessary for st->previous to be intialized in this way because legality check relies on its existence @@ -518,8 +518,8 @@ bool Position::legal(Move m) const { // st->previous->blockersForKing consider capsq as empty. // If pinned, it has to move along the king ray. if (type_of(m) == EN_PASSANT) - return !(st->previous->blockersForKing[sideToMove] & from) || - aligned(from, to, square(us)); + return !(st->previous->blockersForKing[sideToMove] & from) + || aligned(from, to, square(us)); // Castling moves generation does not check if the castling path is clear of // enemy attacks, it is delayed at a later time: now! @@ -546,8 +546,8 @@ bool Position::legal(Move m) const { // A non-king move is legal if and only if it is not pinned or it // is moving along the ray towards or away from the king. - return !(blockers_for_king(us) & from) - || aligned(from, to, square(us)); + return !(blockers_for_king(us) & from) + || aligned(from, to, square(us)); } @@ -657,8 +657,9 @@ bool Position::gives_check(Move m) const { // So the King must be in the same rank as fromsq to consider this possibility. // st->previous->blockersForKing consider capsq as empty. case EN_PASSANT: - return st->previous->checkersBB || (rank_of(square(~sideToMove)) == rank_of(from) - && st->previous->blockersForKing[~sideToMove] & from); + return st->previous->checkersBB + || ( rank_of(square(~sideToMove)) == rank_of(from) + && st->previous->blockersForKing[~sideToMove] & from); default: //CASTLING { diff --git a/src/search.cpp b/src/search.cpp index d77ab691..b5d21b9d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1025,12 +1025,12 @@ moves_loop: // When in check, search starts from here movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); - // Indicate PvNodes that will probably fail low if node was searched with non-PV search + // Indicate PvNodes that will probably fail low if node was searched with non-PV search // at depth equal or greater to current depth and result of this search was far below alpha - bool likelyFailLow = PvNode - && ttMove - && (tte->bound() & BOUND_UPPER) - && ttValue < alpha + 200 + 100 * depth + bool likelyFailLow = PvNode + && ttMove + && (tte->bound() & BOUND_UPPER) + && ttValue < alpha + 200 + 100 * depth && tte->depth() >= depth; // Calculate new depth for this move @@ -1180,8 +1180,8 @@ moves_loop: // When in check, search starts from here if (th.marked()) r++; - // Decrease reduction if position is or has been on the PV - // and node is not likely to fail low (~10 Elo) + // Decrease reduction if position is or has been on the PV + // and node is not likely to fail low. (~10 Elo) if (ss->ttPv && !likelyFailLow) r -= 2; From 9f6d69c544a64e06056524ddeaa690560b3896c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Tue, 16 Feb 2021 16:19:37 +0100 Subject: [PATCH 58/88] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • reorder some sections of the README file • add reference to the AUTHORS file • rename Syzygybases to Syzygy tablebases • add pointer to the Discord channel • more precise info about the GPLv3 licence No functional change --- README.md | 68 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index eb7aa5a7..fdc6fd61 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ This distribution of Stockfish consists of the following files: * Readme.md, the file you are currently reading. * Copying.txt, a text file containing the GNU General Public License version 3. + + * AUTHORS, a text file with the list of authors for the project * src, a subdirectory containing the full source code, including a Makefile that can be used to compile Stockfish on Unix-like systems. @@ -31,17 +33,6 @@ This distribution of Stockfish consists of the following files: * a file with the .nnue extension, storing the neural network for the NNUE evaluation. Binary distributions will have this file embedded. -Note: to use the NNUE evaluation, the additional data file with neural network parameters -needs to be available. Normally, this file is already embedded in the binary or it can be downloaded. -The filename for the default (recommended) net can be found as the default -value of the `EvalFile` UCI option, with the format `nn-[SHA256 first 12 digits].nnue` -(for instance, `nn-c157e0a5755b.nnue`). This file can be downloaded from -``` -https://tests.stockfishchess.org/api/nn/[filename] -``` -replacing `[filename]` as needed. - - ## UCI options Currently, Stockfish has the following UCI options: @@ -53,6 +44,9 @@ Currently, Stockfish has the following UCI options: * #### Hash The size of the hash table in MB. It is recommended to set Hash after setting Threads. + * #### Clear Hash + Clear the hash table. + * #### Ponder Let Stockfish ponder its next move while the opponent is thinking. @@ -109,7 +103,7 @@ Currently, Stockfish has the following UCI options: * #### SyzygyProbeDepth Minimum remaining search depth for which a position is probed. Set this option to a higher value to probe less aggressively if you experience too much slowdown - (in terms of nps) due to TB probing. + (in terms of nps) due to tablebase probing. * #### Syzygy50MoveRule Disable to let fifty-move rule draws detected by Syzygy tablebase probes count @@ -139,13 +133,10 @@ Currently, Stockfish has the following UCI options: Tells the engine to use nodes searched instead of wall time to account for elapsed time. Useful for engine testing. - * #### Clear Hash - Clear the hash table. - * #### Debug Log File Write all communication to and from the engine into a text file. -## A note on classical and NNUE evaluation +## A note on classical evaluation versus NNUE evaluation Both approaches assign a value to a position that is used in alpha-beta (PVS) search to find the best move. The classical evaluation computes this value as a function @@ -158,18 +149,29 @@ The NNUE evaluation was first introduced in shogi, and ported to Stockfish after It can be evaluated efficiently on CPUs, and exploits the fact that only parts of the neural network need to be updated after a typical chess move. [The nodchip repository](https://github.com/nodchip/Stockfish) provides additional -tools to train and develop the NNUE networks. +tools to train and develop the NNUE networks. On CPUs supporting modern vector instructions +(avx2 and similar), the NNUE evaluation results in much stronger playing strength, even +if the nodes per second computed by the engine is somewhat lower (roughly 80% of nps +is typical). -On CPUs supporting modern vector instructions (avx2 and similar), the NNUE evaluation -results in stronger playing strength, even if the nodes per second computed by the engine -is somewhat lower (roughly 60% of nps is typical). +Notes: -Note that the NNUE evaluation depends on the Stockfish binary and the network parameter -file (see EvalFile). Not every parameter file is compatible with a given Stockfish binary. -The default value of the EvalFile UCI option is the name of a network that is guaranteed -to be compatible with that binary. +1) the NNUE evaluation depends on the Stockfish binary and the network parameter +file (see the EvalFile UCI option). Not every parameter file is compatible with a given +Stockfish binary, but the default value of the EvalFile UCI option is the name of a network +that is guaranteed to be compatible with that binary. -## What to expect from Syzygybases? +2) to use the NNUE evaluation, the additional data file with neural network parameters +needs to be available. Normally, this file is already embedded in the binary or it +can be downloaded. The filename for the default (recommended) net can be found as the default +value of the `EvalFile` UCI option, with the format `nn-[SHA256 first 12 digits].nnue` +(for instance, `nn-c157e0a5755b.nnue`). This file can be downloaded from +``` +https://tests.stockfishchess.org/api/nn/[filename] +``` +replacing `[filename]` as needed. + +## What to expect from the Syzygy tablebases? If the engine is searching a position that is not in the tablebases (e.g. a position with 8 pieces), it will access the tablebases during the search. @@ -187,9 +189,9 @@ will not report a mate score, even if the position is known to be won.** It is therefore clear that this behaviour is not identical to what one might be used to with Nalimov tablebases. There are technical reasons for this difference, the main technical reason being that Nalimov tablebases use the -DTM metric (distance-to-mate), while Syzygybases use a variation of the +DTM metric (distance-to-mate), while the Syzygy tablebases use a variation of the DTZ metric (distance-to-zero, zero meaning any move that resets the 50-move -counter). This special metric is one of the reasons that Syzygybases are +counter). This special metric is one of the reasons that the Syzygy tablebases are more compact than Nalimov tablebases, while still storing all information needed for optimal play and in addition being able to take into account the 50-move rule. @@ -272,8 +274,9 @@ generic rather than being focused on Stockfish's precise implementation. Nevertheless, a helpful resource. * The latest source can always be found on [GitHub](https://github.com/official-stockfish/Stockfish). -Discussions about Stockfish take place in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking) -group and engine testing is done on [Fishtest](https://tests.stockfishchess.org/tests). +Discussions about Stockfish take place these days mainly in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking) +group and on the [Stockfish Discord channel](https://discord.gg/nv8gDtt). +The engine testing is done on [Fishtest](https://tests.stockfishchess.org/tests). If you want to help improve Stockfish, please read this [guideline](https://github.com/glinscott/fishtest/wiki/Creating-my-first-test) first, where the basics of Stockfish development are explained. @@ -288,9 +291,10 @@ it (either by itself or as part of some bigger software package), or using it as the starting point for a software project of your own. The only real limitation is that whenever you distribute Stockfish in -some way, you must always include the full source code, or a pointer -to where the source code can be found. If you make any changes to the -source code, these changes must also be made available under the GPL. +some way, you MUST always include the full source code, or a pointer +to where the source code can be found, to generate the exact binary +you are distributing. If you make any changes to the source code, +these changes must also be made available under the GPL. For full details, read the copy of the GPL v3 found in the file named *Copying.txt*. From 3597f1942ec6f2cfbd50b905683739b0900ff5dd Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 15 Feb 2021 13:58:51 +0100 Subject: [PATCH 59/88] Stockfish 13 Official release version of Stockfish 13 Bench: 3766422 ----- It is our pleasure to release Stockfish 13 to chess fans worldwide. As usual, downloads are freely available at https://stockfishchess.org The Stockfish project builds on a thriving community of enthusiasts who contribute their expertise, time, and resources to build a free and open-source chess engine that is robust, widely available, and very strong. We would like to thank them all! The good news first: from now on, our users can expect more frequent high-quality releases of Stockfish! Sadly, this decision has been triggered by the start of sales of the Fat Fritz 2 engine by ChessBase, which is a copy of a very recent development version of Stockfish with minor modifications. We refer to our statement on Fat Fritz 2[1] and a community blog[2] for further information. This version of Stockfish is significantly stronger than any of its predecessors. Stockfish 13 outperforms Stockfish 12 by at least 35 Elo[3]. When playing against a one-year-old Stockfish, it wins 60 times more game pairs than it loses[4]. This release features an NNUE network retrained on billions of positions, much faster network evaluation code, and significantly improved search heuristics, as well as additional evaluation tweaks. In the course of its development, this version has won the superfinals of the TCEC Season 19 and TCEC Season 20. Going forward, the Leela Chess Zero and Stockfish teams will join forces to demonstrate our commitment to open source chess engines and training tools, and open data. We are convinced that our free and open-source chess engines serve the chess community very well. Stay safe and enjoy chess! The Stockfish team [1] https://blog.stockfishchess.org/post/643239805544792064/statement-on-fat-fritz-2 [2] https://lichess.org/blog/YCvy7xMAACIA8007/fat-fritz-2-is-a-rip-off [3] https://tests.stockfishchess.org/tests/view/602bcccf7f517a561bc49b11 [4] https://tests.stockfishchess.org/tests/view/600fbb9c735dd7f0f0352d59 --- src/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 48e20a39..ebc7c028 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -65,7 +65,7 @@ namespace { /// Version number. If Version is left empty, then compile date in the format /// DD-MM-YY and show in engine_info. -const string Version = ""; +const string Version = "13"; /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We From a31007c9e7005d2ab4ee3f5aa479eb50cecd63e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sat, 20 Feb 2021 22:19:14 +0100 Subject: [PATCH 60/88] Restore development version No functional change --- src/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index ebc7c028..48e20a39 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -65,7 +65,7 @@ namespace { /// Version number. If Version is left empty, then compile date in the format /// DD-MM-YY and show in engine_info. -const string Version = "13"; +const string Version = ""; /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We From 6294db7514798ac12536b4d6e77bc591f7e846da Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 19 Feb 2021 10:32:12 +0300 Subject: [PATCH 61/88] Tune search parameters (with Unai Corzo) The values used in this patch are taken from a SPSA parameter tuning session originated by Unai Corzo (@unaiic), but the final difference of his tune was multiplied x2 by hand. Most of the credits should go to him :-) STC: https://tests.stockfishchess.org/tests/view/602f03d07f517a561bc49d40 LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 67664 W: 6252 L: 6035 D: 55377 Ptnml(0-2): 256, 4799, 23527, 4972, 278 LTC: https://tests.stockfishchess.org/tests/view/602f41697f517a561bc49d5a LLR: 2.96 (-2.94,2.94) {0.25,1.25} Total: 26256 W: 1034 L: 906 D: 24316 Ptnml(0-2): 10, 804, 11377, 922, 15 Closes https://github.com/official-stockfish/Stockfish/pull/3363 Bench: 3957653 --- src/search.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b5d21b9d..8f01f785 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -839,7 +839,7 @@ namespace { // Step 8. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 22661 + && (ss-1)->statScore < 24185 && eval >= beta && eval >= ss->staticEval && ss->staticEval >= beta - 24 * depth - 34 * improving + 162 * ss->ttPv + 159 @@ -1075,7 +1075,7 @@ moves_loop: // When in check, search starts from here && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - + (*contHist[5])[movedPiece][to_sq(move)] / 3 < 26237) + + (*contHist[5])[movedPiece][to_sq(move)] / 3 < 28255) continue; // Prune moves with negative SEE (~20 Elo) @@ -1167,7 +1167,7 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || (!PvNode && !formerPv && captureHistory[movedPiece][to_sq(move)][type_of(pos.captured_piece())] < 4506) + || (!PvNode && !formerPv && captureHistory[movedPiece][to_sq(move)][type_of(pos.captured_piece())] < 3678) || thisThread->ttHitAverage < 432 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); @@ -1232,7 +1232,7 @@ moves_loop: // When in check, search starts from here + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - - 5337; + - 4741; // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) if (ss->statScore >= -89 && (ss-1)->statScore < -116) @@ -1246,9 +1246,9 @@ moves_loop: // When in check, search starts from here // use sum of main history and first continuation history with an offset if (ss->inCheck) r -= (thisThread->mainHistory[us][from_to(move)] - + (*contHist[0])[movedPiece][to_sq(move)] - 4341) / 16384; + + (*contHist[0])[movedPiece][to_sq(move)] - 3833) / 16384; else - r -= ss->statScore / 14382; + r -= ss->statScore / 14790; } Depth d = std::clamp(newDepth - r, 1, newDepth); From 7c30091a92abddb8265e53768b32751c49642040 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 20 Feb 2021 22:48:08 +0100 Subject: [PATCH 62/88] Introduce ProbCut for check evasions The idea of this patch can be described as follows: if we are in check and the transposition table move is a capture that returns a value far above beta, we can assume that the opponent just blundered a piece by giving check, and we return the transposition table value. This is similar to the usual probCut logic for quiet moves, but with a different threshold. Passed STC LLR: 2.94 (-2.94,2.94) {-0.25,1.25} Total: 33440 W: 3056 L: 2891 D: 27493 Ptnml(0-2): 110, 2338, 11672, 2477, 123 https://tests.stockfishchess.org/tests/view/602cd1087f517a561bc49bda Passed LTC LLR: 2.98 (-2.94,2.94) {0.25,1.25} Total: 10072 W: 401 L: 309 D: 9362 Ptnml(0-2): 2, 288, 4365, 378, 3 https://tests.stockfishchess.org/tests/view/602ceea57f517a561bc49bf0 The committed version has an additional fix to never return unproven wins in the tablebase range or the mate range. This fix passed tests for non- regression at STC and LTC: STC: LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 26240 W: 2354 L: 2280 D: 21606 Ptnml(0-2): 85, 1763, 9372, 1793, 107 https://tests.stockfishchess.org/tests/view/602d86a87f517a561bc49c7a LTC: LLR: 2.95 (-2.94,2.94) {-0.75,0.25} Total: 35304 W: 1299 L: 1256 D: 32749 Ptnml(0-2): 14, 1095, 15395, 1130, 18 https://tests.stockfishchess.org/tests/view/602d98d17f517a561bc49c83 Closes https://github.com/official-stockfish/Stockfish/pull/3362 Bench: 3830215 --- src/search.cpp | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 8f01f785..c33bc914 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -969,6 +969,23 @@ namespace { moves_loop: // When in check, search starts from here + ttCapture = ttMove && pos.capture_or_promotion(ttMove); + + // Step 11. A small Probcut idea, when we are in check + probCutBeta = beta + 400; + if ( ss->inCheck + && !PvNode + && depth >= 4 + && ttCapture + && (tte->bound() & BOUND_LOWER) + && tte->depth() >= depth - 3 + && ttValue >= probCutBeta + && abs(ttValue) <= VALUE_KNOWN_WIN + && abs(beta) <= VALUE_KNOWN_WIN + ) + return probCutBeta; + + const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, nullptr , (ss-4)->continuationHistory, nullptr , (ss-6)->continuationHistory }; @@ -985,12 +1002,11 @@ moves_loop: // When in check, search starts from here value = bestValue; singularQuietLMR = moveCountPruning = false; - ttCapture = ttMove && pos.capture_or_promotion(ttMove); // Mark this node as being searched ThreadHolding th(thisThread, posKey, ss->ply); - // Step 11. Loop through all pseudo-legal moves until no moves remain + // Step 12. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. while ((move = mp.next_move(moveCountPruning)) != MOVE_NONE) { @@ -1036,7 +1052,7 @@ moves_loop: // When in check, search starts from here // Calculate new depth for this move newDepth = depth - 1; - // Step 12. Pruning at shallow depth (~200 Elo) + // Step 13. Pruning at shallow depth (~200 Elo) if ( !rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) @@ -1084,7 +1100,7 @@ moves_loop: // When in check, search starts from here } } - // Step 13. Extensions (~75 Elo) + // Step 14. Extensions (~75 Elo) // Singular extension search (~70 Elo). If all moves but one fail low on a // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), @@ -1156,10 +1172,10 @@ moves_loop: // When in check, search starts from here [movedPiece] [to_sq(move)]; - // Step 14. Make the move + // Step 15. Make the move pos.do_move(move, st, givesCheck); - // Step 15. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be + // Step 16. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be // re-searched at full depth. if ( depth >= 3 && moveCount > 1 + 2 * rootNode @@ -1266,7 +1282,7 @@ moves_loop: // When in check, search starts from here didLMR = false; } - // Step 16. Full depth search when LMR is skipped or fails high + // Step 17. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) { value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); @@ -1293,12 +1309,12 @@ moves_loop: // When in check, search starts from here std::min(maxNextDepth, newDepth), false); } - // Step 17. Undo move + // Step 18. Undo move pos.undo_move(move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); - // Step 18. Check for a new best move + // Step 19. Check for a new best move // Finished searching the move. If a stop occurred, the return value of // the search cannot be trusted, and we return immediately without // updating best move, PV and TT. @@ -1375,7 +1391,7 @@ moves_loop: // When in check, search starts from here return VALUE_DRAW; */ - // Step 19. Check for mate and stalemate + // Step 20. Check for mate and stalemate // All legal moves have been searched and if there are no legal moves, it // must be a mate or a stalemate. If we are in a singular extension search then // return a fail low score. From 0f3f5d85fb5c9f75199f27fbf7a725ff3e8bb4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Fri, 26 Feb 2021 10:13:37 +0100 Subject: [PATCH 63/88] Introduce DistanceFromPV We introduce a metric for each internal node in search, called DistanceFromPV. This distance indicated how far the current node is from the principal variation. We then use this distance to search the nodes which are close to the PV a little deeper (up to 4 plies deeper than the PV): this improves the quality of the search at these nodes and bring better updates for the PV during search. STC: LLR: 2.96 (-2.94,2.94) {-0.25,1.25} Total: 54936 W: 5047 L: 4850 D: 45039 Ptnml(0-2): 183, 3907, 19075, 4136, 167 https://tests.stockfishchess.org/tests/view/6037b88e7f517a561bc4a392 LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.25} Total: 49608 W: 1880 L: 1703 D: 46025 Ptnml(0-2): 22, 1514, 21555, 1691, 22 https://tests.stockfishchess.org/tests/view/6038271b7f517a561bc4a3cb Closes https://github.com/official-stockfish/Stockfish/pull/3369 Bench: 5037279 --- src/search.cpp | 23 +++++++++++++++-------- src/search.h | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c33bc914..b3bd2f03 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -616,6 +616,7 @@ namespace { moveCount = captureCount = quietCount = ss->moveCount = 0; bestValue = -VALUE_INFINITE; maxValue = VALUE_INFINITE; + ss->distanceFromPv = (PvNode ? 0 : ss->distanceFromPv); // Check for the available remaining time if (thisThread == Threads.main()) @@ -1175,8 +1176,12 @@ moves_loop: // When in check, search starts from here // Step 15. Make the move pos.do_move(move, st, givesCheck); - // Step 16. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be - // re-searched at full depth. + (ss+1)->distanceFromPv = ss->distanceFromPv + moveCount - 1; + + // Step 16. Late moves reduction / extension (LMR, ~200 Elo) + // We use various heuristics for the sons of a node after the first son has + // been searched. In general we would like to reduce them, but there are many + // cases where we extend a son if it has good chances to be "interesting". if ( depth >= 3 && moveCount > 1 + 2 * rootNode && ( !captureOrPromotion @@ -1258,8 +1263,8 @@ moves_loop: // When in check, search starts from here r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - // If we are not in check use statScore, if we are in check - // use sum of main history and first continuation history with an offset + // If we are not in check use statScore, but if we are in check we use + // the sum of main history and first continuation history with an offset. if (ss->inCheck) r -= (thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] - 3833) / 16384; @@ -1267,18 +1272,20 @@ moves_loop: // When in check, search starts from here r -= ss->statScore / 14790; } - Depth d = std::clamp(newDepth - r, 1, newDepth); + // In general we want to cap the LMR depth search at newDepth. But for nodes + // close to the principal variation the cap is at (newDepth + 1), which will + // allow these nodes to be searched deeper than the pv (up to 4 plies deeper). + Depth d = std::clamp(newDepth - r, 1, newDepth + ((ss+1)->distanceFromPv <= 4)); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - doFullDepthSearch = value > alpha && d != newDepth; - + // If the son is reduced and fails high it will be re-searched at full depth + doFullDepthSearch = value > alpha && d < newDepth; didLMR = true; } else { doFullDepthSearch = !PvNode || moveCount > 1; - didLMR = false; } diff --git a/src/search.h b/src/search.h index 3bf3e9ae..5e51c18e 100644 --- a/src/search.h +++ b/src/search.h @@ -47,6 +47,7 @@ struct Stack { Value staticEval; int statScore; int moveCount; + int distanceFromPv; bool inCheck; bool ttPv; bool ttHit; From 9b1274aba3cad440b925283fe7407954743ade78 Mon Sep 17 00:00:00 2001 From: Antoine Champion Date: Sat, 30 Jan 2021 09:50:04 +0100 Subject: [PATCH 64/88] Clean functions returning by const values The codebase contains multiple functions returning by const-value. This patch is a small cleanup making those function returns by value instead, removing the const specifier. closes https://github.com/official-stockfish/Stockfish/pull/3328 No functional change --- AUTHORS | 1 + src/bitboard.cpp | 2 +- src/bitboard.h | 2 +- src/misc.cpp | 4 ++-- src/misc.h | 4 ++-- src/position.cpp | 2 +- src/position.h | 2 +- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index 5f21c048..3ef7d1b1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,6 +24,7 @@ Ali AlZhrani (Cooffe) Andrew Grant (AndyGrant) Andrey Neporada (nepal) Andy Duplain +Antoine Champion (antoinechampion) Aram Tumanian (atumanian) Arjun Temurnikar Auguste Pop diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 841aa0b6..8146ce97 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -55,7 +55,7 @@ inline Bitboard safe_destination(Square s, int step) { /// Bitboards::pretty() returns an ASCII representation of a bitboard suitable /// to be printed to standard output. Useful for debugging. -const std::string Bitboards::pretty(Bitboard b) { +std::string Bitboards::pretty(Bitboard b) { std::string s = "+---+---+---+---+---+---+---+---+\n"; diff --git a/src/bitboard.h b/src/bitboard.h index 95591fc4..c9555b6b 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -33,7 +33,7 @@ bool probe(Square wksq, Square wpsq, Square bksq, Color us); namespace Bitboards { void init(); -const std::string pretty(Bitboard b); +std::string pretty(Bitboard b); } diff --git a/src/misc.cpp b/src/misc.cpp index 48e20a39..fe920140 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -138,7 +138,7 @@ public: /// the program was compiled) or "Stockfish ", depending on whether /// Version is empty. -const string engine_info(bool to_uci) { +string engine_info(bool to_uci) { const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); string month, day, year; @@ -161,7 +161,7 @@ const string engine_info(bool to_uci) { /// compiler_info() returns a string trying to describe the compiler we use -const std::string compiler_info() { +std::string compiler_info() { #define stringify2(x) #x #define stringify(x) stringify2(x) diff --git a/src/misc.h b/src/misc.h index 7b551ade..7eb75bc7 100644 --- a/src/misc.h +++ b/src/misc.h @@ -28,8 +28,8 @@ #include "types.h" -const std::string engine_info(bool to_uci = false); -const std::string compiler_info(); +std::string engine_info(bool to_uci = false); +std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); void* std_aligned_alloc(size_t alignment, size_t size); diff --git a/src/position.cpp b/src/position.cpp index 2eb30ca0..8f9b7eee 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -408,7 +408,7 @@ Position& Position::set(const string& code, Color c, StateInfo* si) { /// Position::fen() returns a FEN representation of the position. In case of /// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function. -const string Position::fen() const { +string Position::fen() const { int emptyCnt; std::ostringstream ss; diff --git a/src/position.h b/src/position.h index 3624e29e..e9803756 100644 --- a/src/position.h +++ b/src/position.h @@ -87,7 +87,7 @@ public: // FEN string input/output Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th); Position& set(const std::string& code, Color c, StateInfo* si); - const std::string fen() const; + std::string fen() const; // Position representation Bitboard pieces(PieceType pt) const; From 7ffae17f85709e49672a0e98e136b66aea067b2c Mon Sep 17 00:00:00 2001 From: Dieter Dobbelaere Date: Fri, 26 Feb 2021 10:02:13 +0100 Subject: [PATCH 65/88] Add Stockfish namespace. fixes #3350 and is a small cleanup that might make it easier to use SF in separate projects, like a NNUE trainer or similar. closes https://github.com/official-stockfish/Stockfish/pull/3370 No functional change. --- src/benchmark.cpp | 4 ++++ src/bitbase.cpp | 6 ++++-- src/bitboard.cpp | 6 ++++-- src/bitboard.h | 8 ++++++-- src/endgame.cpp | 4 ++++ src/endgame.h | 3 +++ src/evaluate.cpp | 6 +++++- src/evaluate.h | 4 ++++ src/main.cpp | 2 ++ src/material.cpp | 4 ++++ src/material.h | 4 ++-- src/misc.cpp | 4 ++++ src/misc.h | 4 ++++ src/movegen.cpp | 4 ++++ src/movegen.h | 4 ++++ src/movepick.cpp | 4 ++++ src/movepick.h | 4 ++++ src/nnue/architectures/halfkp_256x2-32-32.h | 4 ++-- src/nnue/evaluate_nnue.cpp | 4 ++-- src/nnue/evaluate_nnue.h | 4 ++-- src/nnue/features/feature_set.h | 4 ++-- src/nnue/features/features_common.h | 4 ++-- src/nnue/features/half_kp.cpp | 4 ++-- src/nnue/features/half_kp.h | 4 ++-- src/nnue/features/index_list.h | 4 ++-- src/nnue/layers/affine_transform.h | 4 ++-- src/nnue/layers/clipped_relu.h | 4 ++-- src/nnue/layers/input_slice.h | 4 ++-- src/nnue/nnue_accumulator.h | 4 ++-- src/nnue/nnue_architecture.h | 4 ++-- src/nnue/nnue_common.h | 4 ++-- src/nnue/nnue_feature_transformer.h | 4 ++-- src/pawns.cpp | 4 ++++ src/pawns.h | 4 ++-- src/position.cpp | 4 ++++ src/position.h | 3 +++ src/psqt.cpp | 3 +++ src/psqt.h | 4 ++-- src/search.cpp | 6 +++++- src/search.h | 4 ++++ src/syzygy/tbprobe.cpp | 8 ++++++-- src/syzygy/tbprobe.h | 4 ++-- src/thread.cpp | 4 ++++ src/thread.h | 3 +++ src/thread_win32_osx.h | 8 ++++++++ src/timeman.cpp | 4 ++++ src/timeman.h | 4 ++++ src/tt.cpp | 4 ++++ src/tt.h | 4 ++++ src/tune.cpp | 8 ++++++++ src/tune.h | 4 ++++ src/types.h | 4 ++++ src/uci.cpp | 4 ++++ src/uci.h | 4 ++++ src/ucioption.cpp | 4 ++++ tests/instrumented.sh | 18 +++++++++--------- 56 files changed, 199 insertions(+), 57 deletions(-) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 7cb04382..7945a453 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -92,6 +92,8 @@ const vector Defaults = { } // namespace +namespace Stockfish { + /// setup_bench() builds a list of UCI commands to be run by bench. There /// are five parameters: TT size in MB, number of search threads that /// should be used, the limit value spent for each position, a file name @@ -168,3 +170,5 @@ vector setup_bench(const Position& current, istream& is) { return list; } + +} // namespace Stockfish diff --git a/src/bitbase.cpp b/src/bitbase.cpp index b640eabb..ece9ec72 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -23,6 +23,8 @@ #include "bitboard.h" #include "types.h" +namespace Stockfish { + namespace { // There are 24 possible pawn squares: files A to D and ranks from 2 to 7. @@ -66,7 +68,6 @@ namespace { } // namespace - bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) { assert(file_of(wpsq) <= FILE_D); @@ -96,7 +97,6 @@ void Bitbases::init() { KPKBitbase.set(idx); } - namespace { KPKPosition::KPKPosition(unsigned idx) { @@ -168,3 +168,5 @@ namespace { } } // namespace + +} // namespace Stockfish diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 8146ce97..a2021449 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -22,6 +22,8 @@ #include "bitboard.h" #include "misc.h" +namespace Stockfish { + uint8_t PopCnt16[1 << 16]; uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; @@ -42,7 +44,6 @@ namespace { } - /// safe_destination() returns the bitboard of target square for the given step /// from the given square. If the step is off the board, returns empty bitboard. @@ -111,7 +112,6 @@ void Bitboards::init() { } } - namespace { Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) { @@ -211,3 +211,5 @@ namespace { } } } + +} // namespace Stockfish diff --git a/src/bitboard.h b/src/bitboard.h index c9555b6b..e14fe0df 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -23,19 +23,21 @@ #include "types.h" +namespace Stockfish { + namespace Bitbases { void init(); bool probe(Square wksq, Square wpsq, Square bksq, Color us); -} +} // namespace Stockfish::Bitbases namespace Bitboards { void init(); std::string pretty(Bitboard b); -} +} // namespace Stockfish::Bitboards constexpr Bitboard AllSquares = ~Bitboard(0); constexpr Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL; @@ -430,4 +432,6 @@ inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); } +} // namespace Stockfish + #endif // #ifndef BITBOARD_H_INCLUDED diff --git a/src/endgame.cpp b/src/endgame.cpp index 1489a36b..a44d3a1c 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -22,6 +22,8 @@ #include "endgame.h" #include "movegen.h" +namespace Stockfish { + namespace { // Used to drive the king towards the edge of the board @@ -741,3 +743,5 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // it's probably at least a draw even with the pawn. return Bitbases::probe(strongKing, strongPawn, weakKing, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; } + +} // namespace Stockfish diff --git a/src/endgame.h b/src/endgame.h index 860cc863..146111b9 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -28,6 +28,7 @@ #include "position.h" #include "types.h" +namespace Stockfish { /// EndgameCode lists all supported endgame functions by corresponding codes @@ -120,4 +121,6 @@ namespace Endgames { } } +} // namespace Stockfish + #endif // #ifndef ENDGAME_H_INCLUDED diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d55ef695..d43b8fa7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -54,7 +54,9 @@ using namespace std; -using namespace Eval::NNUE; +using namespace Stockfish::Eval::NNUE; + +namespace Stockfish { namespace Eval { @@ -1146,3 +1148,5 @@ std::string Eval::trace(const Position& pos) { return ss.str(); } + +} // namespace Stockfish diff --git a/src/evaluate.h b/src/evaluate.h index 8beca2d0..6210bd58 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -23,6 +23,8 @@ #include "types.h" +namespace Stockfish { + class Position; namespace Eval { @@ -49,4 +51,6 @@ namespace Eval { } // namespace Eval +} // namespace Stockfish + #endif // #ifndef EVALUATE_H_INCLUDED diff --git a/src/main.cpp b/src/main.cpp index ef662468..62e0ed52 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,8 @@ #include "tt.h" #include "uci.h" +using namespace Stockfish; + int main(int argc, char* argv[]) { std::cout << engine_info() << std::endl; diff --git a/src/material.cpp b/src/material.cpp index e76641d1..84d7a4bd 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -24,6 +24,8 @@ using namespace std; +namespace Stockfish { + namespace { #define S(mg, eg) make_score(mg, eg) @@ -223,3 +225,5 @@ Entry* probe(const Position& pos) { } } // namespace Material + +} // namespace Stockfish diff --git a/src/material.h b/src/material.h index be26425f..26535a53 100644 --- a/src/material.h +++ b/src/material.h @@ -24,7 +24,7 @@ #include "position.h" #include "types.h" -namespace Material { +namespace Stockfish::Material { /// Material::Entry contains various information about a material configuration. /// It contains a material imbalance evaluation, a function pointer to a special @@ -66,6 +66,6 @@ typedef HashTable Table; Entry* probe(const Position& pos); -} // namespace Material +} // namespace Stockfish::Material #endif // #ifndef MATERIAL_H_INCLUDED diff --git a/src/misc.cpp b/src/misc.cpp index fe920140..834e909b 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -61,6 +61,8 @@ typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); using namespace std; +namespace Stockfish { + namespace { /// Version number. If Version is left empty, then compile date in the format @@ -626,3 +628,5 @@ void init(int argc, char* argv[]) { } // namespace CommandLine + +} // namespace Stockfish diff --git a/src/misc.h b/src/misc.h index 7eb75bc7..f834e470 100644 --- a/src/misc.h +++ b/src/misc.h @@ -28,6 +28,8 @@ #include "types.h" +namespace Stockfish { + std::string engine_info(bool to_uci = false); std::string compiler_info(); void prefetch(void* addr); @@ -143,4 +145,6 @@ namespace CommandLine { extern std::string workingDirectory; // path of the working directory } +} // namespace Stockfish + #endif // #ifndef MISC_H_INCLUDED diff --git a/src/movegen.cpp b/src/movegen.cpp index c9d6a90d..51df6d07 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -21,6 +21,8 @@ #include "movegen.h" #include "position.h" +namespace Stockfish { + namespace { template @@ -362,3 +364,5 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { return moveList; } + +} // namespace Stockfish diff --git a/src/movegen.h b/src/movegen.h index 85887a64..3f895f05 100644 --- a/src/movegen.h +++ b/src/movegen.h @@ -23,6 +23,8 @@ #include "types.h" +namespace Stockfish { + class Position; enum GenType { @@ -70,4 +72,6 @@ private: ExtMove moveList[MAX_MOVES], *last; }; +} // namespace Stockfish + #endif // #ifndef MOVEGEN_H_INCLUDED diff --git a/src/movepick.cpp b/src/movepick.cpp index 0ceeb8ea..4ff4cff4 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -20,6 +20,8 @@ #include "movepick.h" +namespace Stockfish { + namespace { enum Stages { @@ -263,3 +265,5 @@ top: assert(false); return MOVE_NONE; // Silence warning } + +} // namespace Stockfish diff --git a/src/movepick.h b/src/movepick.h index ea599cda..c76d4957 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -27,6 +27,8 @@ #include "position.h" #include "types.h" +namespace Stockfish { + /// StatsEntry stores the stat table value. It is usually a number but could /// be a move or even a nested history. We use a class instead of naked value /// to directly call history update operator<<() on the entry so to use stats @@ -156,4 +158,6 @@ private: ExtMove moves[MAX_MOVES]; }; +} // namespace Stockfish + #endif // #ifndef MOVEPICK_H_INCLUDED diff --git a/src/nnue/architectures/halfkp_256x2-32-32.h b/src/nnue/architectures/halfkp_256x2-32-32.h index a0fe2e0a..a6768204 100644 --- a/src/nnue/architectures/halfkp_256x2-32-32.h +++ b/src/nnue/architectures/halfkp_256x2-32-32.h @@ -28,7 +28,7 @@ #include "../layers/affine_transform.h" #include "../layers/clipped_relu.h" -namespace Eval::NNUE { +namespace Stockfish::Eval::NNUE { // Input features used in evaluation function using RawFeatures = Features::FeatureSet< @@ -49,6 +49,6 @@ using OutputLayer = AffineTransform; using Network = Layers::OutputLayer; -} // namespace Eval::NNUE +} // namespace Stockfish::Eval::NNUE #endif // #ifndef NNUE_HALFKP_256X2_32_32_H_INCLUDED diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index fb4a5021..5416f13e 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -29,7 +29,7 @@ #include "evaluate_nnue.h" -namespace Eval::NNUE { +namespace Stockfish::Eval::NNUE { // Input feature converter LargePagePtr feature_transformer; @@ -141,4 +141,4 @@ namespace Eval::NNUE { return ReadParameters(stream); } -} // namespace Eval::NNUE +} // namespace Stockfish::Eval::NNUE diff --git a/src/nnue/evaluate_nnue.h b/src/nnue/evaluate_nnue.h index c30d7c01..24aa6cc0 100644 --- a/src/nnue/evaluate_nnue.h +++ b/src/nnue/evaluate_nnue.h @@ -25,7 +25,7 @@ #include -namespace Eval::NNUE { +namespace Stockfish::Eval::NNUE { // Hash value of evaluation function structure constexpr std::uint32_t kHashValue = @@ -54,6 +54,6 @@ namespace Eval::NNUE { template using LargePagePtr = std::unique_ptr>; -} // namespace Eval::NNUE +} // namespace Stockfish::Eval::NNUE #endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED diff --git a/src/nnue/features/feature_set.h b/src/nnue/features/feature_set.h index 77d2220f..a3fea9c0 100644 --- a/src/nnue/features/feature_set.h +++ b/src/nnue/features/feature_set.h @@ -24,7 +24,7 @@ #include "features_common.h" #include -namespace Eval::NNUE::Features { +namespace Stockfish::Eval::NNUE::Features { // Class template that represents a list of values template @@ -64,6 +64,6 @@ namespace Eval::NNUE::Features { }; -} // namespace Eval::NNUE::Features +} // namespace Stockfish::Eval::NNUE::Features #endif // #ifndef NNUE_FEATURE_SET_H_INCLUDED diff --git a/src/nnue/features/features_common.h b/src/nnue/features/features_common.h index b0073b8b..118ec953 100644 --- a/src/nnue/features/features_common.h +++ b/src/nnue/features/features_common.h @@ -24,7 +24,7 @@ #include "../../evaluate.h" #include "../nnue_common.h" -namespace Eval::NNUE::Features { +namespace Stockfish::Eval::NNUE::Features { class IndexList; @@ -40,6 +40,6 @@ namespace Eval::NNUE::Features { kFriend // side to move }; -} // namespace Eval::NNUE::Features +} // namespace Stockfish::Eval::NNUE::Features #endif // #ifndef NNUE_FEATURES_COMMON_H_INCLUDED diff --git a/src/nnue/features/half_kp.cpp b/src/nnue/features/half_kp.cpp index b52a45f2..ac6317e7 100644 --- a/src/nnue/features/half_kp.cpp +++ b/src/nnue/features/half_kp.cpp @@ -21,7 +21,7 @@ #include "half_kp.h" #include "index_list.h" -namespace Eval::NNUE::Features { +namespace Stockfish::Eval::NNUE::Features { // Orient a square according to perspective (rotates by 180 for black) inline Square orient(Color perspective, Square s) { @@ -65,4 +65,4 @@ namespace Eval::NNUE::Features { template class HalfKP; -} // namespace Eval::NNUE::Features +} // namespace Stockfish::Eval::NNUE::Features diff --git a/src/nnue/features/half_kp.h b/src/nnue/features/half_kp.h index d203dc22..2461acb7 100644 --- a/src/nnue/features/half_kp.h +++ b/src/nnue/features/half_kp.h @@ -24,7 +24,7 @@ #include "../../evaluate.h" #include "features_common.h" -namespace Eval::NNUE::Features { +namespace Stockfish::Eval::NNUE::Features { // Feature HalfKP: Combination of the position of own king // and the position of pieces other than kings @@ -54,6 +54,6 @@ namespace Eval::NNUE::Features { IndexList* removed, IndexList* added); }; -} // namespace Eval::NNUE::Features +} // namespace Stockfish::Eval::NNUE::Features #endif // #ifndef NNUE_FEATURES_HALF_KP_H_INCLUDED diff --git a/src/nnue/features/index_list.h b/src/nnue/features/index_list.h index ca3ebee5..9f03993b 100644 --- a/src/nnue/features/index_list.h +++ b/src/nnue/features/index_list.h @@ -24,7 +24,7 @@ #include "../../position.h" #include "../nnue_architecture.h" -namespace Eval::NNUE::Features { +namespace Stockfish::Eval::NNUE::Features { // Class template used for feature index list template @@ -59,6 +59,6 @@ namespace Eval::NNUE::Features { : public ValueList { }; -} // namespace Eval::NNUE::Features +} // namespace Stockfish::Eval::NNUE::Features #endif // NNUE_FEATURES_INDEX_LIST_H_INCLUDED diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index adf152ee..d2713c5a 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -24,7 +24,7 @@ #include #include "../nnue_common.h" -namespace Eval::NNUE::Layers { +namespace Stockfish::Eval::NNUE::Layers { // Affine transformation layer template @@ -459,6 +459,6 @@ namespace Eval::NNUE::Layers { #endif }; -} // namespace Eval::NNUE::Layers +} // namespace Stockfish::Eval::NNUE::Layers #endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED diff --git a/src/nnue/layers/clipped_relu.h b/src/nnue/layers/clipped_relu.h index 3ed41ee5..a10e3e48 100644 --- a/src/nnue/layers/clipped_relu.h +++ b/src/nnue/layers/clipped_relu.h @@ -23,7 +23,7 @@ #include "../nnue_common.h" -namespace Eval::NNUE::Layers { +namespace Stockfish::Eval::NNUE::Layers { // Clipped ReLU template @@ -161,6 +161,6 @@ namespace Eval::NNUE::Layers { PreviousLayer previous_layer_; }; -} // namespace Eval::NNUE::Layers +} // namespace Stockfish::Eval::NNUE::Layers #endif // NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED diff --git a/src/nnue/layers/input_slice.h b/src/nnue/layers/input_slice.h index efdf0725..43b06eec 100644 --- a/src/nnue/layers/input_slice.h +++ b/src/nnue/layers/input_slice.h @@ -23,7 +23,7 @@ #include "../nnue_common.h" -namespace Eval::NNUE::Layers { +namespace Stockfish::Eval::NNUE::Layers { // Input layer template @@ -63,6 +63,6 @@ class InputSlice { private: }; -} // namespace Layers +} // namespace Stockfish::Eval::NNUE::Layers #endif // #ifndef NNUE_LAYERS_INPUT_SLICE_H_INCLUDED diff --git a/src/nnue/nnue_accumulator.h b/src/nnue/nnue_accumulator.h index 6b4390f9..55fafa13 100644 --- a/src/nnue/nnue_accumulator.h +++ b/src/nnue/nnue_accumulator.h @@ -23,7 +23,7 @@ #include "nnue_architecture.h" -namespace Eval::NNUE { +namespace Stockfish::Eval::NNUE { // The accumulator of a StateInfo without parent is set to the INIT state enum AccumulatorState { EMPTY, COMPUTED, INIT }; @@ -35,6 +35,6 @@ namespace Eval::NNUE { AccumulatorState state[2]; }; -} // namespace Eval::NNUE +} // namespace Stockfish::Eval::NNUE #endif // NNUE_ACCUMULATOR_H_INCLUDED diff --git a/src/nnue/nnue_architecture.h b/src/nnue/nnue_architecture.h index ad5be006..1680368e 100644 --- a/src/nnue/nnue_architecture.h +++ b/src/nnue/nnue_architecture.h @@ -24,7 +24,7 @@ // Defines the network structure #include "architectures/halfkp_256x2-32-32.h" -namespace Eval::NNUE { +namespace Stockfish::Eval::NNUE { static_assert(kTransformedFeatureDimensions % kMaxSimdWidth == 0, ""); static_assert(Network::kOutputDimensions == 1, ""); @@ -33,6 +33,6 @@ namespace Eval::NNUE { // Trigger for full calculation instead of difference calculation constexpr auto kRefreshTriggers = RawFeatures::kRefreshTriggers; -} // namespace Eval::NNUE +} // namespace Stockfish::Eval::NNUE #endif // #ifndef NNUE_ARCHITECTURE_H_INCLUDED diff --git a/src/nnue/nnue_common.h b/src/nnue/nnue_common.h index 33e58745..09a152a5 100644 --- a/src/nnue/nnue_common.h +++ b/src/nnue/nnue_common.h @@ -43,7 +43,7 @@ #include #endif -namespace Eval::NNUE { +namespace Stockfish::Eval::NNUE { // Version of the evaluation file constexpr std::uint32_t kVersion = 0x7AF32F16u; @@ -127,6 +127,6 @@ namespace Eval::NNUE { return result; } -} // namespace Eval::NNUE +} // namespace Stockfish::Eval::NNUE #endif // #ifndef NNUE_COMMON_H_INCLUDED diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index 2641321e..1e0b0e6d 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -27,7 +27,7 @@ #include // std::memset() -namespace Eval::NNUE { +namespace Stockfish::Eval::NNUE { // If vector instructions are enabled, we update and refresh the // accumulator tile by tile such that each tile fits in the CPU's @@ -412,6 +412,6 @@ namespace Eval::NNUE { WeightType weights_[kHalfDimensions * kInputDimensions]; }; -} // namespace Eval::NNUE +} // namespace Stockfish::Eval::NNUE #endif // #ifndef NNUE_FEATURE_TRANSFORMER_H_INCLUDED diff --git a/src/pawns.cpp b/src/pawns.cpp index cd4d4e45..9a0610a0 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -24,6 +24,8 @@ #include "position.h" #include "thread.h" +namespace Stockfish { + namespace { #define V Value @@ -298,3 +300,5 @@ template Score Entry::do_king_safety(const Position& pos); template Score Entry::do_king_safety(const Position& pos); } // namespace Pawns + +} // namespace Stockfish diff --git a/src/pawns.h b/src/pawns.h index 888bf990..124619d6 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -23,7 +23,7 @@ #include "position.h" #include "types.h" -namespace Pawns { +namespace Stockfish::Pawns { /// Pawns::Entry contains various information about a pawn structure. A lookup /// to the pawn hash table (performed by calling the probe function) returns a @@ -65,6 +65,6 @@ typedef HashTable Table; Entry* probe(const Position& pos); -} // namespace Pawns +} // namespace Stockfish::Pawns #endif // #ifndef PAWNS_H_INCLUDED diff --git a/src/position.cpp b/src/position.cpp index 8f9b7eee..17b165b9 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -34,6 +34,8 @@ using std::string; +namespace Stockfish { + namespace Zobrist { Key psq[PIECE_NB][SQUARE_NB]; @@ -1338,3 +1340,5 @@ bool Position::pos_is_ok() const { return true; } + +} // namespace Stockfish diff --git a/src/position.h b/src/position.h index e9803756..4ab3761f 100644 --- a/src/position.h +++ b/src/position.h @@ -31,6 +31,7 @@ #include "nnue/nnue_accumulator.h" +namespace Stockfish { /// StateInfo struct stores information needed to restore a Position object to /// its previous state when we retract a move. Whenever a move is made on the @@ -423,4 +424,6 @@ inline StateInfo* Position::state() const { return st; } +} // namespace Stockfish + #endif // #ifndef POSITION_H_INCLUDED diff --git a/src/psqt.cpp b/src/psqt.cpp index cfade295..33a3e00c 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -24,6 +24,7 @@ #include "bitboard.h" #include "types.h" +namespace Stockfish { namespace { @@ -126,3 +127,5 @@ void init() { } } // namespace PSQT + +} // namespace Stockfish diff --git a/src/psqt.h b/src/psqt.h index 8b4fd6eb..7abb1483 100644 --- a/src/psqt.h +++ b/src/psqt.h @@ -24,7 +24,7 @@ #include "types.h" -namespace PSQT +namespace Stockfish::PSQT { extern Score psq[PIECE_NB][SQUARE_NB]; @@ -32,7 +32,7 @@ extern Score psq[PIECE_NB][SQUARE_NB]; // Fill psqt array from a set of internally linked parameters extern void init(); -} // namespace PSQT +} // namespace Stockfish::PSQT #endif // PSQT_H_INCLUDED diff --git a/src/search.cpp b/src/search.cpp index b3bd2f03..4e2ec095 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -35,6 +35,8 @@ #include "uci.h" #include "syzygy/tbprobe.h" +namespace Stockfish { + namespace Search { LimitsType Limits; @@ -422,7 +424,7 @@ void Thread::search() { while (true) { Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - searchAgainCounter); - bestValue = ::search(rootPos, ss, alpha, beta, adjustedDepth, false); + bestValue = Stockfish::search(rootPos, ss, alpha, beta, adjustedDepth, false); // Bring the best move to the front. It is critical that sorting // is done with a stable algorithm because all the values but the @@ -2034,3 +2036,5 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { m.tbRank = 0; } } + +} // namespace Stockfish diff --git a/src/search.h b/src/search.h index 5e51c18e..6f9fbd05 100644 --- a/src/search.h +++ b/src/search.h @@ -25,6 +25,8 @@ #include "movepick.h" #include "types.h" +namespace Stockfish { + class Position; namespace Search { @@ -107,4 +109,6 @@ void clear(); } // namespace Search +} // namespace Stockfish + #endif // #ifndef SEARCH_H_INCLUDED diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 115815e1..5cfd38e5 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -50,9 +50,11 @@ #include #endif -using namespace Tablebases; +using namespace Stockfish::Tablebases; -int Tablebases::MaxCardinality; +int Stockfish::Tablebases::MaxCardinality; + +namespace Stockfish { namespace { @@ -1610,3 +1612,5 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) { return true; } + +} // namespace Stockfish diff --git a/src/syzygy/tbprobe.h b/src/syzygy/tbprobe.h index cefd39ce..56734af9 100644 --- a/src/syzygy/tbprobe.h +++ b/src/syzygy/tbprobe.h @@ -23,7 +23,7 @@ #include "../search.h" -namespace Tablebases { +namespace Stockfish::Tablebases { enum WDLScore { WDLLoss = -2, // Loss @@ -73,6 +73,6 @@ inline std::ostream& operator<<(std::ostream& os, const ProbeState v) { return os; } -} +} // namespace Stockfish::Tablebases #endif diff --git a/src/thread.cpp b/src/thread.cpp index a12c0bcc..3ef73dfa 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -26,6 +26,8 @@ #include "syzygy/tbprobe.h" #include "tt.h" +namespace Stockfish { + ThreadPool Threads; // Global object @@ -258,3 +260,5 @@ void ThreadPool::wait_for_search_finished() const { if (th != front()) th->wait_for_search_finished(); } + +} // namespace Stockfish diff --git a/src/thread.h b/src/thread.h index 585f2088..2b3dea0d 100644 --- a/src/thread.h +++ b/src/thread.h @@ -32,6 +32,7 @@ #include "search.h" #include "thread_win32_osx.h" +namespace Stockfish { /// Thread class keeps together all the thread-related stuff. We use /// per-thread pawn and material hash tables so that once we get a @@ -128,4 +129,6 @@ private: extern ThreadPool Threads; +} // namespace Stockfish + #endif // #ifndef THREAD_H_INCLUDED diff --git a/src/thread_win32_osx.h b/src/thread_win32_osx.h index a0e4d199..a21674cc 100644 --- a/src/thread_win32_osx.h +++ b/src/thread_win32_osx.h @@ -31,6 +31,8 @@ #include +namespace Stockfish { + static const size_t TH_STACK_SIZE = 8 * 1024 * 1024; template > @@ -57,10 +59,16 @@ public: void join() { pthread_join(thread, NULL); } }; +} // namespace Stockfish + #else // Default case: use STL classes +namespace Stockfish { + typedef std::thread NativeThread; +} // namespace Stockfish + #endif #endif // #ifndef THREAD_WIN32_OSX_H_INCLUDED diff --git a/src/timeman.cpp b/src/timeman.cpp index fc4fbaac..f742d1e4 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -24,6 +24,8 @@ #include "timeman.h" #include "uci.h" +namespace Stockfish { + TimeManagement Time; // Our global time management object @@ -95,3 +97,5 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { if (Options["Ponder"]) optimumTime += optimumTime / 4; } + +} // namespace Stockfish diff --git a/src/timeman.h b/src/timeman.h index 55a68de4..b1878d65 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -23,6 +23,8 @@ #include "search.h" #include "thread.h" +namespace Stockfish { + /// The TimeManagement class computes the optimal time to think depending on /// the maximum available time, the game move number and other parameters. @@ -44,4 +46,6 @@ private: extern TimeManagement Time; +} // namespace Stockfish + #endif // #ifndef TIMEMAN_H_INCLUDED diff --git a/src/tt.cpp b/src/tt.cpp index cb5af5c8..1f495ca9 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -26,6 +26,8 @@ #include "tt.h" #include "uci.h" +namespace Stockfish { + TranspositionTable TT; // Our global transposition table /// TTEntry::save() populates the TTEntry with a new node's data, possibly @@ -156,3 +158,5 @@ int TranspositionTable::hashfull() const { return cnt / ClusterSize; } + +} // namespace Stockfish diff --git a/src/tt.h b/src/tt.h index a750b6c4..d915d92e 100644 --- a/src/tt.h +++ b/src/tt.h @@ -22,6 +22,8 @@ #include "misc.h" #include "types.h" +namespace Stockfish { + /// TTEntry struct is the 10 bytes transposition table entry, defined as below: /// /// key 16 bit @@ -100,4 +102,6 @@ private: extern TranspositionTable TT; +} // namespace Stockfish + #endif // #ifndef TT_H_INCLUDED diff --git a/src/tune.cpp b/src/tune.cpp index 424bdac8..d9618efc 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -26,6 +26,8 @@ using std::string; +namespace Stockfish { + bool Tune::update_on_last; const UCI::Option* LastOption = nullptr; BoolConditions Conditions; @@ -126,6 +128,8 @@ void BoolConditions::set() { sync_cout << binary[i] << sync_endl; } +} // namespace Stockfish + // Init options with tuning session results instead of default values. Useful to // get correct bench signature after a tuning session or to test tuned values. @@ -138,7 +142,11 @@ void BoolConditions::set() { #include +namespace Stockfish { + void Tune::read_results() { /* ...insert your values here... */ } + +} // namespace Stockfish diff --git a/src/tune.h b/src/tune.h index c2cd0c97..c904c09d 100644 --- a/src/tune.h +++ b/src/tune.h @@ -24,6 +24,8 @@ #include #include +namespace Stockfish { + typedef std::pair Range; // Option's min-max values typedef Range (RangeFun) (int); @@ -190,4 +192,6 @@ public: #define TUNE_CONDITIONS() int UNIQUE(c, __LINE__) = (Conditions.init(__COUNTER__), 0); \ TUNE(Conditions, set_conditions) +} // namespace Stockfish + #endif // #ifndef TUNE_H_INCLUDED diff --git a/src/types.h b/src/types.h index d270384e..efebce1a 100644 --- a/src/types.h +++ b/src/types.h @@ -83,6 +83,8 @@ # define pext(b, m) 0 #endif +namespace Stockfish { + #ifdef USE_POPCNT constexpr bool HasPopCnt = true; #else @@ -482,6 +484,8 @@ constexpr Key make_key(uint64_t seed) { return seed * 6364136223846793005ULL + 1442695040888963407ULL; } +} // namespace Stockfish + #endif // #ifndef TYPES_H_INCLUDED #include "tune.h" // Global visibility to tuning setup diff --git a/src/uci.cpp b/src/uci.cpp index b3017e91..47a8824e 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -34,6 +34,8 @@ using namespace std; +namespace Stockfish { + extern vector setup_bench(const Position&, istream&); namespace { @@ -369,3 +371,5 @@ Move UCI::to_move(const Position& pos, string& str) { return MOVE_NONE; } + +} // namespace Stockfish diff --git a/src/uci.h b/src/uci.h index edcfcade..d3160109 100644 --- a/src/uci.h +++ b/src/uci.h @@ -24,6 +24,8 @@ #include "types.h" +namespace Stockfish { + class Position; namespace UCI { @@ -78,4 +80,6 @@ Move to_move(const Position& pos, std::string& str); extern UCI::OptionsMap Options; +} // namespace Stockfish + #endif // #ifndef UCI_H_INCLUDED diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 03f377b3..d59c0100 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -31,6 +31,8 @@ using std::string; +namespace Stockfish { + UCI::OptionsMap Options; // Global object namespace UCI { @@ -190,3 +192,5 @@ Option& Option::operator=(const string& v) { } } // namespace UCI + +} // namespace Stockfish diff --git a/tests/instrumented.sh b/tests/instrumented.sh index 03e9c9de..bfb50e94 100755 --- a/tests/instrumented.sh +++ b/tests/instrumented.sh @@ -39,16 +39,16 @@ case $1 in threads="2" cat << EOF > tsan.supp -race:TTEntry::move -race:TTEntry::depth -race:TTEntry::bound -race:TTEntry::save -race:TTEntry::value -race:TTEntry::eval -race:TTEntry::is_pv +race:Stockfish::TTEntry::move +race:Stockfish::TTEntry::depth +race:Stockfish::TTEntry::bound +race:Stockfish::TTEntry::save +race:Stockfish::TTEntry::value +race:Stockfish::TTEntry::eval +race:Stockfish::TTEntry::is_pv -race:TranspositionTable::probe -race:TranspositionTable::hashfull +race:Stockfish::TranspositionTable::probe +race:Stockfish::TranspositionTable::hashfull EOF From d4b864ff126e4a5784c9d7f636be057c247738f1 Mon Sep 17 00:00:00 2001 From: noobpwnftw Date: Wed, 3 Mar 2021 22:30:23 +0800 Subject: [PATCH 66/88] Do not try to use large pages on 32 bit Windows. verified to work on windows XP. fixes #3379 closes https://github.com/official-stockfish/Stockfish/pull/3380 No functional change. --- src/misc.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 834e909b..7600fc11 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -362,7 +362,7 @@ void std_aligned_free(void* ptr) { /// aligned_large_pages_alloc() will return suitably aligned memory, if possible using large pages. #if defined(_WIN32) - +#if defined(_WIN64) static void* aligned_large_pages_alloc_win(size_t allocSize) { HANDLE hProcessToken { }; @@ -407,15 +407,20 @@ static void* aligned_large_pages_alloc_win(size_t allocSize) { return mem; } +#endif void* aligned_large_pages_alloc(size_t allocSize) { +#if defined(_WIN64) // Try to allocate large pages void* mem = aligned_large_pages_alloc_win(allocSize); // Fall back to regular, page aligned, allocation if necessary if (!mem) mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +#else + void* mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +#endif return mem; } From 5346f1c6c72e46d66bb4c21259f8c06096c63034 Mon Sep 17 00:00:00 2001 From: mattginsberg Date: Sun, 28 Feb 2021 07:59:07 -0800 Subject: [PATCH 67/88] Deal with commented lines in UCI input commands starting with '#' as the first character will be ignored closes https://github.com/official-stockfish/Stockfish/pull/3378 No functional change --- src/uci.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uci.cpp b/src/uci.cpp index 47a8824e..051ff2e0 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -277,7 +277,7 @@ void UCI::loop(int argc, char* argv[]) { else if (token == "d") sync_cout << pos << sync_endl; else if (token == "eval") trace_eval(pos); else if (token == "compiler") sync_cout << compiler_info() << sync_endl; - else + else if (!token.empty() && token[0] != '#') sync_cout << "Unknown command: " << cmd << sync_endl; } while (token != "quit" && argc == 1); // Command line args are one-shot From b74274628c052cc910e36202b88bc5f81724d78c Mon Sep 17 00:00:00 2001 From: bmc4 Date: Fri, 5 Mar 2021 08:57:43 -0300 Subject: [PATCH 68/88] Use Bitboard over Square in movegen It uses pos.checkers() on target when movegen is the type of EVASION. It simplify the code. And it's also expected a slightly speed up, because Bitboard is more direct when doing bitwise. Passed STC: LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 28176 W: 2506 L: 2437 D: 23233 Ptnml(0-2): 80, 1904, 10063, 1949, 92 https://tests.stockfishchess.org/tests/view/60421d18ddcba5f0627bb6a9 Passed LTC: LLR: 2.93 (-2.94,2.94) {-0.75,0.25} Total: 9704 W: 402 L: 341 D: 8961 Ptnml(0-2): 3, 279, 4230, 334, 6 https://tests.stockfishchess.org/tests/view/60422823ddcba5f0627bb6ae closes https://github.com/official-stockfish/Stockfish/pull/3383 No functional change --- src/movegen.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 51df6d07..c5d76afa 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -223,11 +223,8 @@ namespace { target = ~pos.pieces(); break; case EVASIONS: - { - Square checksq = lsb(pos.checkers()); - target = between_bb(pos.square(Us), checksq) | checksq; + target = between_bb(pos.square(Us), lsb(pos.checkers())) | pos.checkers(); break; - } case NON_EVASIONS: target = ~pos.pieces(Us); break; From f3b296c2e2061951d366edfbd5287f336e865553 Mon Sep 17 00:00:00 2001 From: Topologist Date: Mon, 8 Mar 2021 19:46:41 +0100 Subject: [PATCH 69/88] Change advanced pawn push threshold A pawn push is now considered to be "advanced" if the relative destination rank is > 6 (previously it was > 5). This affects the search heuristic. Also remove an assert concerning en passant moves in qsearch(). STC: LLR: 2.97 (-2.94,2.94) {-0.25,1.25} Total: 46744 W: 4224 L: 4040 D: 38480 Ptnml(0-2): 165, 3206, 16451, 3380, 170 https://tests.stockfishchess.org/tests/view/604746082433018de7a3872e LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.25} Total: 107840 W: 4198 L: 3892 D: 99750 Ptnml(0-2): 58, 3472, 46557, 3772, 61 https://tests.stockfishchess.org/tests/view/60475eae2433018de7a38737 Closes https://github.com/official-stockfish/Stockfish/pull/3389 Bench: 4796780 --- AUTHORS | 1 + src/position.h | 2 +- src/search.cpp | 4 +--- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3ef7d1b1..662cc6ec 100644 --- a/AUTHORS +++ b/AUTHORS @@ -168,6 +168,7 @@ Sergio Vieri (sergiovieri) sf-x Shane Booth (shane31) Shawn Varghese (xXH4CKST3RXx) +Siad Daboul (Topologist) Stefan Geschwentner (locutus2) Stefano Cardanobile (Stefano80) Steinar Gunderson (sesse) diff --git a/src/position.h b/src/position.h index 4ab3761f..a7654aa1 100644 --- a/src/position.h +++ b/src/position.h @@ -312,7 +312,7 @@ inline bool Position::pawn_passed(Color c, Square s) const { inline bool Position::advanced_pawn_push(Move m) const { return type_of(moved_piece(m)) == PAWN - && relative_rank(sideToMove, to_sq(m)) > RANK_5; + && relative_rank(sideToMove, to_sq(m)) > RANK_6; } inline int Position::pawns_on_same_color_squares(Color c, Square s) const { diff --git a/src/search.cpp b/src/search.cpp index 4e2ec095..fa592a85 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1575,15 +1575,13 @@ moves_loop: // When in check, search starts from here moveCount++; - // Futility pruning + // Futility pruning and moveCount pruning if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY && !givesCheck && futilityBase > -VALUE_KNOWN_WIN && !pos.advanced_pawn_push(move)) { - assert(type_of(move) != EN_PASSANT); // Due to !pos.advanced_pawn_push - // moveCount pruning if (moveCount > 2) continue; From 939395729c78dd43816826ffdb0a61f33a833e9f Mon Sep 17 00:00:00 2001 From: bmc4 Date: Tue, 16 Mar 2021 20:51:31 +0100 Subject: [PATCH 70/88] Introduce least_significant_square_bb() Introducing least_significant_square_bb(). It is a function that returns a value equal to square_bb(lsb(bb)), but it uses fewer instruction. It should speed up more on older processors like armv7-a Clang. Passed STC: LLR: 2.93 (-2.94,2.94) {-0.25,1.25} Total: 213200 W: 19171 L: 18753 D: 175276 Ptnml(0-2): 680, 14513, 75831, 14861, 715 https://tests.stockfishchess.org/tests/view/604bc7632433018de7a38982 Closes https://github.com/official-stockfish/Stockfish/pull/3391 No functional change --- src/bitboard.h | 7 +++++++ src/position.cpp | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index e14fe0df..1b6af3ea 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -414,6 +414,13 @@ inline Square msb(Bitboard b) { #endif +/// least_significant_square_bb() returns the bitboard of the least significant +/// square of a non-zero bitboard. It is equivalent to square_bb(lsb(bb)). + +inline Bitboard least_significant_square_bb(Bitboard b) { + assert(b); + return b & -b; +} /// pop_lsb() finds and clears the least significant bit in a non-zero bitboard diff --git a/src/position.cpp b/src/position.cpp index 17b165b9..f4739413 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1109,7 +1109,7 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = PawnValueMg - swap) < res) break; - occupied ^= lsb(bb); + occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } @@ -1118,7 +1118,7 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = KnightValueMg - swap) < res) break; - occupied ^= lsb(bb); + occupied ^= least_significant_square_bb(bb); } else if ((bb = stmAttackers & pieces(BISHOP))) @@ -1126,7 +1126,7 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = BishopValueMg - swap) < res) break; - occupied ^= lsb(bb); + occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } @@ -1135,7 +1135,7 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = RookValueMg - swap) < res) break; - occupied ^= lsb(bb); + occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(ROOK, QUEEN); } @@ -1144,7 +1144,7 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = QueenValueMg - swap) < res) break; - occupied ^= lsb(bb); + occupied ^= least_significant_square_bb(bb); attackers |= (attacks_bb(to, occupied) & pieces(BISHOP, QUEEN)) | (attacks_bb(to, occupied) & pieces(ROOK , QUEEN)); } From 4b509559fbabe8a41cb8387c71d07bb1c7b78d6f Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 15 Mar 2021 19:52:45 -0300 Subject: [PATCH 71/88] Simplify move generation (1/2) STC: LLR: 2.95 (-2.94,2.94) {-1.25,0.25} Total: 29792 W: 2611 L: 2545 D: 24636 Ptnml(0-2): 94, 1982, 10659, 2086, 75 https://tests.stockfishchess.org/tests/view/604fe5b62433018de7a38ba8 LTC: LLR: 2.92 (-2.94,2.94) {-0.75,0.25} Total: 22040 W: 826 L: 777 D: 20437 Ptnml(0-2): 8, 646, 9664, 693, 9 https://tests.stockfishchess.org/tests/view/604fec892433018de7a38bac Closes https://github.com/official-stockfish/Stockfish/pull/3399 No functional change --- src/movegen.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index c5d76afa..d8c4370a 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -182,17 +182,12 @@ namespace { Bitboard bb = piecesToMove & pos.pieces(Pt); - if (!bb) - return moveList; - - [[maybe_unused]] const Bitboard checkSquares = pos.check_squares(Pt); - while (bb) { Square from = pop_lsb(&bb); Bitboard b = attacks_bb(from, pos.pieces()) & target; if constexpr (Checks) - b &= checkSquares; + b &= pos.check_squares(Pt); while (b) *moveList++ = make_move(from, pop_lsb(&b)); From 830f597134bc942554283833623f12aa970bcad6 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Tue, 16 Mar 2021 12:21:24 -0300 Subject: [PATCH 72/88] Simplify move generation (2/2) STC: LLR: 2.97 (-2.94,2.94) {-1.25,0.25} Total: 39352 W: 3551 L: 3493 D: 32308 Ptnml(0-2): 143, 2695, 13928, 2781, 129 https://tests.stockfishchess.org/tests/view/6050007a2433018de7a38bbb LTC: LLR: 2.96 (-2.94,2.94) {-0.75,0.25} Total: 44944 W: 1629 L: 1596 D: 41719 Ptnml(0-2): 22, 1319, 19762, 1342, 27 https://tests.stockfishchess.org/tests/view/60500e892433018de7a38bc4 Closes https://github.com/official-stockfish/Stockfish/pull/3399 No functional change --- src/movegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index d8c4370a..5dbc37ce 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -63,7 +63,7 @@ namespace { Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB; Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB; - Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target: + Bitboard enemies = (Type == EVASIONS ? pos.checkers(): Type == CAPTURES ? target : pos.pieces(Them)); // Single and double pawn pushes, no promotions From d58e83695f1dbe5bb75ca9e5d6775757b5fd5f7a Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Thu, 11 Mar 2021 14:51:20 +0300 Subject: [PATCH 73/88] Remove advanced_pawn_push() Continuation of work by @topologist: we now do futility pruning and movecount pruning in qsearch() for pawn pushes up to the 7th rank. So the condition to avoid the pruning is if the move is a promotion or not. This allows to get rid of the advanced_pawn_push() function in position.h alltogether. Passed STC https://tests.stockfishchess.org/tests/view/6048c5842433018de7a387e6 LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 34424 W: 3081 L: 3015 D: 28328 Ptnml(0-2): 110, 2442, 12052, 2488, 120 Passed LTC https://tests.stockfishchess.org/tests/view/6048f7d22433018de7a387f0 LLR: 2.94 (-2.94,2.94) {-0.75,0.25} Total: 142024 W: 5170 L: 5202 D: 131652 Ptnml(0-2): 50, 4678, 61613, 4596, 75 Closes https://github.com/official-stockfish/Stockfish/pull/3390 Bench: 4339126 --- src/position.h | 6 ------ src/search.cpp | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/position.h b/src/position.h index a7654aa1..d470ef90 100644 --- a/src/position.h +++ b/src/position.h @@ -128,7 +128,6 @@ public: bool capture(Move m) const; bool capture_or_promotion(Move m) const; bool gives_check(Move m) const; - bool advanced_pawn_push(Move m) const; Piece moved_piece(Move m) const; Piece captured_piece() const; @@ -310,11 +309,6 @@ inline bool Position::pawn_passed(Color c, Square s) const { return !(pieces(~c, PAWN) & passed_pawn_span(c, s)); } -inline bool Position::advanced_pawn_push(Move m) const { - return type_of(moved_piece(m)) == PAWN - && relative_rank(sideToMove, to_sq(m)) > RANK_6; -} - inline int Position::pawns_on_same_color_squares(Color c, Square s) const { return popcount(pieces(c, PAWN) & ((DarkSquares & s) ? DarkSquares : ~DarkSquares)); } diff --git a/src/search.cpp b/src/search.cpp index fa592a85..af7f801f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1579,7 +1579,7 @@ moves_loop: // When in check, search starts from here if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY && !givesCheck && futilityBase > -VALUE_KNOWN_WIN - && !pos.advanced_pawn_push(move)) + && type_of(move) != PROMOTION) { if (moveCount > 2) From 50890616591443ab06faa0927747bf14c8d450e3 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 15 Mar 2021 16:06:42 -0300 Subject: [PATCH 74/88] Change definition of between_bb() We remark that in current master, most of our use cases for between_bb() can be optimized if the second parameter of the function is added to the segment. So we change the definition of between_bb(s1, s2) such that it excludes s1 but includes s2. We also use a precomputed array for between_bb() for another small speed gain (see https://tests.stockfishchess.org/tests/view/604d09f72433018de7a389fb). Passed STC: LLR: 2.96 (-2.94,2.94) {-0.25,1.25} Total: 18736 W: 1746 L: 1607 D: 15383 Ptnml(0-2): 61, 1226, 6644, 1387, 50 https://tests.stockfishchess.org/tests/view/60428c84ddcba5f0627bb6e4 Yellow LTC: LTC: LLR: -3.00 (-2.94,2.94) {0.25,1.25} Total: 39144 W: 1431 L: 1413 D: 36300 Ptnml(0-2): 13, 1176, 17184, 1178, 21 https://tests.stockfishchess.org/tests/view/605128702433018de7a38ca1 Closes https://github.com/official-stockfish/Stockfish/pull/3397 --------- Verified for correctness by running perft on the following position: ./stockfish position fen 4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21 go perft 6 Nodes searched: 6136386434 -------- No functional change --- src/bitboard.cpp | 9 ++++++++- src/bitboard.h | 20 ++++++++++++-------- src/movegen.cpp | 6 +++--- src/position.cpp | 8 ++++---- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index a2021449..2da4d728 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -29,6 +29,7 @@ uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; Bitboard SquareBB[SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB]; +Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; @@ -107,8 +108,14 @@ void Bitboards::init() { for (PieceType pt : { BISHOP, ROOK }) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) + { if (PseudoAttacks[pt][s1] & s2) - LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2; + { + LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2; + BetweenBB[s1][s2] = (attacks_bb(pt, s1, square_bb(s2)) & attacks_bb(pt, s2, square_bb(s1))); + } + BetweenBB[s1][s2] |= s2; + } } } diff --git a/src/bitboard.h b/src/bitboard.h index 1b6af3ea..70835e8e 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -75,6 +75,7 @@ extern uint8_t PopCnt16[1 << 16]; extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; extern Bitboard SquareBB[SQUARE_NB]; +extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; @@ -215,19 +216,22 @@ inline Bitboard line_bb(Square s1, Square s2) { } -/// between_bb() returns a bitboard representing squares that are linearly -/// between the two given squares (excluding the given squares). If the given -/// squares are not on a same file/rank/diagonal, we return 0. For instance, -/// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5 and E6. +/// between_bb(s1, s2) returns a bitboard representing the squares in the semi-open +/// segment between the squares s1 and s2 (excluding s1 but including s2). If the +/// given squares are not on a same file/rank/diagonal, it returns s2. For instance, +/// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5, E6 and F7, but +/// between_bb(SQ_E6, SQ_F8) will return a bitboard with the square F8. This trick +/// allows to generate non-king evasion moves faster: the defending piece must either +/// interpose itself to cover the check or capture the checking piece. inline Bitboard between_bb(Square s1, Square s2) { - Bitboard b = line_bb(s1, s2) & ((AllSquares << s1) ^ (AllSquares << s2)); - return b & (b - 1); //exclude lsb + assert(is_ok(s1) && is_ok(s2)); + return BetweenBB[s1][s2]; } -/// forward_ranks_bb() returns a bitboard representing the squares on the ranks -/// in front of the given one, from the point of view of the given color. For instance, +/// forward_ranks_bb() returns a bitboard representing the squares on the ranks in +/// front of the given one, from the point of view of the given color. For instance, /// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2. constexpr Bitboard forward_ranks_bb(Color c, Square s) { diff --git a/src/movegen.cpp b/src/movegen.cpp index 5dbc37ce..742dbf40 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -158,7 +158,7 @@ namespace { { assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6)); - // An en passant capture cannot resolve a discovered check. + // An en passant capture cannot resolve a discovered check if (Type == EVASIONS && (target & (pos.ep_square() + Up))) return moveList; @@ -218,7 +218,7 @@ namespace { target = ~pos.pieces(); break; case EVASIONS: - target = between_bb(pos.square(Us), lsb(pos.checkers())) | pos.checkers(); + target = between_bb(pos.square(Us), lsb(pos.checkers())); break; case NON_EVASIONS: target = ~pos.pieces(Us); @@ -329,7 +329,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { if (more_than_one(pos.checkers())) return moveList; // Double check, only a king move can save the day - // Generate blocking evasions or captures of the checking piece + // Generate blocking interpositions or captures of the checking piece return us == WHITE ? generate_all(pos, moveList) : generate_all(pos, moveList); } diff --git a/src/position.cpp b/src/position.cpp index f4739413..772e4545 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -320,7 +320,7 @@ void Position::set_castling_right(Color c, Square rfrom) { Square kto = relative_square(c, cr & KING_SIDE ? SQ_G1 : SQ_C1); Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1); - castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto) + castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto)) & ~(kfrom | rfrom); } @@ -613,8 +613,8 @@ bool Position::pseudo_legal(const Move m) const { if (more_than_one(checkers())) return false; - // Our move must be a blocking evasion or a capture of the checking piece - if (!((between_bb(lsb(checkers()), square(us)) | checkers()) & to)) + // Our move must be a blocking interposition or a capture of the checking piece + if (!(between_bb(square(us), lsb(checkers())) & to)) return false; } // In case of king moves under check we have to remove king so as to catch @@ -1218,7 +1218,7 @@ bool Position::has_game_cycle(int ply) const { Square s1 = from_sq(move); Square s2 = to_sq(move); - if (!(between_bb(s1, s2) & pieces())) + if (!((between_bb(s1, s2) ^ s2) & pieces())) { if (ply > i) return true; From ace9632c6713e346ccca73b3e2edc046c1f5527c Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Mon, 15 Mar 2021 19:05:01 +0100 Subject: [PATCH 75/88] Add a specific FRC correction from classical to NNUE our net currently is not trained on FRC games, and so doesn't know about the important pattern of a bishop that is cornered in FRC. This patch introduces a term we have in the classical evaluation for this case, and adds it to the NNUE eval. Since fishtest doesn't support FRC right now, the patch was tested locally at STC conditions, starting from the book of FRC starting positions. Score of master vs patch: 993 - 2226 - 6781 [0.438] 10000 Which corresponds to approximately 40 Elo The patch passes non-regression testing for traditional chess (where it adds one branch). passed STC: https://tests.stockfishchess.org/tests/view/604fa2532433018de7a38b67 LLR: 2.95 (-2.94,2.94) {-1.25,0.25} Total: 30560 W: 2701 L: 2636 D: 25223 Ptnml(0-2): 88, 2056, 10921, 2133, 82 passed STC also in an earlier version: https://tests.stockfishchess.org/tests/view/604f61282433018de7a38b4d closes https://github.com/official-stockfish/Stockfish/pull/3398 No functional change --- src/evaluate.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d43b8fa7..bb4f9ef7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1038,6 +1038,45 @@ make_v: return v; } + // specifically correct for cornered bishops to fix FRC with NNUE. + Value fix_FRC(const Position& pos) { + + Value bAdjust = Value(0); + + constexpr Value p1=Value(209), p2=Value(136), p3=Value(148); + + Color Us = pos.side_to_move(); + if ( (pos.pieces(Us, BISHOP) & relative_square(Us, SQ_A1)) + && (pos.pieces(Us, PAWN) & relative_square(Us, SQ_B2))) + { + bAdjust -= !pos.empty(relative_square(Us,SQ_B3)) ? p1 + : pos.piece_on(relative_square(Us,SQ_C3)) == make_piece(Us, PAWN) ? p2 + : p3; + } + if ( (pos.pieces(Us, BISHOP) & relative_square(Us, SQ_H1)) + && (pos.pieces(Us, PAWN) & relative_square(Us, SQ_G2))) + { + bAdjust -= !pos.empty(relative_square(Us,SQ_G3)) ? p1 + : pos.piece_on(relative_square(Us,SQ_F3)) == make_piece(Us, PAWN) ? p2 + : p3; + } + if ( (pos.pieces(~Us, BISHOP) & relative_square(Us, SQ_A8)) + && (pos.pieces(~Us, PAWN) & relative_square(Us, SQ_B7))) + { + bAdjust += !pos.empty(relative_square(Us,SQ_B6)) ? p1 + : pos.piece_on(relative_square(Us,SQ_C6)) == make_piece(~Us, PAWN) ? p2 + : p3; + } + if ( (pos.pieces(~Us, BISHOP) & relative_square(Us, SQ_H8)) + && (pos.pieces(~Us, PAWN) & relative_square(Us, SQ_G7))) + { + bAdjust += !pos.empty(relative_square(Us,SQ_G6)) ? p1 + : pos.piece_on(relative_square(Us,SQ_F6)) == make_piece(~Us, PAWN) ? p2 + : p3; + } + return bAdjust; + } + } // namespace @@ -1055,7 +1094,12 @@ Value Eval::evaluate(const Position& pos) { // Scale and shift NNUE for compatibility with search and classical evaluation auto adjusted_NNUE = [&](){ int mat = pos.non_pawn_material() + 2 * PawnValueMg * pos.count(); - return NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo; + Value nnueValue = NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo; + + if (pos.is_chess960()) + nnueValue += fix_FRC(pos); + + return nnueValue; }; // If there is PSQ imbalance use classical eval, with small probability if it is small From ec42154ef2569a58dae2164e328d5bbffcb2aee9 Mon Sep 17 00:00:00 2001 From: Guy Vreuls Date: Sat, 13 Mar 2021 17:40:07 +0100 Subject: [PATCH 76/88] Use reference instead of pointer for pop_lsb() signature This patch changes the pop_lsb() signature from Square pop_lsb(Bitboard*) to Square pop_lsb(Bitboard&). This is more idomatic for C++ style signatures. Passed a non-regression STC test: LLR: 2.93 (-2.94,2.94) {-1.25,0.25} Total: 21280 W: 1928 L: 1847 D: 17505 Ptnml(0-2): 71, 1427, 7558, 1518, 66 https://tests.stockfishchess.org/tests/view/6053a1e22433018de7a38e2f We have verified that the generated binary is identical on gcc-10. Closes https://github.com/official-stockfish/Stockfish/pull/3404 No functional change. --- src/bitbase.cpp | 4 ++-- src/bitboard.h | 8 ++++---- src/evaluate.cpp | 8 ++++---- src/movegen.cpp | 30 +++++++++++++++--------------- src/nnue/features/half_kp.cpp | 2 +- src/pawns.cpp | 4 ++-- src/position.cpp | 6 +++--- src/syzygy/tbprobe.cpp | 4 ++-- 8 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index ece9ec72..10aab6d9 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -150,8 +150,8 @@ namespace { Bitboard b = attacks_bb(ksq[stm]); while (b) - r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(&b), psq)] - : db[index(WHITE, pop_lsb(&b), ksq[WHITE], psq)]; + r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(b), psq)] + : db[index(WHITE, pop_lsb(b), ksq[WHITE], psq)]; if (stm == WHITE) { diff --git a/src/bitboard.h b/src/bitboard.h index 70835e8e..c663f4bd 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -428,10 +428,10 @@ inline Bitboard least_significant_square_bb(Bitboard b) { /// pop_lsb() finds and clears the least significant bit in a non-zero bitboard -inline Square pop_lsb(Bitboard* b) { - assert(*b); - const Square s = lsb(*b); - *b &= *b - 1; +inline Square pop_lsb(Bitboard& b) { + assert(b); + const Square s = lsb(b); + b &= b - 1; return s; } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index bb4f9ef7..d4138cfa 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -397,7 +397,7 @@ namespace { attackedBy[Us][Pt] = 0; while (b1) { - Square s = pop_lsb(&b1); + Square s = pop_lsb(b1); // Find attacked squares, including x-ray attacks for bishops and rooks b = Pt == BISHOP ? attacks_bb(s, pos.pieces() ^ pos.pieces(QUEEN)) @@ -658,11 +658,11 @@ namespace { { b = (defended | weak) & (attackedBy[Us][KNIGHT] | attackedBy[Us][BISHOP]); while (b) - score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(&b)))]; + score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(b)))]; b = weak & attackedBy[Us][ROOK]; while (b) - score += ThreatByRook[type_of(pos.piece_on(pop_lsb(&b)))]; + score += ThreatByRook[type_of(pos.piece_on(pop_lsb(b)))]; if (weak & attackedBy[Us][KING]) score += ThreatByKing; @@ -760,7 +760,7 @@ namespace { while (b) { - Square s = pop_lsb(&b); + Square s = pop_lsb(b); assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up))); diff --git a/src/movegen.cpp b/src/movegen.cpp index 742dbf40..8b043f42 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -102,13 +102,13 @@ namespace { while (b1) { - Square to = pop_lsb(&b1); + Square to = pop_lsb(b1); *moveList++ = make_move(to - Up, to); } while (b2) { - Square to = pop_lsb(&b2); + Square to = pop_lsb(b2); *moveList++ = make_move(to - Up - Up, to); } } @@ -127,13 +127,13 @@ namespace { Bitboard b3 = shift(pawnsOn7) & emptySquares; while (b1) - moveList = make_promotions(moveList, pop_lsb(&b1), ksq); + moveList = make_promotions(moveList, pop_lsb(b1), ksq); while (b2) - moveList = make_promotions(moveList, pop_lsb(&b2), ksq); + moveList = make_promotions(moveList, pop_lsb(b2), ksq); while (b3) - moveList = make_promotions(moveList, pop_lsb(&b3), ksq); + moveList = make_promotions(moveList, pop_lsb(b3), ksq); } // Standard and en passant captures @@ -144,13 +144,13 @@ namespace { while (b1) { - Square to = pop_lsb(&b1); + Square to = pop_lsb(b1); *moveList++ = make_move(to - UpRight, to); } while (b2) { - Square to = pop_lsb(&b2); + Square to = pop_lsb(b2); *moveList++ = make_move(to - UpLeft, to); } @@ -167,7 +167,7 @@ namespace { assert(b1); while (b1) - *moveList++ = make(pop_lsb(&b1), pos.ep_square()); + *moveList++ = make(pop_lsb(b1), pos.ep_square()); } } @@ -183,14 +183,14 @@ namespace { Bitboard bb = piecesToMove & pos.pieces(Pt); while (bb) { - Square from = pop_lsb(&bb); + Square from = pop_lsb(bb); Bitboard b = attacks_bb(from, pos.pieces()) & target; if constexpr (Checks) b &= pos.check_squares(Pt); while (b) - *moveList++ = make_move(from, pop_lsb(&b)); + *moveList++ = make_move(from, pop_lsb(b)); } return moveList; @@ -236,7 +236,7 @@ namespace { Square ksq = pos.square(Us); Bitboard b = attacks_bb(ksq) & target; while (b) - *moveList++ = make_move(ksq, pop_lsb(&b)); + *moveList++ = make_move(ksq, pop_lsb(b)); if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING)) for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } ) @@ -286,7 +286,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { while (dc) { - Square from = pop_lsb(&dc); + Square from = pop_lsb(dc); PieceType pt = type_of(pos.piece_on(from)); Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces(); @@ -295,7 +295,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { b &= ~attacks_bb(pos.square(~us)); while (b) - *moveList++ = make_move(from, pop_lsb(&b)); + *moveList++ = make_move(from, pop_lsb(b)); } return us == WHITE ? generate_all(pos, moveList) @@ -319,12 +319,12 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { // the king evasions in order to skip known illegal moves, which avoids any // useless legality checks later on. while (sliders) - sliderAttacks |= line_bb(ksq, pop_lsb(&sliders)) & ~pos.checkers(); + sliderAttacks |= line_bb(ksq, pop_lsb(sliders)) & ~pos.checkers(); // Generate evasions for king, capture and non capture moves Bitboard b = attacks_bb(ksq) & ~pos.pieces(us) & ~sliderAttacks; while (b) - *moveList++ = make_move(ksq, pop_lsb(&b)); + *moveList++ = make_move(ksq, pop_lsb(b)); if (more_than_one(pos.checkers())) return moveList; // Double check, only a king move can save the day diff --git a/src/nnue/features/half_kp.cpp b/src/nnue/features/half_kp.cpp index ac6317e7..3a25a91d 100644 --- a/src/nnue/features/half_kp.cpp +++ b/src/nnue/features/half_kp.cpp @@ -41,7 +41,7 @@ namespace Stockfish::Eval::NNUE::Features { Square ksq = orient(perspective, pos.square(perspective)); Bitboard bb = pos.pieces() & ~pos.pieces(KING); while (bb) { - Square s = pop_lsb(&bb); + Square s = pop_lsb(bb); active->push_back(make_index(perspective, s, pos.piece_on(s), ksq)); } } diff --git a/src/pawns.cpp b/src/pawns.cpp index 9a0610a0..81255813 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -110,7 +110,7 @@ namespace { // Loop through all pawns of the current color and score each pawn while (b) { - s = pop_lsb(&b); + s = pop_lsb(b); assert(pos.piece_on(s) == make_piece(Us, PAWN)); @@ -290,7 +290,7 @@ Score Entry::do_king_safety(const Position& pos) { if (pawns & attacks_bb(ksq)) minPawnDist = 1; else while (pawns) - minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); + minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(pawns))); return shelter - make_score(0, 16 * minPawnDist); } diff --git a/src/position.cpp b/src/position.cpp index 772e4545..6c5a11b2 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -73,7 +73,7 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) { << std::setfill(' ') << std::dec << "\nCheckers: "; for (Bitboard b = pos.checkers(); b; ) - os << UCI::square(pop_lsb(&b)) << " "; + os << UCI::square(pop_lsb(b)) << " "; if ( int(Tablebases::MaxCardinality) >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING)) @@ -359,7 +359,7 @@ void Position::set_state(StateInfo* si) const { for (Bitboard b = pieces(); b; ) { - Square s = pop_lsb(&b); + Square s = pop_lsb(b); Piece pc = piece_on(s); si->key ^= Zobrist::psq[pc][s]; @@ -476,7 +476,7 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners while (snipers) { - Square sniperSq = pop_lsb(&snipers); + Square sniperSq = pop_lsb(snipers); Bitboard b = between_bb(s, sniperSq) & occupancy; if (b && !more_than_one(b)) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 5cfd38e5..0500dd5a 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -711,7 +711,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu leadPawns = b = pos.pieces(color_of(pc), PAWN); do - squares[size++] = pop_lsb(&b) ^ flipSquares; + squares[size++] = pop_lsb(b) ^ flipSquares; while (b); leadPawnsCnt = size; @@ -731,7 +731,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu // directly map them to the correct color and square. b = pos.pieces() ^ leadPawns; do { - Square s = pop_lsb(&b); + Square s = pop_lsb(b); squares[size] = s ^ flipSquares; pieces[size++] = Piece(pos.piece_on(s) ^ flipColor); } while (b); From 83eac08e7562d93787f75eccd4b7781c4bd45dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Fri, 19 Mar 2021 19:43:25 +0100 Subject: [PATCH 77/88] Small cleanups (march 2021) With help of @BM123499, @mstembera, @gvreuls, @noobpwnftw and @Fanael Thanks! Closes https://github.com/official-stockfish/Stockfish/pull/3405 No functional change --- AUTHORS | 2 +- src/bitbase.cpp | 4 +- src/evaluate.cpp | 92 +++++++++++++++++------------- src/material.cpp | 2 +- src/misc.cpp | 22 +++---- src/movegen.cpp | 3 +- src/nnue/features/half_kp.cpp | 3 +- src/nnue/layers/affine_transform.h | 8 +-- src/pawns.cpp | 3 +- src/search.cpp | 33 ++++++----- src/syzygy/tbprobe.cpp | 10 ++-- src/thread.cpp | 6 +- 12 files changed, 107 insertions(+), 81 deletions(-) diff --git a/AUTHORS b/AUTHORS index 662cc6ec..11de282b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -# List of authors for Stockfish, as of August 4, 2020 +# List of authors for Stockfish, as of March 24, 2021 # Founders of the Stockfish project and fishtest infrastructure Tord Romstad (romstad) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 10aab6d9..27bf4095 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -150,8 +150,8 @@ namespace { Bitboard b = attacks_bb(ksq[stm]); while (b) - r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(b), psq)] - : db[index(WHITE, pop_lsb(b), ksq[WHITE], psq)]; + r |= stm == WHITE ? db[index(BLACK, ksq[BLACK], pop_lsb(b), psq)] + : db[index(WHITE, pop_lsb(b), ksq[WHITE], psq)]; if (stm == WHITE) { diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d4138cfa..ca86a435 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -54,7 +54,6 @@ using namespace std; -using namespace Stockfish::Eval::NNUE; namespace Stockfish { @@ -396,7 +395,8 @@ namespace { attackedBy[Us][Pt] = 0; - while (b1) { + while (b1) + { Square s = pop_lsb(b1); // Find attacked squares, including x-ray attacks for bishops and rooks @@ -1038,46 +1038,51 @@ make_v: return v; } - // specifically correct for cornered bishops to fix FRC with NNUE. + + /// Fisher Random Chess: correction for cornered bishops, to fix chess960 play with NNUE + Value fix_FRC(const Position& pos) { - Value bAdjust = Value(0); + constexpr Bitboard Corners = 1ULL << SQ_A1 | 1ULL << SQ_H1 | 1ULL << SQ_A8 | 1ULL << SQ_H8; - constexpr Value p1=Value(209), p2=Value(136), p3=Value(148); + if (!(pos.pieces(BISHOP) & Corners)) + return VALUE_ZERO; - Color Us = pos.side_to_move(); - if ( (pos.pieces(Us, BISHOP) & relative_square(Us, SQ_A1)) - && (pos.pieces(Us, PAWN) & relative_square(Us, SQ_B2))) - { - bAdjust -= !pos.empty(relative_square(Us,SQ_B3)) ? p1 - : pos.piece_on(relative_square(Us,SQ_C3)) == make_piece(Us, PAWN) ? p2 - : p3; - } - if ( (pos.pieces(Us, BISHOP) & relative_square(Us, SQ_H1)) - && (pos.pieces(Us, PAWN) & relative_square(Us, SQ_G2))) - { - bAdjust -= !pos.empty(relative_square(Us,SQ_G3)) ? p1 - : pos.piece_on(relative_square(Us,SQ_F3)) == make_piece(Us, PAWN) ? p2 - : p3; - } - if ( (pos.pieces(~Us, BISHOP) & relative_square(Us, SQ_A8)) - && (pos.pieces(~Us, PAWN) & relative_square(Us, SQ_B7))) - { - bAdjust += !pos.empty(relative_square(Us,SQ_B6)) ? p1 - : pos.piece_on(relative_square(Us,SQ_C6)) == make_piece(~Us, PAWN) ? p2 - : p3; - } - if ( (pos.pieces(~Us, BISHOP) & relative_square(Us, SQ_H8)) - && (pos.pieces(~Us, PAWN) & relative_square(Us, SQ_G7))) - { - bAdjust += !pos.empty(relative_square(Us,SQ_G6)) ? p1 - : pos.piece_on(relative_square(Us,SQ_F6)) == make_piece(~Us, PAWN) ? p2 - : p3; - } - return bAdjust; + constexpr int penalty1 = -209; + constexpr int penalty2 = -136; + constexpr int penalty3 = -148; + + int correction = 0; + + if ( pos.piece_on(SQ_A1) == W_BISHOP + && pos.piece_on(SQ_B2) == W_PAWN) + correction += !pos.empty(SQ_B3) ? penalty1 + : pos.piece_on(SQ_C3) == W_PAWN ? penalty2 + : penalty3; + + if ( pos.piece_on(SQ_H1) == W_BISHOP + && pos.piece_on(SQ_G2) == W_PAWN) + correction += !pos.empty(SQ_G3) ? penalty1 + : pos.piece_on(SQ_F3) == W_PAWN ? penalty2 + : penalty3; + + if ( pos.piece_on(SQ_A8) == B_BISHOP + && pos.piece_on(SQ_B7) == B_PAWN) + correction += !pos.empty(SQ_B6) ? -penalty1 + : pos.piece_on(SQ_C6) == B_PAWN ? -penalty2 + : -penalty3; + + if ( pos.piece_on(SQ_H8) == B_BISHOP + && pos.piece_on(SQ_G7) == B_PAWN) + correction += !pos.empty(SQ_G6) ? -penalty1 + : pos.piece_on(SQ_F6) == B_PAWN ? -penalty2 + : -penalty3; + + return pos.side_to_move() == WHITE ? Value(correction) + : -Value(correction); } -} // namespace +} // namespace Eval /// evaluate() is the evaluator for the outer world. It returns a static @@ -1092,14 +1097,19 @@ Value Eval::evaluate(const Position& pos) { else { // Scale and shift NNUE for compatibility with search and classical evaluation - auto adjusted_NNUE = [&](){ - int mat = pos.non_pawn_material() + 2 * PawnValueMg * pos.count(); - Value nnueValue = NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo; + auto adjusted_NNUE = [&]() + { + int material = pos.non_pawn_material() + 2 * PawnValueMg * pos.count(); + int scale = 641 + + material / 32 + - 4 * pos.rule50_count(); + + Value nnue = NNUE::evaluate(pos) * scale / 1024 + Tempo; if (pos.is_chess960()) - nnueValue += fix_FRC(pos); + nnue += fix_FRC(pos); - return nnueValue; + return nnue; }; // If there is PSQ imbalance use classical eval, with small probability if it is small diff --git a/src/material.cpp b/src/material.cpp index 84d7a4bd..9d17af20 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -74,7 +74,7 @@ namespace { bool is_KBPsK(const Position& pos, Color us) { return pos.non_pawn_material(us) == BishopValueMg - && pos.count(us) >= 1; + && pos.count(us) >= 1; } bool is_KQKRPs(const Position& pos, Color us) { diff --git a/src/misc.cpp b/src/misc.cpp index 7600fc11..918dc7a9 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -362,8 +362,12 @@ void std_aligned_free(void* ptr) { /// aligned_large_pages_alloc() will return suitably aligned memory, if possible using large pages. #if defined(_WIN32) -#if defined(_WIN64) -static void* aligned_large_pages_alloc_win(size_t allocSize) { + +static void* aligned_large_pages_alloc_windows(size_t allocSize) { + + #if !defined(_WIN64) + return nullptr; + #else HANDLE hProcessToken { }; LUID luid { }; @@ -406,21 +410,18 @@ static void* aligned_large_pages_alloc_win(size_t allocSize) { CloseHandle(hProcessToken); return mem; + + #endif } -#endif void* aligned_large_pages_alloc(size_t allocSize) { -#if defined(_WIN64) // Try to allocate large pages - void* mem = aligned_large_pages_alloc_win(allocSize); + void* mem = aligned_large_pages_alloc_windows(allocSize); // Fall back to regular, page aligned, allocation if necessary if (!mem) mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); -#else - void* mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); -#endif return mem; } @@ -456,8 +457,9 @@ void aligned_large_pages_free(void* mem) { if (mem && !VirtualFree(mem, 0, MEM_RELEASE)) { DWORD err = GetLastError(); - std::cerr << "Failed to free transposition table. Error code: 0x" << - std::hex << err << std::dec << std::endl; + std::cerr << "Failed to free large page memory. Error code: 0x" + << std::hex << err + << std::dec << std::endl; exit(EXIT_FAILURE); } } diff --git a/src/movegen.cpp b/src/movegen.cpp index 8b043f42..1e42f99e 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -182,7 +182,8 @@ namespace { Bitboard bb = piecesToMove & pos.pieces(Pt); - while (bb) { + while (bb) + { Square from = pop_lsb(bb); Bitboard b = attacks_bb(from, pos.pieces()) & target; diff --git a/src/nnue/features/half_kp.cpp b/src/nnue/features/half_kp.cpp index 3a25a91d..5a440b92 100644 --- a/src/nnue/features/half_kp.cpp +++ b/src/nnue/features/half_kp.cpp @@ -40,7 +40,8 @@ namespace Stockfish::Eval::NNUE::Features { Square ksq = orient(perspective, pos.square(perspective)); Bitboard bb = pos.pieces() & ~pos.pieces(KING); - while (bb) { + while (bb) + { Square s = pop_lsb(bb); active->push_back(make_index(perspective, s, pos.piece_on(s), ksq)); } diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index d2713c5a..1faa180d 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -96,7 +96,7 @@ namespace Stockfish::Eval::NNUE::Layers { IndexType idx = k / 2 * kOutputDimensions * 4 + k % 2; sum[w[idx] < 0] += w[idx]; } - for (int sign : {-1, 1}) + for (int sign : { -1, 1 }) while (sign * sum[sign == -1] > 258) { int maxK = 0, maxW = 0; @@ -234,9 +234,9 @@ namespace Stockfish::Eval::NNUE::Layers { __m128i product1 = _mm_maddubs_epi16(a1, b1); __m128i product2 = _mm_maddubs_epi16(a2, b2); __m128i product3 = _mm_maddubs_epi16(a3, b3); - product0 = _mm_adds_epi16(product0, product1); - product2 = _mm_adds_epi16(product2, product3); - product0 = _mm_adds_epi16(product0, product2); + product0 = _mm_add_epi16(product0, product1); + product2 = _mm_add_epi16(product2, product3); + product0 = _mm_add_epi16(product0, product2); product0 = _mm_madd_epi16(product0, kOnes128); acc = _mm_add_epi32(acc, product0); }; diff --git a/src/pawns.cpp b/src/pawns.cpp index 81255813..70fb6f23 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -109,7 +109,8 @@ namespace { e->blockedCount += popcount(shift(ourPawns) & (theirPawns | doubleAttackThem)); // Loop through all pawns of the current color and score each pawn - while (b) { + while (b) + { s = pop_lsb(b); assert(pos.piece_on(s) == make_piece(Us, PAWN)); diff --git a/src/search.cpp b/src/search.cpp index af7f801f..ff8764d8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -612,12 +612,12 @@ namespace { // Step 1. Initialize node Thread* thisThread = pos.this_thread(); - ss->inCheck = pos.checkers(); - priorCapture = pos.captured_piece(); - Color us = pos.side_to_move(); - moveCount = captureCount = quietCount = ss->moveCount = 0; - bestValue = -VALUE_INFINITE; - maxValue = VALUE_INFINITE; + ss->inCheck = pos.checkers(); + priorCapture = pos.captured_piece(); + Color us = pos.side_to_move(); + moveCount = captureCount = quietCount = ss->moveCount = 0; + bestValue = -VALUE_INFINITE; + maxValue = VALUE_INFINITE; ss->distanceFromPv = (PvNode ? 0 : ss->distanceFromPv); // Check for the available remaining time @@ -917,6 +917,7 @@ namespace { return probCutBeta; assert(probCutBeta < VALUE_INFINITE); + MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory); int probCutCount = 0; bool ttPv = ss->ttPv; @@ -1121,6 +1122,7 @@ moves_loop: // When in check, search starts from here { Value singularBeta = ttValue - ((formerPv + 4) * depth) / 2; Depth singularDepth = (depth - 1 + 3 * formerPv) / 2; + ss->excludedMove = move; value = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); ss->excludedMove = MOVE_NONE; @@ -1205,15 +1207,19 @@ moves_loop: // When in check, search starts from here // Decrease reduction if position is or has been on the PV // and node is not likely to fail low. (~10 Elo) - if (ss->ttPv && !likelyFailLow) + if ( ss->ttPv + && !likelyFailLow) r -= 2; // Increase reduction at root and non-PV nodes when the best move does not change frequently - if ((rootNode || !PvNode) && thisThread->rootDepth > 10 && thisThread->bestMoveChanges <= 2) + if ( (rootNode || !PvNode) + && thisThread->rootDepth > 10 + && thisThread->bestMoveChanges <= 2) r++; // More reductions for late moves if position was not in previous PV - if (moveCountPruning && !formerPv) + if ( moveCountPruning + && !formerPv) r++; // Decrease reduction if opponent's move count is high (~5 Elo) @@ -1226,7 +1232,7 @@ moves_loop: // When in check, search starts from here if (captureOrPromotion) { - // Unless giving check, this capture is likely bad + // Increase reduction for non-checking captures likely to be bad if ( !givesCheck && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 210 * depth <= alpha) r++; @@ -1246,7 +1252,7 @@ moves_loop: // When in check, search starts from here // Decrease reduction for moves that escape a capture. Filter out // castling moves, because they are coded as "king captures rook" and - // hence break make_move(). (~2 Elo) + // hence break reverse_move() (~2 Elo) else if ( type_of(move) == NORMAL && !pos.see_ge(reverse_move(move))) r -= 2 + ss->ttPv - (type_of(movedPiece) == PAWN); @@ -1408,8 +1414,9 @@ moves_loop: // When in check, search starts from here assert(moveCount || !ss->inCheck || excludedMove || !MoveList(pos).size()); if (!moveCount) - bestValue = excludedMove ? alpha - : ss->inCheck ? mated_in(ss->ply) : VALUE_DRAW; + bestValue = excludedMove ? alpha : + ss->inCheck ? mated_in(ss->ply) + : VALUE_DRAW; // If there is a move which produces search value greater than alpha we update stats of searched moves else if (bestMove) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 0500dd5a..831c8259 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -192,7 +192,8 @@ public: std::stringstream ss(Paths); std::string path; - while (std::getline(ss, path, SepChar)) { + while (std::getline(ss, path, SepChar)) + { fname = path + "/" + f; std::ifstream::open(fname); if (is_open()) @@ -567,7 +568,8 @@ int decompress_pairs(PairsData* d, uint64_t idx) { int buf64Size = 64; Sym sym; - while (true) { + while (true) + { int len = 0; // This is the symbol length - d->min_sym_len // Now get the symbol length. For any symbol s64 of length l right-padded @@ -605,8 +607,8 @@ int decompress_pairs(PairsData* d, uint64_t idx) { // We binary-search for our value recursively expanding into the left and // right child symbols until we reach a leaf node where symlen[sym] + 1 == 1 // that will store the value we need. - while (d->symlen[sym]) { - + while (d->symlen[sym]) + { Sym left = d->btree[sym].get(); // If a symbol contains 36 sub-symbols (d->symlen[sym] + 1 = 36) and diff --git a/src/thread.cpp b/src/thread.cpp index 3ef73dfa..da8e1d05 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -128,14 +128,16 @@ void Thread::idle_loop() { void ThreadPool::set(size_t requested) { - if (size() > 0) { // destroy any existing thread(s) + if (size() > 0) // destroy any existing thread(s) + { main()->wait_for_search_finished(); while (size() > 0) delete back(), pop_back(); } - if (requested > 0) { // create new thread(s) + if (requested > 0) // create new thread(s) + { push_back(new MainThread(0)); while (size() < requested) From f28303d214645e37ee13b5c285d33142dd71bcb1 Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Sat, 27 Feb 2021 11:52:18 +0100 Subject: [PATCH 78/88] Allow using Intel SDE for PGO builds. The software development emulator (SDE) allows to run binaries compiled for architectures not supported by the actual CPU. This is useful to do PGO builds for newer architectures. The SDE can currently be obtained from https://software.intel.com/content/www/us/en/develop/articles/intel-software-development-emulator.html This patch introduces a new optional makefile argument SDE_PATH. If not empty it should contain the path to the sde executable closes https://github.com/official-stockfish/Stockfish/pull/3373 No functional change. --- src/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index eb32758f..cdd2007f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -31,7 +31,11 @@ PREFIX = /usr/local BINDIR = $(PREFIX)/bin ### Built-in benchmark for pgo-builds -PGOBENCH = ./$(EXE) bench +ifeq ($(SDE_PATH),) + PGOBENCH = ./$(EXE) bench +else + PGOBENCH = $(SDE_PATH) -- ./$(EXE) bench +endif ### Source and object files SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \ From 62a0b65ff886f8f4895d854705c0c870e6a2a834 Mon Sep 17 00:00:00 2001 From: mstembera Date: Thu, 25 Mar 2021 13:33:05 -0700 Subject: [PATCH 79/88] Simplify and unify FRC cornered bishop. tested locally as fishtest doesn't support FRC: STC NNUE 9646 - 9647 - 20707 [0.500] 40000 -0.0 +/- 2.4, LOS: 49.7 %, DrawRatio: 51.8 % STC classical 9678 - 9609 - 20713 [0.501] 40000 0.6 +/- 2.4, LOS: 69.0 %, DrawRatio: 51.8 % and verified independently: Score of master vs patch: 6463 - 6580 - 34957 [0.499] 48000 closes https://github.com/official-stockfish/Stockfish/pull/3413 bench: 4321677 --- src/evaluate.cpp | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ca86a435..74f2e39b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -260,7 +260,8 @@ namespace { constexpr Score UncontestedOutpost = S( 1, 10); constexpr Score BishopOnKingRing = S( 24, 0); constexpr Score BishopXRayPawns = S( 4, 5); - constexpr Score CorneredBishop = S( 50, 50); + constexpr Value CorneredBishopV = Value(50); + constexpr Score CorneredBishop = S(CorneredBishopV, CorneredBishopV); constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); constexpr Score KnightOnQueen = S( 16, 11); @@ -477,9 +478,8 @@ namespace { { Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST); if (pos.piece_on(s + d) == make_piece(Us, PAWN)) - score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4 - : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2 - : CorneredBishop; + score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4 + : CorneredBishop * 3; } } } @@ -1048,35 +1048,27 @@ make_v: if (!(pos.pieces(BISHOP) & Corners)) return VALUE_ZERO; - constexpr int penalty1 = -209; - constexpr int penalty2 = -136; - constexpr int penalty3 = -148; - int correction = 0; if ( pos.piece_on(SQ_A1) == W_BISHOP && pos.piece_on(SQ_B2) == W_PAWN) - correction += !pos.empty(SQ_B3) ? penalty1 - : pos.piece_on(SQ_C3) == W_PAWN ? penalty2 - : penalty3; + correction += !pos.empty(SQ_B3) ? -CorneredBishopV * 4 + : -CorneredBishopV * 3; if ( pos.piece_on(SQ_H1) == W_BISHOP && pos.piece_on(SQ_G2) == W_PAWN) - correction += !pos.empty(SQ_G3) ? penalty1 - : pos.piece_on(SQ_F3) == W_PAWN ? penalty2 - : penalty3; + correction += !pos.empty(SQ_G3) ? -CorneredBishopV * 4 + : -CorneredBishopV * 3; if ( pos.piece_on(SQ_A8) == B_BISHOP && pos.piece_on(SQ_B7) == B_PAWN) - correction += !pos.empty(SQ_B6) ? -penalty1 - : pos.piece_on(SQ_C6) == B_PAWN ? -penalty2 - : -penalty3; + correction += !pos.empty(SQ_B6) ? CorneredBishopV * 4 + : CorneredBishopV * 3; if ( pos.piece_on(SQ_H8) == B_BISHOP && pos.piece_on(SQ_G7) == B_PAWN) - correction += !pos.empty(SQ_G6) ? -penalty1 - : pos.piece_on(SQ_F6) == B_PAWN ? -penalty2 - : -penalty3; + correction += !pos.empty(SQ_G6) ? CorneredBishopV * 4 + : CorneredBishopV * 3; return pos.side_to_move() == WHITE ? Value(correction) : -Value(correction); From c489df6f5b5629a135af3b8222fa1ef607ec1526 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Tue, 30 Mar 2021 00:42:45 -0300 Subject: [PATCH 80/88] Simplify King Evasion Simplify away the removal of some illegal `KING`-evasion moves during move generation. Verified for correctness by running perft on the following positions: ``` ./stockfish bench 16 1 6 default perft Nodes searched: 71608931810 ./stockfish position fen 4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21 go perft 6 Nodes searched: 6136386434 ``` Passed STC: LLR: 2.94 (-2.94,2.94) {-1.00,0.20} Total: 16072 W: 1473 L: 1349 D: 13250 Ptnml(0-2): 57, 1047, 5710, 1159, 63 https://tests.stockfishchess.org/tests/view/60629e7ef183b42957b423b1 Passed LTC: LLR: 2.94 (-2.94,2.94) {-0.70,0.20} Total: 59064 W: 2214 L: 2177 D: 54673 Ptnml(0-2): 26, 1944, 25556, 1979, 27 https://tests.stockfishchess.org/tests/view/6062dce4f183b42957b423de closes https://github.com/official-stockfish/Stockfish/pull/3415 No functional change --- src/movegen.cpp | 12 ++---------- src/position.cpp | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 1e42f99e..50496136 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -313,17 +313,9 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { Color us = pos.side_to_move(); Square ksq = pos.square(us); - Bitboard sliderAttacks = 0; - Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN); - // Find all the squares attacked by slider checkers. We will remove them from - // the king evasions in order to skip known illegal moves, which avoids any - // useless legality checks later on. - while (sliders) - sliderAttacks |= line_bb(ksq, pop_lsb(sliders)) & ~pos.checkers(); - - // Generate evasions for king, capture and non capture moves - Bitboard b = attacks_bb(ksq) & ~pos.pieces(us) & ~sliderAttacks; + // Generate evasions for king + Bitboard b = attacks_bb(ksq) & ~pos.pieces(us); while (b) *moveList++ = make_move(ksq, pop_lsb(b)); diff --git a/src/position.cpp b/src/position.cpp index 6c5a11b2..ec356ace 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -544,7 +544,7 @@ bool Position::legal(Move m) const { // If the moving piece is a king, check whether the destination square is // attacked by the opponent. if (type_of(piece_on(from)) == KING) - return !(attackers_to(to) & pieces(~us)); + return !(attackers_to(to, pieces() ^ from) & pieces(~us)); // A non-king move is legal if and only if it is not pinned or it // is moving along the ray towards or away from the king. From b862c8d4be2cf6245360a8072ab910a67eb5bc00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Wed, 24 Mar 2021 21:55:49 +0100 Subject: [PATCH 81/88] Small clean-up Bench: 4321677 --- AUTHORS | 2 +- README.md | 10 +++++----- src/bitboard.cpp | 2 +- src/bitboard.h | 3 +++ src/evaluate.cpp | 27 ++++++++++++++------------- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/AUTHORS b/AUTHORS index 11de282b..c12b98a0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -# List of authors for Stockfish, as of March 24, 2021 +# List of authors for Stockfish, as of March 31, 2021 # Founders of the Stockfish project and fishtest infrastructure Tord Romstad (romstad) diff --git a/README.md b/README.md index fdc6fd61..67fb5fa0 100644 --- a/README.md +++ b/README.md @@ -242,9 +242,9 @@ When not using the Makefile to compile (for instance, with Microsoft MSVC) you need to manually set/unset some switches in the compiler command line; see file *types.h* for a quick reference. -When reporting an issue or a bug, please tell us which version and -compiler you used to create your executable. These informations can -be found by typing the following commands in a console: +When reporting an issue or a bug, please tell us which Stockfish version +and which compiler you used to create your executable. This information +can be found by typing the following command in a console: ``` ./stockfish compiler @@ -252,8 +252,8 @@ be found by typing the following commands in a console: ## Understanding the code base and participating in the project -Stockfish's improvement over the last couple of years has been a great -community effort. There are a few ways to help contribute to its growth. +Stockfish's improvement over the last decade has been a great community +effort. There are a few ways to help contribute to its growth. ### Donating hardware diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 2da4d728..6b84b51e 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -130,7 +130,7 @@ namespace { for (Direction d : (pt == ROOK ? RookDirections : BishopDirections)) { Square s = sq; - while(safe_destination(s, d) && !(occupied & s)) + while (safe_destination(s, d) && !(occupied & s)) attacks |= (s += d); } diff --git a/src/bitboard.h b/src/bitboard.h index c663f4bd..b29f3e24 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -212,6 +212,7 @@ constexpr Bitboard adjacent_files_bb(Square s) { inline Bitboard line_bb(Square s1, Square s2) { assert(is_ok(s1) && is_ok(s2)); + return LineBB[s1][s2]; } @@ -225,7 +226,9 @@ inline Bitboard line_bb(Square s1, Square s2) { /// interpose itself to cover the check or capture the checking piece. inline Bitboard between_bb(Square s1, Square s2) { + assert(is_ok(s1) && is_ok(s2)); + return BetweenBB[s1][s2]; } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 74f2e39b..437e753a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -256,12 +256,12 @@ namespace { S(0, 0), S(3, 44), S(37, 68), S(42, 60), S(0, 39), S(58, 43) }; + constexpr Value CorneredBishop = Value(50); + // Assorted bonuses and penalties constexpr Score UncontestedOutpost = S( 1, 10); constexpr Score BishopOnKingRing = S( 24, 0); constexpr Score BishopXRayPawns = S( 4, 5); - constexpr Value CorneredBishopV = Value(50); - constexpr Score CorneredBishop = S(CorneredBishopV, CorneredBishopV); constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); constexpr Score KnightOnQueen = S( 16, 11); @@ -478,8 +478,8 @@ namespace { { Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST); if (pos.piece_on(s + d) == make_piece(Us, PAWN)) - score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4 - : CorneredBishop * 3; + score -= !pos.empty(s + d + pawn_push(Us)) ? 4 * make_score(CorneredBishop, CorneredBishop) + : 3 * make_score(CorneredBishop, CorneredBishop); } } } @@ -1052,23 +1052,23 @@ make_v: if ( pos.piece_on(SQ_A1) == W_BISHOP && pos.piece_on(SQ_B2) == W_PAWN) - correction += !pos.empty(SQ_B3) ? -CorneredBishopV * 4 - : -CorneredBishopV * 3; + correction += !pos.empty(SQ_B3) ? -CorneredBishop * 4 + : -CorneredBishop * 3; if ( pos.piece_on(SQ_H1) == W_BISHOP && pos.piece_on(SQ_G2) == W_PAWN) - correction += !pos.empty(SQ_G3) ? -CorneredBishopV * 4 - : -CorneredBishopV * 3; + correction += !pos.empty(SQ_G3) ? -CorneredBishop * 4 + : -CorneredBishop * 3; if ( pos.piece_on(SQ_A8) == B_BISHOP && pos.piece_on(SQ_B7) == B_PAWN) - correction += !pos.empty(SQ_B6) ? CorneredBishopV * 4 - : CorneredBishopV * 3; + correction += !pos.empty(SQ_B6) ? CorneredBishop * 4 + : CorneredBishop * 3; if ( pos.piece_on(SQ_H8) == B_BISHOP && pos.piece_on(SQ_G7) == B_PAWN) - correction += !pos.empty(SQ_G6) ? CorneredBishopV * 4 - : CorneredBishopV * 3; + correction += !pos.empty(SQ_G6) ? CorneredBishop * 4 + : CorneredBishop * 3; return pos.side_to_move() == WHITE ? Value(correction) : -Value(correction); @@ -1119,7 +1119,8 @@ Value Eval::evaluate(const Position& pos) { // If the classical eval is small and imbalance large, use NNUE nevertheless. // For the case of opposite colored bishops, switch to NNUE eval with // small probability if the classical eval is less than the threshold. - if ( largePsq && !strongClassical + if ( largePsq + && !strongClassical && ( abs(v) * 16 < NNUEThreshold2 * r50 || ( pos.opposite_bishops() && abs(v) * 16 < (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50 From f40913f7f699d9d875e44929608b45947421ad03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sun, 4 Apr 2021 10:51:45 +0200 Subject: [PATCH 82/88] Keep more pawns This patch increases the weight of pawns in the scale factor applied to the output of the NNUE evaluation. This has the effect that Stockfish will try a little bit harder to keep more pawns in position where the engine has the advantage, and exchange more pawns in bad positions. STC: LLR: 2.93 (-2.94,2.94) {-0.20,1.10} Total: 42552 W: 3858 L: 3668 D: 35026 Ptnml(0-2): 152, 2956, 14876, 3134, 158 https://tests.stockfishchess.org/tests/view/606a06dd2b2df919fd5f0504 LTC: LLR: 2.95 (-2.94,2.94) {0.20,0.90} Total: 44328 W: 1703 L: 1531 D: 41094 Ptnml(0-2): 20, 1373, 19207, 1543, 21 https://tests.stockfishchess.org/tests/view/606aa4ec2b2df919fd5f053e Closes https://github.com/official-stockfish/Stockfish/pull/3420 Bench: 4310076 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 437e753a..789e2859 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1091,8 +1091,8 @@ Value Eval::evaluate(const Position& pos) { // Scale and shift NNUE for compatibility with search and classical evaluation auto adjusted_NNUE = [&]() { - int material = pos.non_pawn_material() + 2 * PawnValueMg * pos.count(); - int scale = 641 + int material = pos.non_pawn_material() + 4 * PawnValueMg * pos.count(); + int scale = 580 + material / 32 - 4 * pos.rule50_count(); From 3dfda1b28e14d1f3c2422fed5f203e305f58af28 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 6 Apr 2021 16:51:05 +0300 Subject: [PATCH 83/88] Replace distanceFromPv with a better logic This patch removes the recently introduced distanceFromPv logic, and replaces it with following logic: if reduction of moves with low movecount is really negative, we search them deeper than the first move. passed STC: LLR: 2.95 (-2.94,2.94) {-0.20,1.10} Total: 153008 W: 13913 L: 13579 D: 125516 Ptnml(0-2): 547, 10811, 53470, 11113, 563 https://tests.stockfishchess.org/tests/view/6069c9d02b2df919fd5f04d2 passed LTC: LLR: 2.94 (-2.94,2.94) {0.20,0.90} Total: 101920 W: 3964 L: 3699 D: 94257 Ptnml(0-2): 55, 3279, 44019, 3560, 47 https://tests.stockfishchess.org/tests/view/606a99fd2b2df919fd5f0532 Closes https://github.com/official-stockfish/Stockfish/pull/3421 Bench: 4191632 --- src/search.cpp | 11 ++++------- src/search.h | 1 - 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index ff8764d8..f23db4c1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -618,7 +618,6 @@ namespace { moveCount = captureCount = quietCount = ss->moveCount = 0; bestValue = -VALUE_INFINITE; maxValue = VALUE_INFINITE; - ss->distanceFromPv = (PvNode ? 0 : ss->distanceFromPv); // Check for the available remaining time if (thisThread == Threads.main()) @@ -1180,8 +1179,6 @@ moves_loop: // When in check, search starts from here // Step 15. Make the move pos.do_move(move, st, givesCheck); - (ss+1)->distanceFromPv = ss->distanceFromPv + moveCount - 1; - // Step 16. Late moves reduction / extension (LMR, ~200 Elo) // We use various heuristics for the sons of a node after the first son has // been searched. In general we would like to reduce them, but there are many @@ -1280,10 +1277,10 @@ moves_loop: // When in check, search starts from here r -= ss->statScore / 14790; } - // In general we want to cap the LMR depth search at newDepth. But for nodes - // close to the principal variation the cap is at (newDepth + 1), which will - // allow these nodes to be searched deeper than the pv (up to 4 plies deeper). - Depth d = std::clamp(newDepth - r, 1, newDepth + ((ss+1)->distanceFromPv <= 4)); + // In general we want to cap the LMR depth search at newDepth. But if + // reductions are really negative and movecount is low, we allow this move + // to be searched deeper than the first move. + Depth d = std::clamp(newDepth - r, 1, newDepth + (r < -1 && moveCount <= 5)); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); diff --git a/src/search.h b/src/search.h index 6f9fbd05..811b2e2a 100644 --- a/src/search.h +++ b/src/search.h @@ -49,7 +49,6 @@ struct Stack { Value staticEval; int statScore; int moveCount; - int distanceFromPv; bool inCheck; bool ttPv; bool ttHit; From 79bb28281ce5e9b40b2662915a96e9072ddad82e Mon Sep 17 00:00:00 2001 From: bmc4 Date: Fri, 2 Apr 2021 09:30:14 -0300 Subject: [PATCH 84/88] Merge all move generators Merging `generate` and `generate` into `generate_all()`. STC: LLR: 2.94 (-2.94,2.94) {-1.00,0.20} Total: 161800 W: 14585 L: 14624 D: 132591 Ptnml(0-2): 577, 11681, 56451, 11586, 605 https://tests.stockfishchess.org/tests/view/606532732b2df919fd5f026d LTC: LLR: 2.98 (-2.94,2.94) {-0.70,0.20} Total: 188504 W: 6906 L: 6961 D: 174637 Ptnml(0-2): 87, 6272, 81610, 6175, 108 https://tests.stockfishchess.org/tests/view/6065b0772b2df919fd5f02ae ------------ Verified for correctness of `EVASIONS` by running perft: ``` ./stockfish b3nch 16 1 6 default perft (replace 3 by e in b3nch) Nodes searched : 71608931810 ``` Also tested for correctness on Chess960 with a similar code shown here: https://github.com/official-stockfish/Stockfish/pull/3418#issuecomment-816630295 ``` ./stockfish b3nch 16 1 6 fischer.txt perft Nodes searched : 506736009395 ``` ------------ Closes https://github.com/official-stockfish/Stockfish/pull/3418 No functional change --- src/movegen.cpp | 99 ++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 72 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 50496136..c3c149b7 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -175,19 +175,19 @@ namespace { } - template - ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard piecesToMove, Bitboard target) { + template + ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) { static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); - Bitboard bb = piecesToMove & pos.pieces(Pt); + Bitboard bb = pos.pieces(Us, Pt); while (bb) { Square from = pop_lsb(bb); Bitboard b = attacks_bb(from, pos.pieces()) & target; - if constexpr (Checks) + if (Checks && (Pt == QUEEN || !(pos.blockers_for_king(~Us) & from))) b &= pos.check_squares(Pt); while (b) @@ -204,10 +204,11 @@ namespace { static_assert(Type != LEGAL, "Unsupported type in generate_all()"); constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations - Bitboard target, piecesToMove = pos.pieces(Us); - - if(Type == QUIET_CHECKS) - piecesToMove &= ~pos.blockers_for_king(~Us); + const Square ksq = pos.square(Us); + Bitboard target; + + if (Type == EVASIONS && more_than_one(pos.checkers())) + goto kingMoves; // Double check, only a king move can save the day switch (Type) { @@ -219,7 +220,7 @@ namespace { target = ~pos.pieces(); break; case EVASIONS: - target = between_bb(pos.square(Us), lsb(pos.checkers())); + target = between_bb(ksq, lsb(pos.checkers())); break; case NON_EVASIONS: target = ~pos.pieces(Us); @@ -227,19 +228,22 @@ namespace { } moveList = generate_pawn_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, piecesToMove, target); - moveList = generate_moves(pos, moveList, piecesToMove, target); - moveList = generate_moves< ROOK, Checks>(pos, moveList, piecesToMove, target); - moveList = generate_moves< QUEEN, Checks>(pos, moveList, piecesToMove, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); - if (Type != QUIET_CHECKS && Type != EVASIONS) +kingMoves: + if (!Checks || pos.blockers_for_king(~Us) & ksq) { - Square ksq = pos.square(Us); - Bitboard b = attacks_bb(ksq) & target; + Bitboard b = attacks_bb(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target); + if (Checks) + b &= ~attacks_bb(pos.square(~Us)); + while (b) *moveList++ = make_move(ksq, pop_lsb(b)); - if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING)) + if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING)) for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } ) if (!pos.castling_impeded(cr) && pos.can_castle(cr)) *moveList++ = make(ksq, pos.castling_rook_square(cr)); @@ -253,6 +257,8 @@ namespace { /// Generates all pseudo-legal captures plus queen and checking knight promotions /// Generates all pseudo-legal non-captures and underpromotions (except checking knight) +/// Generates all pseudo-legal check evasions when the side to move is in check +/// Generates all pseudo-legal non-captures giving check, except castling /// Generates all pseudo-legal captures and non-captures /// /// Returns a pointer to the end of the move list. @@ -260,8 +266,8 @@ namespace { template ExtMove* generate(const Position& pos, ExtMove* moveList) { - static_assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS, "Unsupported type in generate()"); - assert(!pos.checkers()); + static_assert(Type != LEGAL, "Unsupported type in generate()"); + assert((Type == EVASIONS) == (bool)pos.checkers()); Color us = pos.side_to_move(); @@ -272,62 +278,11 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { // Explicit template instantiations template ExtMove* generate(const Position&, ExtMove*); template ExtMove* generate(const Position&, ExtMove*); +template ExtMove* generate(const Position&, ExtMove*); +template ExtMove* generate(const Position&, ExtMove*); template ExtMove* generate(const Position&, ExtMove*); -/// generate generates all pseudo-legal non-captures giving check, -/// except castling. Returns a pointer to the end of the move list. -template<> -ExtMove* generate(const Position& pos, ExtMove* moveList) { - - assert(!pos.checkers()); - - Color us = pos.side_to_move(); - Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us) & ~pos.pieces(PAWN); - - while (dc) - { - Square from = pop_lsb(dc); - PieceType pt = type_of(pos.piece_on(from)); - - Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces(); - - if (pt == KING) - b &= ~attacks_bb(pos.square(~us)); - - while (b) - *moveList++ = make_move(from, pop_lsb(b)); - } - - return us == WHITE ? generate_all(pos, moveList) - : generate_all(pos, moveList); -} - - -/// generate generates all pseudo-legal check evasions when the side -/// to move is in check. Returns a pointer to the end of the move list. -template<> -ExtMove* generate(const Position& pos, ExtMove* moveList) { - - assert(pos.checkers()); - - Color us = pos.side_to_move(); - Square ksq = pos.square(us); - - // Generate evasions for king - Bitboard b = attacks_bb(ksq) & ~pos.pieces(us); - while (b) - *moveList++ = make_move(ksq, pop_lsb(b)); - - if (more_than_one(pos.checkers())) - return moveList; // Double check, only a king move can save the day - - // Generate blocking interpositions or captures of the checking piece - return us == WHITE ? generate_all(pos, moveList) - : generate_all(pos, moveList); -} - - /// generate generates all the legal moves in the given position template<> From 4889cf22bb2985d6d0babb8da93698e5d7641304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Thu, 15 Apr 2021 11:18:38 +0200 Subject: [PATCH 85/88] Revert previous patch Revert the previous patch about move generation, as it unexpectedly changed the bench. Better to take the time to understand the issue. Bench: 4191632 --- src/movegen.cpp | 99 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 27 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index c3c149b7..50496136 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -175,19 +175,19 @@ namespace { } - template - ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) { + template + ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard piecesToMove, Bitboard target) { static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); - Bitboard bb = pos.pieces(Us, Pt); + Bitboard bb = piecesToMove & pos.pieces(Pt); while (bb) { Square from = pop_lsb(bb); Bitboard b = attacks_bb(from, pos.pieces()) & target; - if (Checks && (Pt == QUEEN || !(pos.blockers_for_king(~Us) & from))) + if constexpr (Checks) b &= pos.check_squares(Pt); while (b) @@ -204,11 +204,10 @@ namespace { static_assert(Type != LEGAL, "Unsupported type in generate_all()"); constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations - const Square ksq = pos.square(Us); - Bitboard target; - - if (Type == EVASIONS && more_than_one(pos.checkers())) - goto kingMoves; // Double check, only a king move can save the day + Bitboard target, piecesToMove = pos.pieces(Us); + + if(Type == QUIET_CHECKS) + piecesToMove &= ~pos.blockers_for_king(~Us); switch (Type) { @@ -220,7 +219,7 @@ namespace { target = ~pos.pieces(); break; case EVASIONS: - target = between_bb(ksq, lsb(pos.checkers())); + target = between_bb(pos.square(Us), lsb(pos.checkers())); break; case NON_EVASIONS: target = ~pos.pieces(Us); @@ -228,22 +227,19 @@ namespace { } moveList = generate_pawn_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, piecesToMove, target); + moveList = generate_moves(pos, moveList, piecesToMove, target); + moveList = generate_moves< ROOK, Checks>(pos, moveList, piecesToMove, target); + moveList = generate_moves< QUEEN, Checks>(pos, moveList, piecesToMove, target); -kingMoves: - if (!Checks || pos.blockers_for_king(~Us) & ksq) + if (Type != QUIET_CHECKS && Type != EVASIONS) { - Bitboard b = attacks_bb(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target); - if (Checks) - b &= ~attacks_bb(pos.square(~Us)); - + Square ksq = pos.square(Us); + Bitboard b = attacks_bb(ksq) & target; while (b) *moveList++ = make_move(ksq, pop_lsb(b)); - if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING)) + if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING)) for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } ) if (!pos.castling_impeded(cr) && pos.can_castle(cr)) *moveList++ = make(ksq, pos.castling_rook_square(cr)); @@ -257,8 +253,6 @@ kingMoves: /// Generates all pseudo-legal captures plus queen and checking knight promotions /// Generates all pseudo-legal non-captures and underpromotions (except checking knight) -/// Generates all pseudo-legal check evasions when the side to move is in check -/// Generates all pseudo-legal non-captures giving check, except castling /// Generates all pseudo-legal captures and non-captures /// /// Returns a pointer to the end of the move list. @@ -266,8 +260,8 @@ kingMoves: template ExtMove* generate(const Position& pos, ExtMove* moveList) { - static_assert(Type != LEGAL, "Unsupported type in generate()"); - assert((Type == EVASIONS) == (bool)pos.checkers()); + static_assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS, "Unsupported type in generate()"); + assert(!pos.checkers()); Color us = pos.side_to_move(); @@ -278,11 +272,62 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { // Explicit template instantiations template ExtMove* generate(const Position&, ExtMove*); template ExtMove* generate(const Position&, ExtMove*); -template ExtMove* generate(const Position&, ExtMove*); -template ExtMove* generate(const Position&, ExtMove*); template ExtMove* generate(const Position&, ExtMove*); +/// generate generates all pseudo-legal non-captures giving check, +/// except castling. Returns a pointer to the end of the move list. +template<> +ExtMove* generate(const Position& pos, ExtMove* moveList) { + + assert(!pos.checkers()); + + Color us = pos.side_to_move(); + Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us) & ~pos.pieces(PAWN); + + while (dc) + { + Square from = pop_lsb(dc); + PieceType pt = type_of(pos.piece_on(from)); + + Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces(); + + if (pt == KING) + b &= ~attacks_bb(pos.square(~us)); + + while (b) + *moveList++ = make_move(from, pop_lsb(b)); + } + + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); +} + + +/// generate generates all pseudo-legal check evasions when the side +/// to move is in check. Returns a pointer to the end of the move list. +template<> +ExtMove* generate(const Position& pos, ExtMove* moveList) { + + assert(pos.checkers()); + + Color us = pos.side_to_move(); + Square ksq = pos.square(us); + + // Generate evasions for king + Bitboard b = attacks_bb(ksq) & ~pos.pieces(us); + while (b) + *moveList++ = make_move(ksq, pop_lsb(b)); + + if (more_than_one(pos.checkers())) + return moveList; // Double check, only a king move can save the day + + // Generate blocking interpositions or captures of the checking piece + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); +} + + /// generate generates all the legal moves in the given position template<> From 14d162d9f4f3544acf617de46a38a69878003e31 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 14 Apr 2021 21:25:18 +0300 Subject: [PATCH 86/88] Simplification: last capture extension The code for last capture extension can be removed in current master. Passed STC LLR: 2.95 (-2.94,2.94) {-1.00,0.20} Total: 85024 W: 7754 L: 7707 D: 69563 Ptnml(0-2): 293, 5991, 29914, 6004, 310 https://tests.stockfishchess.org/tests/view/607690f1814175337896068f Passed LTC LLR: 2.96 (-2.94,2.94) {-0.70,0.20} Total: 39880 W: 1503 L: 1453 D: 36924 Ptnml(0-2): 17, 1281, 17293, 1333, 16 https://tests.stockfishchess.org/tests/view/6076ccbe814175337896069e Closes https://github.com/official-stockfish/Stockfish/pull/3430 Bench: 4202264 --- src/search.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f23db4c1..c9ee47fe 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1158,11 +1158,6 @@ moves_loop: // When in check, search starts from here && (pos.is_discovered_check_on_king(~us, move) || pos.see_ge(move))) extension = 1; - // Last captures extension - else if ( PieceValue[EG][pos.captured_piece()] > PawnValueEg - && pos.non_pawn_material() <= 2 * RookValueMg) - extension = 1; - // Add extension to new depth newDepth += extension; From 255514fb29f5a7a2c95863c9b074e36209b841c1 Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Tue, 13 Apr 2021 20:02:28 +0200 Subject: [PATCH 87/88] Documentation patch: AppendChangedIndices Clarify the assumptions on the position passed to the AppendChangedIndices(). Closes https://github.com/official-stockfish/Stockfish/pull/3428 No functional change --- src/nnue/features/half_kp.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/nnue/features/half_kp.cpp b/src/nnue/features/half_kp.cpp index 5a440b92..8e6907ae 100644 --- a/src/nnue/features/half_kp.cpp +++ b/src/nnue/features/half_kp.cpp @@ -47,7 +47,25 @@ namespace Stockfish::Eval::NNUE::Features { } } - // Get a list of indices for recently changed features + + // AppendChangedIndices() : get a list of indices for recently changed features + + // IMPORTANT: The `pos` in this function is pretty much useless as it + // is not always the position the features are updated to. The feature + // transformer code right now can update multiple accumulators per move, + // but since Stockfish only keeps the full state of the current leaf + // search position it is not possible to always pass here the position for + // which the accumulator is being updated. Therefore the only thing that + // can be reliably extracted from `pos` is the king square for the king + // of the `perspective` color (note: not even the other king's square will + // match reality in all cases, this is also the reason why `dp` is passed + // as a parameter and not extracted from pos.state()). This is of particular + // problem for future nets with other feature sets, where updating the active + // feature might require more information from the intermediate positions. In + // this case the only easy solution is to remove the multiple updates from + // the feature transformer update code and only update the accumulator for + // the current leaf position (the position after the move). + template void HalfKP::AppendChangedIndices( const Position& pos, const DirtyPiece& dp, Color perspective, From a7ab92ec25c91e8413630c52cfc2db6b4ecacf0c Mon Sep 17 00:00:00 2001 From: dsmsgms Date: Mon, 12 Apr 2021 12:06:22 -0300 Subject: [PATCH 88/88] Use classical eval for Bishop vs Pawns NNUE evaluation is incapable of recognizing trivially drawn bishop endgames (the wrong-colored rook pawn), which are in fact ubiquitous and stock standard in chess analysis. Switching off NNUE evaluation in KBPs vs KPs endgames is a measure that stops Stockfish from trading down to a drawn version of these endings when we presumably have advantage. The patch is able to edge over master in endgame positions. Patch tested for Elo gain with the "endgame.epd" book, and verified for non-regression with our usual book (see the pull request for details). STC: LLR: 2.93 (-2.94,2.94) {-0.20,1.10} Total: 33232 W: 6655 L: 6497 D: 20080 Ptnml(0-2): 4, 2342, 11769, 2494, 7 https://tests.stockfishchess.org/tests/view/6074a52981417533789605b8 LTC: LLR: 2.93 (-2.94,2.94) {0.20,0.90} Total: 159056 W: 29799 L: 29378 D: 99879 Ptnml(0-2): 7, 9004, 61085, 9425, 7 https://tests.stockfishchess.org/tests/view/6074c39a81417533789605ca Closes https://github.com/official-stockfish/Stockfish/pull/3427 Bench: 4503918 blah --- src/evaluate.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 789e2859..ba3de70b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1104,23 +1104,26 @@ Value Eval::evaluate(const Position& pos) { return nnue; }; - // If there is PSQ imbalance use classical eval, with small probability if it is small + // If there is PSQ imbalance we use the classical eval. We also introduce + // a small probability of using the classical eval when PSQ imbalance is small. Value psq = Value(abs(eg_value(pos.psq_score()))); int r50 = 16 + pos.rule50_count(); bool largePsq = psq * 16 > (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50; bool classical = largePsq || (psq > PawnValueMg / 4 && !(pos.this_thread()->nodes & 0xB)); // Use classical evaluation for really low piece endgames. - // The most critical case is a bishop + A/H file pawn vs naked king draw. - bool strongClassical = pos.non_pawn_material() < 2 * RookValueMg && pos.count() < 2; + // One critical case is the draw for bishop + A/H file pawn vs naked king. + bool lowPieceEndgame = pos.non_pawn_material() == BishopValueMg + || (pos.non_pawn_material() < 2 * RookValueMg && pos.count() < 2); - v = classical || strongClassical ? Evaluation(pos).value() : adjusted_NNUE(); + v = classical || lowPieceEndgame ? Evaluation(pos).value() + : adjusted_NNUE(); // If the classical eval is small and imbalance large, use NNUE nevertheless. - // For the case of opposite colored bishops, switch to NNUE eval with - // small probability if the classical eval is less than the threshold. - if ( largePsq - && !strongClassical + // For the case of opposite colored bishops, switch to NNUE eval with small + // probability if the classical eval is less than the threshold. + if ( largePsq + && !lowPieceEndgame && ( abs(v) * 16 < NNUEThreshold2 * r50 || ( pos.opposite_bishops() && abs(v) * 16 < (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50