Skip to content

Commit

Permalink
Introduce Various Correction Histories
Browse files Browse the repository at this point in the history
This patch introduces four additional correction histories, namely, Major Piece Correction History, Minor Piece Correction History, Defender Piece Correction History, and Non-Pawn Correction History.
  • Loading branch information
PikaCat-OuO committed Sep 17, 2024
1 parent 83af752 commit ad65f08
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 25 deletions.
4 changes: 2 additions & 2 deletions src/bitboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ Bitboard lame_leaper_attack(Square s, 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.
template<PieceType pt>
void init_magics(Bitboard table[], Magic magics[], const Bitboard magicsInit[]) {

Expand Down
50 changes: 44 additions & 6 deletions src/movepick.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@

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 DEFENDER_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");
Expand All @@ -59,6 +63,24 @@ 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);
}

inline int defender_piece_index(const Position& pos) {
return pos.defender_piece_key() & (DEFENDER_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
Expand Down Expand Up @@ -120,7 +142,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, 1 << 14>;

// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
Expand All @@ -138,10 +160,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 =
Expand All @@ -151,6 +173,22 @@ using PawnCorrectionHistory =
using MaterialCorrectionHistory =
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, MATERIAL_CORRECTION_HISTORY_SIZE>;

// MajorPieceCorrectionHistory is addressed by color and king/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, Cannon) positions
using MinorPieceCorrectionHistory =
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, MINOR_PIECE_CORRECTION_HISTORY_SIZE>;

// DefenderPieceCorrectionHistory is addressed by color and king/defender piece (Advisor, Bishop) positions
using DefenderPieceCorrectionHistory =
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, DEFENDER_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
Expand Down
70 changes: 65 additions & 5 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,9 @@ void Position::set_check_info() const {
void Position::set_state() const {

st->key = st->materialKey = 0;
st->pawnKey = Zobrist::noPawns;
st->majorPieceKey = st->minorPieceKey = st->defenderPieceKey = 0;
st->nonPawnKey[WHITE] = st->nonPawnKey[BLACK] = 0;
st->pawnKey = Zobrist::noPawns;
st->majorMaterial[WHITE] = st->majorMaterial[BLACK] = VALUE_ZERO;
st->checkersBB = checkers_to(~sideToMove, king_square(sideToMove));
st->move = Move::none();
Expand All @@ -227,8 +229,32 @@ void Position::set_state() const {
if (pt == PAWN)
st->pawnKey ^= Zobrist::psq[pc][s];

else if (pt & 1)
st->majorMaterial[color_of(pc)] += PieceValue[pc];
else
{
st->nonPawnKey[color_of(pc)] ^= Zobrist::psq[pc][s];

if (pt != KING)
{
if (pt & 1)
st->majorMaterial[color_of(pc)] += PieceValue[pc];

if (pt == ROOK)
st->majorPieceKey ^= Zobrist::psq[pc][s];

else if (pt == KNIGHT || pt == CANNON)
st->minorPieceKey ^= Zobrist::psq[pc][s];

else
st->defenderPieceKey ^= Zobrist::psq[pc][s];
}

else
{
st->majorPieceKey ^= Zobrist::psq[pc][s];
st->minorPieceKey ^= Zobrist::psq[pc][s];
st->defenderPieceKey ^= Zobrist::psq[pc][s];
}
}
}

if (sideToMove == BLACK)
Expand Down Expand Up @@ -495,8 +521,22 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
// update major material.
if (type_of(captured) == PAWN)
st->pawnKey ^= Zobrist::psq[captured][capsq];
else if (type_of(captured) & 1)
st->majorMaterial[them] -= PieceValue[captured];

else
{
if (type_of(captured) & 1)
st->majorMaterial[them] -= PieceValue[captured];
st->nonPawnKey[them] ^= Zobrist::psq[captured][capsq];

if (type_of(captured) == ROOK)
st->majorPieceKey ^= Zobrist::psq[captured][capsq];

else if (type_of(captured) == KNIGHT || type_of(captured) == CANNON)
st->minorPieceKey ^= Zobrist::psq[captured][capsq];

else
st->defenderPieceKey ^= Zobrist::psq[captured][capsq];
}

dp.dirty_num = 2; // 1 piece moved, 1 piece captured
dp.piece[1] = captured;
Expand Down Expand Up @@ -526,6 +566,26 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
// If the moving piece is a pawn, update pawn hash key.
if (type_of(pc) == PAWN)
st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
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];
st->defenderPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
}

else if (type_of(pc) == ROOK)
st->majorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];

else if (type_of(pc) == KNIGHT || type_of(pc) == CANNON)
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];

else
st->defenderPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
}

// Move the piece.
dp.piece[0] = pc;
Expand Down
16 changes: 16 additions & 0 deletions src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ struct StateInfo {
// Copied when making a move
Key materialKey;
Key pawnKey;
Key majorPieceKey;
Key minorPieceKey;
Key defenderPieceKey;
Key nonPawnKey[COLOR_NB];
Value majorMaterial[COLOR_NB];
int16_t check10[COLOR_NB];
int rule60;
Expand Down Expand Up @@ -147,6 +151,10 @@ 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 defender_piece_key() const;
Key non_pawn_key(Color c) const;

// Other properties of the position
Color side_to_move() const;
Expand Down Expand Up @@ -275,6 +283,14 @@ 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::defender_piece_key() const { return st->defenderPieceKey; }

inline Key Position::non_pawn_key(Color c) const { return st->nonPawnKey[c]; }

inline Value Position::major_material(Color c) const { return st->majorMaterial[c]; }

inline Value Position::major_material() const {
Expand Down
27 changes: 22 additions & 5 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,18 @@ constexpr int futility_move_count(bool improving, Depth depth) {
// Add correctionHistory value to raw staticEval and guarantee evaluation
// does not hit the mate 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 += 32 * 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 decv = w.defenderPieceCorrectionHistory[us][defender_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 + 85174 * decv
+ 85581 * (wnpcv + bnpcv))
/ 2097152;
v += cv;
return std::clamp(v, VALUE_MATED_IN_MAX_PLY + 1, VALUE_MATE_IN_MAX_PLY - 1);
}

Expand Down Expand Up @@ -459,6 +466,11 @@ void Search::Worker::clear() {
pawnHistory.fill(-1316);
pawnCorrectionHistory.fill(0);
materialCorrectionHistory.fill(0);
majorPieceCorrectionHistory.fill(0);
minorPieceCorrectionHistory.fill(0);
defenderPieceCorrectionHistory.fill(0);
nonPawnCorrectionHistory[WHITE].fill(0);
nonPawnCorrectionHistory[BLACK].fill(0);

for (bool inCheck : {false, true})
for (StatsType c : {NoCaptures, Captures})
Expand Down Expand Up @@ -1313,6 +1325,11 @@ Value Search::Worker::search(
-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->defenderPieceCorrectionHistory[us][defender_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);
Expand Down
19 changes: 12 additions & 7 deletions src/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,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;
DefenderPieceCorrectionHistory defenderPieceCorrectionHistory;
NonPawnCorrectionHistory nonPawnCorrectionHistory[COLOR_NB];

private:
void iterative_deepening();
Expand Down

0 comments on commit ad65f08

Please sign in to comment.