Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 6 Jun 2021 17:10:05 +0000 (19:10 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 6 Jun 2021 17:10:05 +0000 (19:10 +0200)
bench: 5068534

1  2 
src/evaluate.cpp
src/nnue/features/half_kp.cpp
src/search.cpp

@@@ -1598,24 -1104,26 +1598,27 @@@ Value Eval::evaluate(const Position& po
           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. We also introduce
+       // a small probability of using the classical eval when PSQ imbalance is small.
        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));
 +      bool  pure = !pos.check_counting();
 +      bool  largePsq = psq * 16 > (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50 && !pure;
 +      bool  classical = largePsq || (psq > PawnValueMg / 4 && !(pos.this_thread()->nodes & 0xB) && !pure);
  
        // 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<PAWN>() < 2;
+       // One critical case is the draw for bishop + A/H file pawn vs naked king.
+       bool lowPieceEndgame =   pos.non_pawn_material() == BishopValueMg
+                             || (pos.non_pawn_material() < 2 * RookValueMg && pos.count<PAWN>() < 2);
  
-       v = classical || strongClassical ? Evaluation<NO_TRACE>(pos).value() : adjusted_NNUE();
+       v = classical || lowPieceEndgame ? Evaluation<NO_TRACE>(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
+       // 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
+           && !lowPieceEndgame
            && (   abs(v) * 16 < NNUEThreshold2 * r50
                || (   pos.opposite_bishops()
                    && abs(v) * 16 < (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50
@@@ -52,9 -47,27 +52,27 @@@ namespace Stockfish::Eval::NNUE::Featur
      }
    }
  
-   // Get a list of indices for recently changed features
+   // AppendChangedIndices() : get a list of indices for recently changed features
+   // IMPORTANT: The `pos` in this function is pretty much useless as it
+   // is not always the position the features are updated to. The feature
+   // transformer code right now can update multiple accumulators per move,
+   // but since Stockfish only keeps the full state of the current leaf
+   // search position it is not possible to always pass here the position for
+   // which the accumulator is being updated. Therefore the only thing that
+   // can be reliably extracted from `pos` is the king square for the king
+   // of the `perspective` color (note: not even the other king's square will
+   // match reality in all cases, this is also the reason why `dp` is passed
+   // as a parameter and not extracted from pos.state()). This is of particular
+   // problem for future nets with other feature sets, where updating the active
+   // feature might require more information from the intermediate positions. In
+   // this case the only easy solution is to remove the multiple updates from
+   // the feature transformer update code and only update the accumulator for
+   // the current leaf position (the position after the move).
    template <Side AssociatedKing>
 -  void HalfKP<AssociatedKing>::AppendChangedIndices(
 +  void HalfKPChess<AssociatedKing>::AppendChangedIndices(
        const Position& pos, const DirtyPiece& dp, Color perspective,
        IndexList* removed, IndexList* added) {
  
diff --cc src/search.cpp
@@@ -1301,17 -1158,6 +1301,12 @@@ moves_loop: // When in check, search st
                 && (pos.is_discovered_check_on_king(~us, move) || pos.see_ge(move)))
            extension = 1;
  
-       // Last captures extension
-       else if (   PieceValue[EG][pos.captured_piece()] > PawnValueEg
-                && pos.non_pawn_material() <= 2 * RookValueMg)
-           extension = 1;
 +      // Losing chess capture extension
 +      else if (    pos.must_capture()
 +               &&  pos.capture(move)
 +               &&  (ss->inCheck || MoveList<CAPTURES>(pos).size() == 1))
 +          extension = 1;
 +
        // Add extension to new depth
        newDepth += extension;