From c88eebc98905b47077ef2b35b35ea5705d448d4f Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 11 Apr 2011 11:32:55 +0200 Subject: [PATCH] Tempeltize material imbalance Speedup of almost 1% No functional change. Signed-off-by: Marco Costalba --- src/material.cpp | 190 +++++++++++++++++++++++------------------------ src/material.h | 5 +- src/pawns.cpp | 2 +- src/pawns.h | 2 +- 4 files changed, 98 insertions(+), 101 deletions(-) diff --git a/src/material.cpp b/src/material.cpp index cc90c2f9..796153e8 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -17,11 +17,6 @@ along with this program. If not, see . */ - -//// -//// Includes -//// - #include #include #include @@ -30,11 +25,6 @@ using namespace std; - -//// -//// Local definitions -//// - namespace { // Values modified by Joona Kiiski @@ -77,7 +67,7 @@ namespace { && pos.non_pawn_material(Us) >= RookValueMidgame; } - template bool is_KBPsK(const Position& pos) { + template 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() const { return maps.first; } template<> const SFMap& EndgameFunctions::get() 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(key)) != NULL) return mi; - if (is_KXK(pos) || is_KXK(pos)) + if (is_KXK(pos)) { - mi->evaluationFunction = is_KXK(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(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(pos)) + if (is_KBPsKs(pos)) mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE]; - if (is_KBPsK(pos)) + if (is_KBPsKs(pos)) mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK]; if (is_KQKRPs(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(pieceCount) - imbalance(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 +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)); } diff --git a/src/material.h b/src/material.h index 84930157..1a5f1105 100644 --- a/src/material.h +++ b/src/material.h @@ -68,10 +68,13 @@ class MaterialInfoTable : public SimpleHash { 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 + static int imbalance(const int pieceCount[][8]); + EndgameFunctions* funcs; }; diff --git a/src/pawns.cpp b/src/pawns.cpp index 997aa214..59c05c73 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -106,7 +106,7 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const { template 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); diff --git a/src/pawns.h b/src/pawns.h index fbf6df12..fec0395f 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -71,7 +71,7 @@ public: private: template - 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); }; -- 2.39.2