Tempeltize material imbalance
authorMarco Costalba <mcostalba@gmail.com>
Mon, 11 Apr 2011 09:32:55 +0000 (11:32 +0200)
committerMarco Costalba <mcostalba@gmail.com>
Mon, 11 Apr 2011 11:35:54 +0000 (12:35 +0100)
Speedup of almost 1%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/material.cpp
src/material.h
src/pawns.cpp
src/pawns.h

index cc90c2f..796153e 100644 (file)
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-
-////
-//// Includes
-////
-
 #include <cassert>
 #include <cstring>
 #include <map>
 
 using namespace std;
 
-
-////
-//// Local definitions
-////
-
 namespace {
 
   // Values modified by Joona Kiiski
@@ -77,7 +67,7 @@ namespace {
           && pos.non_pawn_material(Us)   >= RookValueMidgame;
   }
 
-  template<Color Us> bool is_KBPsK(const Position& pos) {
+  template<Color Us> bool is_KBPsKs(const Position& pos) {
     return   pos.non_pawn_material(Us)   == BishopValueMidgame
           && pos.piece_count(Us, BISHOP) == 1
           && pos.piece_count(Us, PAWN)   >= 1;
@@ -94,10 +84,6 @@ namespace {
 }
 
 
-////
-//// Classes
-////
-
 /// EndgameFunctions class stores endgame evaluation and scaling functions
 /// in two std::map. Because STL library is not guaranteed to be thread
 /// safe even for read access, the maps, although with identical content,
@@ -128,29 +114,11 @@ template<> const EFMap& EndgameFunctions::get<EF>() const { return maps.first; }
 template<> const SFMap& EndgameFunctions::get<SF>() const { return maps.second; }
 
 
-////
-//// Functions
-////
+/// MaterialInfoTable c'tor and d'tor allocate and free the space for EndgameFunctions
 
 MaterialInfoTable::MaterialInfoTable() { funcs = new EndgameFunctions(); }
 MaterialInfoTable::~MaterialInfoTable() { delete funcs; }
 
-/// MaterialInfoTable::game_phase() calculates the phase given the current
-/// position. Because the phase is strictly a function of the material, it
-/// is stored in MaterialInfo.
-
-Phase MaterialInfoTable::game_phase(const Position& pos) {
-
-  Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
-
-  if (npm >= MidgameLimit)
-      return PHASE_MIDGAME;
-
-  if (npm <= EndgameLimit)
-      return PHASE_ENDGAME;
-
-  return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
-}
 
 /// MaterialInfoTable::get_material_info() takes a position object as input,
 /// computes or looks up a MaterialInfo object, and returns a pointer to it.
@@ -158,7 +126,7 @@ Phase MaterialInfoTable::game_phase(const Position& pos) {
 /// is stored there, so we don't have to recompute everything when the
 /// same material configuration occurs again.
 
-MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
+MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) const {
 
   Key key = pos.get_material_key();
   MaterialInfo* mi = find(key);
@@ -169,10 +137,10 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
   if (mi->key == key)
       return mi;
 
-  // Clear the MaterialInfo object, and set its key
+  // Initialize MaterialInfo entry
   memset(mi, 0, sizeof(MaterialInfo));
-  mi->factor[WHITE] = mi->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
   mi->key = key;
+  mi->factor[WHITE] = mi->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
 
   // Store game phase
   mi->gamePhase = MaterialInfoTable::game_phase(pos);
@@ -183,15 +151,19 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
   if ((mi->evaluationFunction = funcs->get<EF>(key)) != NULL)
       return mi;
 
-  if (is_KXK<WHITE>(pos) || is_KXK<BLACK>(pos))
+  if (is_KXK<WHITE>(pos))
   {
-      mi->evaluationFunction = is_KXK<WHITE>(pos) ? &EvaluateKXK[WHITE] : &EvaluateKXK[BLACK];
+      mi->evaluationFunction = &EvaluateKXK[WHITE];
       return mi;
   }
 
-  if (   pos.pieces(PAWN)  == EmptyBoardBB
-      && pos.pieces(ROOK)  == EmptyBoardBB
-      && pos.pieces(QUEEN) == EmptyBoardBB)
+  if (is_KXK<BLACK>(pos))
+  {
+      mi->evaluationFunction = &EvaluateKXK[BLACK];
+      return mi;
+  }
+
+  if (!pos.pieces(PAWN) && !pos.pieces(ROOK) && !pos.pieces(QUEEN))
   {
       // Minor piece endgame with at least one minor piece per side and
       // no pawns. Note that the case KmmK is already handled by KXK.
@@ -222,10 +194,10 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
   // Generic scaling functions that refer to more then one material
   // distribution. Should be probed after the specialized ones.
   // Note that these ones don't return after setting the function.
-  if (is_KBPsK<WHITE>(pos))
+  if (is_KBPsKs<WHITE>(pos))
       mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
 
-  if (is_KBPsK<BLACK>(pos))
+  if (is_KBPsKs<BLACK>(pos))
       mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
 
   if (is_KQKRPs<WHITE>(pos))
@@ -255,85 +227,107 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
       }
   }
 
+  // No pawns makes it difficult to win, even with a material advantage
+  for (Color c = WHITE; c <= BLACK; c++)
+      if (   pos.piece_count(c, PAWN) == 0
+          && pos.non_pawn_material(c) - pos.non_pawn_material(opposite_color(c)) <= BishopValueMidgame)
+      {
+          if (   pos.non_pawn_material(c) == pos.non_pawn_material(opposite_color(c))
+              || pos.non_pawn_material(c) < RookValueMidgame)
+              mi->factor[c] = 0;
+          else
+          {
+              switch (pos.piece_count(c, BISHOP)) {
+              case 2:
+                  mi->factor[c] = 32;
+                  break;
+              case 1:
+                  mi->factor[c] = 12;
+                  break;
+              case 0:
+                  mi->factor[c] = 6;
+                  break;
+              }
+          }
+      }
+
   // Compute the space weight
   if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >=
       2*QueenValueMidgame + 4*RookValueMidgame + 2*KnightValueMidgame)
   {
       int minorPieceCount =  pos.piece_count(WHITE, KNIGHT)
-                           + pos.piece_count(BLACK, KNIGHT)
                            + pos.piece_count(WHITE, BISHOP)
+                           + pos.piece_count(BLACK, KNIGHT)
                            + pos.piece_count(BLACK, BISHOP);
 
       mi->spaceWeight = minorPieceCount * minorPieceCount;
   }
 
-  // Evaluate the material balance
+  // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
+  // for the bishop pair "extended piece", this allow us to be more flexible
+  // in defining bishop pair bonuses.
   const int pieceCount[2][8] = {
   { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT),
     pos.piece_count(WHITE, BISHOP), pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) },
   { pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT),
     pos.piece_count(BLACK, BISHOP), pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } };
 
-  Color c, them;
-  int sign, pt1, pt2, pc;
-  int v, vv, matValue = 0;
+  mi->value = (int16_t)(imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16;
+  return mi;
+}
 
-  for (c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign)
-  {
-    // No pawns makes it difficult to win, even with a material advantage
-    if (   pos.piece_count(c, PAWN) == 0
-        && pos.non_pawn_material(c) - pos.non_pawn_material(opposite_color(c)) <= BishopValueMidgame)
-    {
-        if (   pos.non_pawn_material(c) == pos.non_pawn_material(opposite_color(c))
-            || pos.non_pawn_material(c) < RookValueMidgame)
-            mi->factor[c] = 0;
-        else
-        {
-            switch (pos.piece_count(c, BISHOP)) {
-            case 2:
-                mi->factor[c] = 32;
-                break;
-            case 1:
-                mi->factor[c] = 12;
-                break;
-            case 0:
-                mi->factor[c] = 6;
-                break;
-            }
-        }
-    }
 
-    // Redundancy of major pieces, formula based on Kaufman's paper
-    // "The Evaluation of Material Imbalances in Chess"
-    // http://mywebpages.comcast.net/danheisman/Articles/evaluation_of_material_imbalance.htm
-    if (pieceCount[c][ROOK] >= 1)
-        matValue -= sign * ((pieceCount[c][ROOK] - 1) * RedundantRookPenalty + pieceCount[c][QUEEN] * RedundantQueenPenalty);
+/// MaterialInfoTable::imbalance() calculates imbalance comparing piece count of each
+/// piece type for both colors.
 
-    them = opposite_color(c);
-    v = 0;
+template<Color Us>
+int MaterialInfoTable::imbalance(const int pieceCount[][8]) {
 
-    // Second-degree polynomial material imbalance by Tord Romstad
-    //
-    // We use PIECE_TYPE_NONE as a place holder for the bishop pair "extended piece",
-    // this allow us to be more flexible in defining bishop pair bonuses.
-    for (pt1 = PIECE_TYPE_NONE; pt1 <= QUEEN; pt1++)
-    {
-        pc = pieceCount[c][pt1];
-        if (!pc)
-            continue;
+  const Color Them = (Us == WHITE ? BLACK : WHITE);
 
-        vv = LinearCoefficients[pt1];
+  int pt1, pt2, pc, vv;
+  int value = 0;
 
-        for (pt2 = PIECE_TYPE_NONE; pt2 <= pt1; pt2++)
-            vv +=  pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]
-                 + pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2];
+  // Redundancy of major pieces, formula based on Kaufman's paper
+  // "The Evaluation of Material Imbalances in Chess"
+  if (pieceCount[Us][ROOK] > 0)
+      value -=  RedundantRookPenalty * (pieceCount[Us][ROOK] - 1)
+              + RedundantQueenPenalty * pieceCount[Us][QUEEN];
 
-        v += pc * vv;
-    }
-    matValue += sign * v;
+  // Second-degree polynomial material imbalance by Tord Romstad
+  for (pt1 = PIECE_TYPE_NONE; pt1 <= QUEEN; pt1++)
+  {
+      pc = pieceCount[Us][pt1];
+      if (!pc)
+          continue;
+
+      vv = LinearCoefficients[pt1];
+
+      for (pt2 = PIECE_TYPE_NONE; pt2 <= pt1; pt2++)
+          vv +=  QuadraticCoefficientsSameColor[pt1][pt2] * pieceCount[Us][pt2]
+               + QuadraticCoefficientsOppositeColor[pt1][pt2] * pieceCount[Them][pt2];
+
+      value += pc * vv;
   }
-  mi->value = (int16_t)(matValue / 16);
-  return mi;
+  return value;
+}
+
+
+/// MaterialInfoTable::game_phase() calculates the phase given the current
+/// position. Because the phase is strictly a function of the material, it
+/// is stored in MaterialInfo.
+
+Phase MaterialInfoTable::game_phase(const Position& pos) {
+
+  Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
+
+  if (npm >= MidgameLimit)
+      return PHASE_MIDGAME;
+
+  if (npm <= EndgameLimit)
+      return PHASE_ENDGAME;
+
+  return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
 }
 
 
index 8493015..1a5f110 100644 (file)
@@ -68,10 +68,13 @@ class MaterialInfoTable : public SimpleHash<MaterialInfo, MaterialTableSize> {
 public:
   MaterialInfoTable();
   ~MaterialInfoTable();
-  MaterialInfo* get_material_info(const Position& pos);
+  MaterialInfo* get_material_info(const Position& pos) const;
   static Phase game_phase(const Position& pos);
 
 private:
+  template<Color Us>
+  static int imbalance(const int pieceCount[][8]);
+
   EndgameFunctions* funcs;
 };
 
index 997aa21..59c05c7 100644 (file)
@@ -106,7 +106,7 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
 
 template<Color Us>
 Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
-                                    Bitboard theirPawns, PawnInfo* pi) const {
+                                    Bitboard theirPawns, PawnInfo* pi) {
 
   const BitCountType Max15 = CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15;
   const Color Them = (Us == WHITE ? BLACK : WHITE);
index fbf6df1..fec0395 100644 (file)
@@ -71,7 +71,7 @@ public:
 
 private:
   template<Color Us>
-  Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) const;
+  static Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi);
 };