X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fevaluate.cpp;h=3b6cbbcd8a644d47fb599107a44a565e7276533d;hb=b60f9cc4515cdfb657a0166abb29a60257cc59e1;hp=536137948575c8c4c34b2a103bc453ada91defb6;hpb=85f8ee6199f8578fbc082fc0f37e1985813e637a;p=stockfish diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 53613794..3b6cbbcd 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-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 @@ -159,7 +159,7 @@ namespace Trace { Score scores[TERM_NB][COLOR_NB]; - double to_cp(Value v) { return double(v) / PawnValueEg; } + double to_cp(Value v) { return double(v) / UCI::NormalizeToPawnValue; } void add(int idx, Color c, Score s) { scores[idx][c] = s; @@ -981,7 +981,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()->trend; + Score score = pos.psq_score() + me->imbalance(); // Probe the pawn hash table pe = Pawns::probe(pos); @@ -1042,38 +1042,6 @@ make_v: return v; } - - /// Fisher Random Chess: correction for cornered bishops, to fix chess960 play with NNUE - - Value fix_FRC(const Position& pos) { - - constexpr Bitboard Corners = 1ULL << SQ_A1 | 1ULL << SQ_H1 | 1ULL << SQ_A8 | 1ULL << SQ_H8; - - if (!(pos.pieces(BISHOP) & Corners)) - return VALUE_ZERO; - - int correction = 0; - - if ( pos.piece_on(SQ_A1) == W_BISHOP - && pos.piece_on(SQ_B2) == W_PAWN) - correction -= CorneredBishop; - - if ( pos.piece_on(SQ_H1) == W_BISHOP - && pos.piece_on(SQ_G2) == W_PAWN) - correction -= CorneredBishop; - - if ( pos.piece_on(SQ_A8) == B_BISHOP - && pos.piece_on(SQ_B7) == B_PAWN) - correction += CorneredBishop; - - if ( pos.piece_on(SQ_H8) == B_BISHOP - && pos.piece_on(SQ_G7) == B_PAWN) - correction += CorneredBishop; - - return pos.side_to_move() == WHITE ? Value(3 * correction) - : -Value(3 * correction); - } - } // namespace Eval @@ -1083,50 +1051,48 @@ make_v: Value Eval::evaluate(const Position& pos, int* complexity) { Value v; - Color stm = pos.side_to_move(); Value psq = pos.psq_eg_stm(); - // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, - // but we switch to NNUE during long shuffling or with high material on the board. - bool useClassical = (pos.this_thread()->depth > 9 || pos.count() > 7) - && abs(psq) * 5 > (856 + pos.non_pawn_material() / 64) * (10 + pos.rule50_count()); - - // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, - // but we switch to NNUE during long shuffling or with high material on the board. - if (!useNNUE || useClassical) - { - v = Evaluation(pos).value(); - useClassical = abs(v) >= 297; - } - // If result of a classical evaluation is much lower than threshold fall back to NNUE - if (useNNUE && !useClassical) + // 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() > 7 && abs(psq) > 1760); + + if (useClassical) + v = Evaluation(pos).value(); + else { - int nnueComplexity; - int scale = 1064 + 106 * pos.non_pawn_material() / 5120; - Value optimism = pos.this_thread()->optimism[stm]; + int nnueComplexity; + int scale = 1076 + 96 * pos.non_pawn_material() / 5120; + + Color stm = pos.side_to_move(); + Value optimism = pos.this_thread()->optimism[stm]; + + Value nnue = NNUE::evaluate(pos, true, &nnueComplexity); - Value nnue = NNUE::evaluate(pos, true, &nnueComplexity); - // Blend nnue complexity with (semi)classical complexity - nnueComplexity = (104 * nnueComplexity + 131 * abs(nnue - psq)) / 256; - if (complexity) // Return hybrid NNUE complexity to caller - *complexity = nnueComplexity; + // Blend nnue complexity with (semi)classical complexity + nnueComplexity = ( 412 * nnueComplexity + + 428 * abs(psq - nnue) + + (optimism > 0 ? int(optimism) * int(psq - nnue) : 0) + ) / 1024; - optimism = optimism * (269 + nnueComplexity) / 256; - v = (nnue * scale + optimism * (scale - 754)) / 1024; + // Return hybrid NNUE complexity to caller + if (complexity) + *complexity = nnueComplexity; - if (pos.is_chess960()) - v += fix_FRC(pos); + optimism = optimism * (278 + nnueComplexity) / 256; + v = (nnue * scale + optimism * (scale - 755)) / 1024; } // Damp down the evaluation linearly when shuffling - v = v * (195 - pos.rule50_count()) / 211; + v = v * (197 - 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); + if (complexity && useClassical) + *complexity = abs(v - psq); return v; } @@ -1149,8 +1115,6 @@ std::string Eval::trace(Position& pos) { std::memset(scores, 0, sizeof(scores)); // Reset any global variable used in eval - pos.this_thread()->depth = 0; - pos.this_thread()->trend = SCORE_ZERO; pos.this_thread()->bestValue = VALUE_ZERO; pos.this_thread()->optimism[WHITE] = VALUE_ZERO; pos.this_thread()->optimism[BLACK] = VALUE_ZERO;