/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2023 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
#include "timeman.h"
#include "uci.h"
#include "incbin/incbin.h"
-
+#include "nnue/evaluate_nnue.h"
// Macro to embed the default efficiently updatable neural network (NNUE) file
// data in the engine binary (using incbin.h, by Dale Weiler).
eval_file = EvalFileDefaultName;
#if defined(DEFAULT_NNUE_DIRECTORY)
- #define stringify2(x) #x
- #define stringify(x) stringify2(x)
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
#else
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory };
#endif
- for (string directory : dirs)
+ for (const string& directory : dirs)
if (currentEvalFileName != eval_file)
{
if (directory != "<internal>")
{
ifstream stream(directory + eval_file, ios::binary);
- if (load_eval(eval_file, stream))
+ if (NNUE::load_eval(eval_file, stream))
currentEvalFileName = eval_file;
}
(void) gEmbeddedNNUEEnd; // Silence warning on unused variable
istream stream(&buffer);
- if (load_eval(eval_file, stream))
+ if (NNUE::load_eval(eval_file, stream))
currentEvalFileName = eval_file;
}
}
Score scores[TERM_NB][COLOR_NB];
- double to_cp(Value v) { return double(v) / UCI::NormalizeToPawnValue; }
+ static double to_cp(Value v) { return double(v) / UCI::NormalizeToPawnValue; }
- void add(int idx, Color c, Score s) {
+ static void add(int idx, Color c, Score s) {
scores[idx][c] = s;
}
- void add(int idx, Score w, Score b = SCORE_ZERO) {
+ static void add(int idx, Score w, Score b = SCORE_ZERO) {
scores[idx][WHITE] = w;
scores[idx][BLACK] = b;
}
- std::ostream& operator<<(std::ostream& os, Score s) {
+ static std::ostream& operator<<(std::ostream& os, Score s) {
os << std::setw(5) << to_cp(mg_value(s)) << " "
<< std::setw(5) << to_cp(eg_value(s));
return os;
}
- std::ostream& operator<<(std::ostream& os, Term t) {
+ static std::ostream& operator<<(std::ostream& os, Term t) {
if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL)
os << " ---- ----" << " | " << " ---- ----";
namespace {
// Threshold for lazy and space evaluation
- constexpr Value LazyThreshold1 = Value(3631);
- constexpr Value LazyThreshold2 = Value(2084);
+ constexpr Value LazyThreshold1 = Value(3622);
+ constexpr Value LazyThreshold2 = Value(1962);
constexpr Value SpaceThreshold = Value(11551);
// KingAttackWeights[PieceType] contains king attack weights by piece type
template<Tracing T> template<Color Us, PieceType Pt>
Score Evaluation<T>::pieces() {
- constexpr Color Them = ~Us;
- constexpr Direction Down = -pawn_push(Us);
- constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
- : Rank5BB | Rank4BB | Rank3BB);
+ constexpr Color Them = ~Us;
+ [[maybe_unused]] constexpr Direction Down = -pawn_push(Us);
+ [[maybe_unused]] constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
+ : Rank5BB | Rank4BB | Rank3BB);
Bitboard b1 = pos.pieces(Us, Pt);
Bitboard b, bb;
Score score = SCORE_ZERO;
int mob = popcount(b & mobilityArea[Us]);
mobility[Us] += MobilityBonus[Pt - 2][mob];
- if (Pt == BISHOP || Pt == KNIGHT)
+ if constexpr (Pt == BISHOP || Pt == KNIGHT)
{
// Bonus if the piece is on an outpost square or can reach one
// Bonus for knights (UncontestedOutpost) if few relevant targets
/// evaluate() is the evaluator for the outer world. It returns a static
/// evaluation of the position from the point of view of the side to move.
-Value Eval::evaluate(const Position& pos, int* complexity) {
+Value Eval::evaluate(const Position& pos) {
+
+ assert(!pos.checkers());
Value v;
Value psq = pos.psq_eg_stm();
// We use the much less accurate but faster Classical eval when the NNUE
// option is set to false. Otherwise we use the NNUE eval unless the
- // PSQ advantage is decisive and several pieces remain. (~3 Elo)
- bool useClassical = !useNNUE || (pos.count<ALL_PIECES>() > 7 && abs(psq) > 1760);
+ // PSQ advantage is decisive. (~4 Elo at STC, 1 Elo at LTC)
+ bool useClassical = !useNNUE || abs(psq) > 2048;
if (useClassical)
v = Evaluation<NO_TRACE>(pos).value();
else
{
int nnueComplexity;
- int scale = 1076 + 96 * pos.non_pawn_material() / 5120;
+ int npm = pos.non_pawn_material() / 64;
Color stm = pos.side_to_move();
Value optimism = pos.this_thread()->optimism[stm];
Value nnue = NNUE::evaluate(pos, true, &nnueComplexity);
// Blend nnue complexity with (semi)classical complexity
- nnueComplexity = ( 412 * nnueComplexity
- + 428 * abs(psq - nnue)
- + (optimism > 0 ? int(optimism) * int(psq - nnue) : 0)
- ) / 1026;
-
- // Return hybrid NNUE complexity to caller
- if (complexity)
- *complexity = nnueComplexity;
+ nnueComplexity = 25 * (nnueComplexity + abs(psq - nnue)) / 64;
- optimism = optimism * (278 + nnueComplexity) / 256;
- v = (nnue * scale + optimism * (scale - 755)) / 1024;
+ optimism += optimism * nnueComplexity / 256;
+ v = (nnue * (945 + npm) + optimism * (174 + npm)) / 1024;
}
// Damp down the evaluation linearly when shuffling
- v = v * (197 - pos.rule50_count()) / 214;
+ v = v * (200 - pos.rule50_count()) / 214;
// Guarantee evaluation does not hit the tablebase range
v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
- // When not using NNUE, return classical complexity to caller
- if (complexity && (!useNNUE || useClassical))
- *complexity = abs(v - psq);
-
return v;
}