X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fevaluate.cpp;h=64f9172574a4d7fda710a4ffde587e9ea4fc065d;hb=b939c805139e4b37f04fbf177f580c35ebe9f130;hp=789e28594cd6d8f2a7c555750b165903088f1afd;hpb=f40913f7f699d9d875e44929608b45947421ad03;p=stockfish diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 789e2859..64f91725 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -33,6 +33,7 @@ #include "misc.h" #include "pawns.h" #include "thread.h" +#include "timeman.h" #include "uci.h" #include "incbin/incbin.h" @@ -179,7 +180,7 @@ namespace Trace { else os << scores[t][WHITE] << " | " << scores[t][BLACK]; - os << " | " << scores[t][WHITE] - scores[t][BLACK] << "\n"; + os << " | " << scores[t][WHITE] - scores[t][BLACK] << " |\n"; return os; } } @@ -189,11 +190,9 @@ using namespace Trace; namespace { // Threshold for lazy and space evaluation - constexpr Value LazyThreshold1 = Value(1565); - constexpr Value LazyThreshold2 = Value(1102); - constexpr Value SpaceThreshold = Value(11551); - constexpr Value NNUEThreshold1 = Value(682); - constexpr Value NNUEThreshold2 = Value(176); + constexpr Value LazyThreshold1 = Value(3130); + constexpr Value LazyThreshold2 = Value(2204); + constexpr Value SpaceThreshold = Value(11551); // KingAttackWeights[PieceType] contains king attack weights by piece type constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 }; @@ -906,7 +905,7 @@ namespace { Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK; int sf = me->scale_factor(pos, strongSide); - // If scale factor is not already specific, scale down via general heuristics + // If scale factor is not already specific, scale up/down via general heuristics if (sf == SCALE_FACTOR_NORMAL) { if (pos.opposite_bishops()) @@ -979,7 +978,7 @@ namespace { // Initialize score by reading the incrementally updated scores included in // the position object (material + piece square tables) and the material // imbalance. Score is computed internally from the white point of view. - Score score = pos.psq_score() + me->imbalance() + pos.this_thread()->contempt; + Score score = pos.psq_score() + me->imbalance() + pos.this_thread()->trend; // Probe the pawn hash table pe = Pawns::probe(pos); @@ -987,7 +986,7 @@ namespace { // Early exit if score is high auto lazy_skip = [&](Value lazyThreshold) { - return abs(mg_value(score) + eg_value(score)) / 2 > lazyThreshold + pos.non_pawn_material() / 64; + return abs(mg_value(score) + eg_value(score)) > lazyThreshold + pos.non_pawn_material() / 32; }; if (lazy_skip(LazyThreshold1)) @@ -1033,7 +1032,7 @@ make_v: v = (v / 16) * 16; // Side to move point of view - v = (pos.side_to_move() == WHITE ? v : -v) + Tempo; + v = (pos.side_to_move() == WHITE ? v : -v); return v; } @@ -1091,12 +1090,11 @@ 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() + 4 * PawnValueMg * pos.count(); - int scale = 580 - + material / 32 - - 4 * pos.rule50_count(); + int scale = 883 + + 32 * pos.count() + + 32 * pos.non_pawn_material() / 1024; - Value nnue = NNUE::evaluate(pos) * scale / 1024 + Tempo; + Value nnue = NNUE::evaluate(pos, true) * scale / 1024; if (pos.is_chess960()) nnue += fix_FRC(pos); @@ -1104,28 +1102,14 @@ 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, but we switch to + // NNUE eval faster when shuffling or if the material on the board is high. + int r50 = pos.rule50_count(); 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; - - v = classical || strongClassical ? 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 - && ( abs(v) * 16 < NNUEThreshold2 * r50 - || ( pos.opposite_bishops() - && abs(v) * 16 < (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50 - && !(pos.this_thread()->nodes & 0xB)))) - v = adjusted_NNUE(); + bool classical = psq * 5 > (850 + pos.non_pawn_material() / 64) * (5 + r50); + + v = classical ? Evaluation(pos).value() // classical + : adjusted_NNUE(); // NNUE } // Damp down the evaluation linearly when shuffling @@ -1142,7 +1126,7 @@ Value Eval::evaluate(const Position& pos) { /// descriptions and values of each evaluation term. Useful for debugging. /// Trace scores are from white's point of view -std::string Eval::trace(const Position& pos) { +std::string Eval::trace(Position& pos) { if (pos.checkers()) return "Final evaluation: none (in check)"; @@ -1154,44 +1138,53 @@ std::string Eval::trace(const Position& pos) { std::memset(scores, 0, sizeof(scores)); - pos.this_thread()->contempt = SCORE_ZERO; // Reset any dynamic contempt + pos.this_thread()->trend = SCORE_ZERO; // Reset any dynamic contempt v = Evaluation(pos).value(); ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2) - << " Term | White | Black | Total \n" - << " | MG EG | MG EG | MG EG \n" - << " ------------+-------------+-------------+------------\n" - << " Material | " << Term(MATERIAL) - << " Imbalance | " << Term(IMBALANCE) - << " Pawns | " << Term(PAWN) - << " Knights | " << Term(KNIGHT) - << " Bishops | " << Term(BISHOP) - << " Rooks | " << Term(ROOK) - << " Queens | " << Term(QUEEN) - << " Mobility | " << Term(MOBILITY) - << " King safety | " << Term(KING) - << " Threats | " << Term(THREAT) - << " Passed | " << Term(PASSED) - << " Space | " << Term(SPACE) - << " Winnable | " << Term(WINNABLE) - << " ------------+-------------+-------------+------------\n" - << " Total | " << Term(TOTAL); + << " Contributing terms for the classical eval:\n" + << "+------------+-------------+-------------+-------------+\n" + << "| Term | White | Black | Total |\n" + << "| | MG EG | MG EG | MG EG |\n" + << "+------------+-------------+-------------+-------------+\n" + << "| Material | " << Term(MATERIAL) + << "| Imbalance | " << Term(IMBALANCE) + << "| Pawns | " << Term(PAWN) + << "| Knights | " << Term(KNIGHT) + << "| Bishops | " << Term(BISHOP) + << "| Rooks | " << Term(ROOK) + << "| Queens | " << Term(QUEEN) + << "| Mobility | " << Term(MOBILITY) + << "|King safety | " << Term(KING) + << "| Threats | " << Term(THREAT) + << "| Passed | " << Term(PASSED) + << "| Space | " << Term(SPACE) + << "| Winnable | " << Term(WINNABLE) + << "+------------+-------------+-------------+-------------+\n" + << "| Total | " << Term(TOTAL) + << "+------------+-------------+-------------+-------------+\n"; - v = pos.side_to_move() == WHITE ? v : -v; + if (Eval::useNNUE) + ss << '\n' << NNUE::trace(pos) << '\n'; - ss << "\nClassical evaluation: " << to_cp(v) << " (white side)\n"; + ss << std::showpoint << std::showpos << std::fixed << std::setprecision(2) << std::setw(15); + v = pos.side_to_move() == WHITE ? v : -v; + ss << "\nClassical evaluation " << to_cp(v) << " (white side)\n"; if (Eval::useNNUE) { - v = NNUE::evaluate(pos); + v = NNUE::evaluate(pos, false); v = pos.side_to_move() == WHITE ? v : -v; - ss << "\nNNUE evaluation: " << to_cp(v) << " (white side)\n"; + ss << "NNUE evaluation " << to_cp(v) << " (white side)\n"; } v = evaluate(pos); v = pos.side_to_move() == WHITE ? v : -v; - ss << "\nFinal evaluation: " << to_cp(v) << " (white side)\n"; + ss << "Final evaluation " << to_cp(v) << " (white side)"; + if (Eval::useNNUE) + ss << " [with scaled NNUE, hybrid, ...]"; + ss << "\n"; return ss.str(); }