mirror of
https://github.com/sockspls/badfish
synced 2025-04-29 08:13:08 +00:00
Introduce Various Correction histories
This patch introduces three additional correction histories, namely, Major Piece Correction History, Minor Piece Correction History, and Non-Pawn Correction History. Introduced by @mcthouacbb in Sirius (https://github.com/mcthouacbb/Sirius) chess engine. The Major Piece Correction History is indexed by side-to-move and the Zobrist key representing the position of the King, Rook, and Queen of both sides. Likewise, the Minor Piece Correction History is indexed by side-to-move and the Zobrist key representing the position of the King, Knight, and Bishop of both sides. Also See:97b85bbaac
3099cdef2f
Introduced by @zzzzz151 in Starzix (https://github.com/zzzzz151/Starzix) chess engine. Non-Pawn correction history consists of side-to-move, side of Zobrist key, and a Zobrist key representing of the position of all non-pawn pieces of **one side**. The non-pawn correction values for both key sides are then summed. Also See:34911772f1
33e0df8dd2
The weights on the final correction value of the above correction histories, as well as existing correction histories, are then tuned in two separate SPSA sessions, totaling 75k games. SPSA1: https://tests.stockfishchess.org/tests/view/66e5243886d5ee47d953a86b (Stopped early due to some weights reaching the maximum value) SPSA2: https://tests.stockfishchess.org/tests/view/66e6a26f86d5ee47d953a965 Also thanks to @martinnovaak, (Motor https://github.com/martinnovaak/motor author) for insights and suggestions. Passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 23328 W: 6197 L: 5901 D: 11230 Ptnml(0-2): 82, 2582, 6041, 2876, 83 https://tests.stockfishchess.org/tests/view/66e8787b86d5ee47d953ab6f Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 10626 W: 2826 L: 2560 D: 5240 Ptnml(0-2): 4, 1054, 2941, 1300, 14 https://tests.stockfishchess.org/tests/view/66e8ab2386d5ee47d953aba8 closes https://github.com/official-stockfish/Stockfish/pull/5598 Bench: 1011161
This commit is contained in:
parent
240a5b1c72
commit
60351b9df9
7 changed files with 140 additions and 27 deletions
|
@ -140,8 +140,8 @@ Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) {
|
|||
|
||||
// Computes all rook and bishop attacks at startup. Magic
|
||||
// bitboards are used to look up attacks of sliding pieces. As a reference see
|
||||
// www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
|
||||
// called "fancy" approach.
|
||||
// https://www.chessprogramming.org/Magic_Bitboards. In particular, here we use
|
||||
// the so called "fancy" approach.
|
||||
void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
|
||||
|
||||
// Optimal PRNG seeds to pick the correct magics in the shortest time
|
||||
|
|
|
@ -34,10 +34,13 @@
|
|||
|
||||
namespace Stockfish {
|
||||
|
||||
constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2
|
||||
constexpr int PAWN_CORRECTION_HISTORY_SIZE = 16384; // has to be a power of 2
|
||||
constexpr int MATERIAL_CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
|
||||
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
|
||||
constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2
|
||||
constexpr int PAWN_CORRECTION_HISTORY_SIZE = 16384; // has to be a power of 2
|
||||
constexpr int MATERIAL_CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
|
||||
constexpr int MAJOR_PIECE_CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
|
||||
constexpr int MINOR_PIECE_CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
|
||||
constexpr int NON_PAWN_CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
|
||||
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
|
||||
|
||||
static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0,
|
||||
"PAWN_HISTORY_SIZE has to be a power of 2");
|
||||
|
@ -59,6 +62,19 @@ inline int material_index(const Position& pos) {
|
|||
return pos.material_key() & (MATERIAL_CORRECTION_HISTORY_SIZE - 1);
|
||||
}
|
||||
|
||||
inline int major_piece_index(const Position& pos) {
|
||||
return pos.major_piece_key() & (MAJOR_PIECE_CORRECTION_HISTORY_SIZE - 1);
|
||||
}
|
||||
|
||||
inline int minor_piece_index(const Position& pos) {
|
||||
return pos.minor_piece_key() & (MINOR_PIECE_CORRECTION_HISTORY_SIZE - 1);
|
||||
}
|
||||
|
||||
template<Color c>
|
||||
inline int non_pawn_index(const Position& pos) {
|
||||
return pos.non_pawn_key(c) & (NON_PAWN_CORRECTION_HISTORY_SIZE - 1);
|
||||
}
|
||||
|
||||
// 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 a naked value
|
||||
// to directly call history update operator<<() on the entry so to use stats
|
||||
|
@ -120,7 +136,7 @@ enum StatsType {
|
|||
// ButterflyHistory records how often quiet moves have been successful or 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 (~11 elo)
|
||||
// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo)
|
||||
using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
|
||||
|
||||
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
|
||||
|
@ -138,10 +154,10 @@ using ContinuationHistory = Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB>
|
|||
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
|
||||
using PawnHistory = Stats<int16_t, 8192, PAWN_HISTORY_SIZE, PIECE_NB, SQUARE_NB>;
|
||||
|
||||
|
||||
// Correction histories record differences between the static evaluation of
|
||||
// positions and their search score. It is used to improve the static evaluation
|
||||
// used by some search heuristics.
|
||||
// see https://www.chessprogramming.org/Static_Evaluation_Correction_History
|
||||
|
||||
// PawnCorrectionHistory is addressed by color and pawn structure
|
||||
using PawnCorrectionHistory =
|
||||
|
@ -151,6 +167,18 @@ using PawnCorrectionHistory =
|
|||
using MaterialCorrectionHistory =
|
||||
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, MATERIAL_CORRECTION_HISTORY_SIZE>;
|
||||
|
||||
// MajorPieceCorrectionHistory is addressed by color and king/major piece (Queen, Rook) positions
|
||||
using MajorPieceCorrectionHistory =
|
||||
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, MAJOR_PIECE_CORRECTION_HISTORY_SIZE>;
|
||||
|
||||
// MinorPieceCorrectionHistory is addressed by color and king/minor piece (Knight, Bishop) positions
|
||||
using MinorPieceCorrectionHistory =
|
||||
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, MINOR_PIECE_CORRECTION_HISTORY_SIZE>;
|
||||
|
||||
// NonPawnCorrectionHistory is addressed by color and non-pawn material positions
|
||||
using NonPawnCorrectionHistory =
|
||||
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, NON_PAWN_CORRECTION_HISTORY_SIZE>;
|
||||
|
||||
// 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 emits one
|
||||
// new pseudo-legal move on every call, until there are no moves left, when
|
||||
|
|
|
@ -334,8 +334,10 @@ void Position::set_check_info() const {
|
|||
// The function is only used when a new position is set up
|
||||
void Position::set_state() const {
|
||||
|
||||
st->key = st->materialKey = 0;
|
||||
st->pawnKey = Zobrist::noPawns;
|
||||
st->key = st->materialKey = 0;
|
||||
st->majorPieceKey = st->minorPieceKey = 0;
|
||||
st->nonPawnKey[WHITE] = st->nonPawnKey[BLACK] = 0;
|
||||
st->pawnKey = Zobrist::noPawns;
|
||||
st->nonPawnMaterial[WHITE] = st->nonPawnMaterial[BLACK] = VALUE_ZERO;
|
||||
st->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
|
||||
|
||||
|
@ -350,8 +352,27 @@ void Position::set_state() const {
|
|||
if (type_of(pc) == PAWN)
|
||||
st->pawnKey ^= Zobrist::psq[pc][s];
|
||||
|
||||
else if (type_of(pc) != KING)
|
||||
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
|
||||
else
|
||||
{
|
||||
st->nonPawnKey[color_of(pc)] ^= Zobrist::psq[pc][s];
|
||||
|
||||
if (type_of(pc) != KING)
|
||||
{
|
||||
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
|
||||
|
||||
if (type_of(pc) == QUEEN || type_of(pc) == ROOK)
|
||||
st->majorPieceKey ^= Zobrist::psq[pc][s];
|
||||
|
||||
else
|
||||
st->minorPieceKey ^= Zobrist::psq[pc][s];
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
st->majorPieceKey ^= Zobrist::psq[pc][s];
|
||||
st->minorPieceKey ^= Zobrist::psq[pc][s];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (st->epSquare != SQ_NONE)
|
||||
|
@ -707,6 +728,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
do_castling<true>(us, from, to, rfrom, rto);
|
||||
|
||||
k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
|
||||
st->majorPieceKey ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
|
||||
st->nonPawnKey[us] ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
|
||||
captured = NO_PIECE;
|
||||
}
|
||||
|
||||
|
@ -732,7 +755,16 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
st->pawnKey ^= Zobrist::psq[captured][capsq];
|
||||
}
|
||||
else
|
||||
{
|
||||
st->nonPawnMaterial[them] -= PieceValue[captured];
|
||||
st->nonPawnKey[them] ^= Zobrist::psq[captured][capsq];
|
||||
|
||||
if (type_of(pc) == QUEEN || type_of(pc) == ROOK)
|
||||
st->majorPieceKey ^= Zobrist::psq[captured][capsq];
|
||||
|
||||
else
|
||||
st->minorPieceKey ^= Zobrist::psq[captured][capsq];
|
||||
}
|
||||
|
||||
dp.dirty_num = 2; // 1 piece moved, 1 piece captured
|
||||
dp.piece[1] = captured;
|
||||
|
@ -790,7 +822,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
|
||||
else if (m.type_of() == PROMOTION)
|
||||
{
|
||||
Piece promotion = make_piece(us, m.promotion_type());
|
||||
Piece promotion = make_piece(us, m.promotion_type());
|
||||
PieceType promotionType = type_of(promotion);
|
||||
|
||||
assert(relative_rank(us, to) == RANK_8);
|
||||
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
|
||||
|
@ -811,6 +844,12 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
st->materialKey ^=
|
||||
Zobrist::psq[promotion][pieceCount[promotion] - 1] ^ Zobrist::psq[pc][pieceCount[pc]];
|
||||
|
||||
if (promotionType == QUEEN || promotionType == ROOK)
|
||||
st->majorPieceKey ^= Zobrist::psq[promotion][to];
|
||||
|
||||
else
|
||||
st->minorPieceKey ^= Zobrist::psq[promotion][to];
|
||||
|
||||
// Update material
|
||||
st->nonPawnMaterial[us] += PieceValue[promotion];
|
||||
}
|
||||
|
@ -822,6 +861,23 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
st->rule50 = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
st->nonPawnKey[us] ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||
|
||||
if (type_of(pc) == KING)
|
||||
{
|
||||
st->majorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||
}
|
||||
|
||||
else if (type_of(pc) == QUEEN || type_of(pc) == ROOK)
|
||||
st->majorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||
|
||||
else
|
||||
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||
}
|
||||
|
||||
// Set capture piece
|
||||
st->capturedPiece = captured;
|
||||
|
||||
|
|
|
@ -43,6 +43,9 @@ struct StateInfo {
|
|||
// Copied when making a move
|
||||
Key materialKey;
|
||||
Key pawnKey;
|
||||
Key majorPieceKey;
|
||||
Key minorPieceKey;
|
||||
Key nonPawnKey[COLOR_NB];
|
||||
Value nonPawnMaterial[COLOR_NB];
|
||||
int castlingRights;
|
||||
int rule50;
|
||||
|
@ -151,6 +154,9 @@ class Position {
|
|||
Key key_after(Move m) const;
|
||||
Key material_key() const;
|
||||
Key pawn_key() const;
|
||||
Key major_piece_key() const;
|
||||
Key minor_piece_key() const;
|
||||
Key non_pawn_key(Color c) const;
|
||||
|
||||
// Other properties of the position
|
||||
Color side_to_move() const;
|
||||
|
@ -298,6 +304,12 @@ inline Key Position::pawn_key() const { return st->pawnKey; }
|
|||
|
||||
inline Key Position::material_key() const { return st->materialKey; }
|
||||
|
||||
inline Key Position::major_piece_key() const { return st->majorPieceKey; }
|
||||
|
||||
inline Key Position::minor_piece_key() const { return st->minorPieceKey; }
|
||||
|
||||
inline Key Position::non_pawn_key(Color c) const { return st->nonPawnKey[c]; }
|
||||
|
||||
inline Value Position::non_pawn_material(Color c) const { return st->nonPawnMaterial[c]; }
|
||||
|
||||
inline Value Position::non_pawn_material() const {
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "thread.h"
|
||||
#include "timeman.h"
|
||||
#include "tt.h"
|
||||
#include "types.h"
|
||||
#include "uci.h"
|
||||
#include "ucioption.h"
|
||||
|
||||
|
@ -81,11 +80,16 @@ constexpr int futility_move_count(bool improving, Depth depth) {
|
|||
// Add correctionHistory value to raw staticEval and guarantee evaluation
|
||||
// does not hit the tablebase range.
|
||||
Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos) {
|
||||
const auto pcv =
|
||||
w.pawnCorrectionHistory[pos.side_to_move()][pawn_structure_index<Correction>(pos)];
|
||||
const auto mcv = w.materialCorrectionHistory[pos.side_to_move()][material_index(pos)];
|
||||
const auto cv = (2 * pcv + mcv) / 3;
|
||||
v += 74 * cv / 512;
|
||||
const Color us = pos.side_to_move();
|
||||
const auto pcv = w.pawnCorrectionHistory[us][pawn_structure_index<Correction>(pos)];
|
||||
const auto mcv = w.materialCorrectionHistory[us][material_index(pos)];
|
||||
const auto macv = w.majorPieceCorrectionHistory[us][major_piece_index(pos)];
|
||||
const auto micv = w.minorPieceCorrectionHistory[us][minor_piece_index(pos)];
|
||||
const auto wnpcv = w.nonPawnCorrectionHistory[WHITE][us][non_pawn_index<WHITE>(pos)];
|
||||
const auto bnpcv = w.nonPawnCorrectionHistory[BLACK][us][non_pawn_index<BLACK>(pos)];
|
||||
const auto cv =
|
||||
(98198 * pcv + 68968 * mcv + 54353 * macv + 85174 * micv + 85581 * (wnpcv + bnpcv)) / 2097152;
|
||||
v += cv;
|
||||
return std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
|
||||
}
|
||||
|
||||
|
@ -500,6 +504,10 @@ void Search::Worker::clear() {
|
|||
pawnHistory.fill(-1152);
|
||||
pawnCorrectionHistory.fill(0);
|
||||
materialCorrectionHistory.fill(0);
|
||||
majorPieceCorrectionHistory.fill(0);
|
||||
minorPieceCorrectionHistory.fill(0);
|
||||
nonPawnCorrectionHistory[WHITE].fill(0);
|
||||
nonPawnCorrectionHistory[BLACK].fill(0);
|
||||
|
||||
for (bool inCheck : {false, true})
|
||||
for (StatsType c : {NoCaptures, Captures})
|
||||
|
@ -1403,6 +1411,10 @@ moves_loop: // When in check, search starts here
|
|||
-CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4);
|
||||
thisThread->pawnCorrectionHistory[us][pawn_structure_index<Correction>(pos)] << bonus;
|
||||
thisThread->materialCorrectionHistory[us][material_index(pos)] << bonus;
|
||||
thisThread->majorPieceCorrectionHistory[us][major_piece_index(pos)] << bonus;
|
||||
thisThread->minorPieceCorrectionHistory[us][minor_piece_index(pos)] << bonus;
|
||||
thisThread->nonPawnCorrectionHistory[WHITE][us][non_pawn_index<WHITE>(pos)] << bonus;
|
||||
thisThread->nonPawnCorrectionHistory[BLACK][us][non_pawn_index<BLACK>(pos)] << bonus;
|
||||
}
|
||||
|
||||
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
||||
|
|
19
src/search.h
19
src/search.h
|
@ -277,13 +277,18 @@ class Worker {
|
|||
void ensure_network_replicated();
|
||||
|
||||
// Public because they need to be updatable by the stats
|
||||
ButterflyHistory mainHistory;
|
||||
ButterflyHistory rootHistory;
|
||||
CapturePieceToHistory captureHistory;
|
||||
ContinuationHistory continuationHistory[2][2];
|
||||
PawnHistory pawnHistory;
|
||||
PawnCorrectionHistory pawnCorrectionHistory;
|
||||
MaterialCorrectionHistory materialCorrectionHistory;
|
||||
ButterflyHistory mainHistory;
|
||||
ButterflyHistory rootHistory;
|
||||
|
||||
CapturePieceToHistory captureHistory;
|
||||
ContinuationHistory continuationHistory[2][2];
|
||||
PawnHistory pawnHistory;
|
||||
|
||||
PawnCorrectionHistory pawnCorrectionHistory;
|
||||
MaterialCorrectionHistory materialCorrectionHistory;
|
||||
MajorPieceCorrectionHistory majorPieceCorrectionHistory;
|
||||
MinorPieceCorrectionHistory minorPieceCorrectionHistory;
|
||||
NonPawnCorrectionHistory nonPawnCorrectionHistory[COLOR_NB];
|
||||
|
||||
private:
|
||||
void iterative_deepening();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
# verify perft numbers (positions from www.chessprogramming.org/Perft_Results)
|
||||
# verify perft numbers (positions from https://www.chessprogramming.org/Perft_Results)
|
||||
|
||||
error()
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue