Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     Texel - A UCI chess engine.
  3.     Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com
  4.  
  5.     This program is free software: you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation, either version 3 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17. */
  18.  
  19. /*
  20.  * transpositionTable.hpp
  21.  *
  22.  *  Created on: Feb 25, 2012
  23.  *      Author: petero
  24.  */
  25.  
  26. #ifndef TRANSPOSITIONTABLE_HPP_
  27. #define TRANSPOSITIONTABLE_HPP_
  28.  
  29. #include "util/util.hpp"
  30. #include "move.hpp"
  31. #include "constants.hpp"
  32. #include "util/alignedAlloc.hpp"
  33.  
  34. #include <vector>
  35.  
  36. class Position;
  37.  
  38. /**
  39.  * Implements the main transposition table using Cuckoo hashing.
  40.  */
  41. class TranspositionTable {
  42. public:
  43.     /** In-memory representation of TT entry. Uses std::atomic for thread safety,
  44.      * but accessed using memory_order_relaxed for maximum performance. */
  45.     struct TTEntryStorage {
  46.         std::atomic<U64> key;
  47.         std::atomic<U64> data;
  48.         TTEntryStorage();
  49.         TTEntryStorage(const TTEntryStorage& a);
  50.     };
  51.     static_assert(sizeof(TTEntryStorage) == 16, "TTEntryStorage size wrong");
  52.  
  53.     /** A local copy of a transposition table entry. */
  54.     class TTEntry {
  55.     public:
  56.         /** Set type to T_EMPTY. */
  57.         void clear();
  58.  
  59.         /** Store in transposition table, encoded for thread safety. */
  60.         void store(TTEntryStorage& ent);
  61.  
  62.         /** Load from transposition table, decode the thread safety encoding. */
  63.         void load(const TTEntryStorage& ent);
  64.  
  65.         /** Return true if this object is more valuable than the other, false otherwise. */
  66.         bool betterThan(const TTEntry& other, int currGen) const;
  67.  
  68.         U64 getKey() const;
  69.         void setKey(U64 k);
  70.  
  71.         void getMove(Move& m) const;
  72.  
  73.         void setMove(const Move& m);
  74.  
  75.         /** Get the score from the hash entry and convert from "mate in x" to "mate at ply". */
  76.         int getScore(int ply) const;
  77.  
  78.         /** Convert score from "mate at ply" to "mate in x" and store in hash entry. */
  79.         void setScore(int score, int ply);
  80.  
  81.         /** Return true if entry is good enough to cut off this branch in the search tree. */
  82.         bool isCutOff(int alpha, int beta, int ply, int depth) const;
  83.  
  84.         int getDepth() const;
  85.         void setDepth(int d);
  86.         int getGeneration() const;
  87.         void setGeneration(int g);
  88.         int getType() const;
  89.         void setType(int t);
  90.         int getEvalScore() const;
  91.         void setEvalScore(int s);
  92.  
  93.     private:
  94.         U64 key;        //  0 64 key         Zobrist hash key
  95.         U64 data;       //  0 16 move        from + (to<<6) + (promote<<12)
  96.                         // 16 16 score       Score from search
  97.                         // 32 10 depth       Search depth
  98.                         // 42  4 generation  Increase when OTB position changes
  99.                         // 46  2 type        exact score, lower bound, upper bound
  100.                         // 48 16 evalScore   Score from static evaluation
  101.  
  102.         void setBits(int first, int size, unsigned int value);
  103.         unsigned int getBits(int first, int size) const;
  104.     };
  105.  
  106.     /** Constructor. Creates an empty transposition table with numEntries slots. */
  107.     TranspositionTable(int log2Size);
  108.  
  109.     void reSize(int log2Size);
  110.  
  111.     /** Insert an entry in the hash table. */
  112.     void insert(U64 key, const Move& sm, int type, int ply, int depth, int evalScore);
  113.  
  114.     /** Retrieve an entry from the hash table corresponding to position with zobrist key "key". */
  115.     void probe(U64 key, TTEntry& result);
  116.  
  117.     /** Prefetch cache line. */
  118.     void prefetch(U64 key);
  119.  
  120.     /**
  121.      * Increase hash table generation. This means that subsequent inserts will be considered
  122.      * more valuable than the entries currently present in the hash table.
  123.      */
  124.     void nextGeneration();
  125.  
  126.     /** Clear the transposition table. */
  127.     void clear();
  128.  
  129.     /** Extract a list of PV moves, starting from "rootPos" and first move "mFirst". */
  130.     void extractPVMoves(const Position& rootPos, const Move& mFirst, std::vector<Move>& pv);
  131.  
  132.     /** Extract the PV starting from posIn, using hash entries, both exact scores and bounds. */
  133.     std::string extractPV(const Position& posIn);
  134.  
  135.     /** Print hash table statistics. */
  136.     void printStats() const;
  137.  
  138. private:
  139.     /** Get position in hash table given zobrist key. */
  140.     size_t getIndex(U64 key) const;
  141.  
  142.     /** Get part of zobrist key to store in hash table. */
  143.     static U64 getStoredKey(U64 key);
  144.  
  145.  
  146.     vector_aligned<TTEntryStorage> table;
  147.     U8 generation;
  148. };
  149.  
  150.  
  151. inline
  152. TranspositionTable::TTEntryStorage::TTEntryStorage() {
  153.     key.store(0, std::memory_order_relaxed);
  154.     data.store(0, std::memory_order_relaxed);
  155. }
  156.  
  157. inline
  158. TranspositionTable::TTEntryStorage::TTEntryStorage(const TTEntryStorage& a) {
  159.     key.store(a.key.load(std::memory_order_relaxed), std::memory_order_relaxed);
  160.     data.store(a.data.load(std::memory_order_relaxed), std::memory_order_relaxed);
  161. }
  162.  
  163.  
  164. inline void
  165. TranspositionTable::TTEntry::clear() {
  166.     key = 0;
  167.     data = 0;
  168.     static_assert(TType::T_EMPTY == 0, "type not set to T_EMPTY");
  169. }
  170.  
  171. inline void
  172. TranspositionTable::TTEntry::store(TTEntryStorage& ent) {
  173.     ent.key.store(key ^ data, std::memory_order_relaxed);
  174.     ent.data.store(data, std::memory_order_relaxed);
  175. }
  176.  
  177. inline void
  178. TranspositionTable::TTEntry::load(const TTEntryStorage& ent) {
  179.     key = ent.key.load(std::memory_order_relaxed);
  180.     data = ent.data.load(std::memory_order_relaxed);
  181.     key ^= data;
  182. }
  183.  
  184. inline bool
  185. TranspositionTable::TTEntry::betterThan(const TTEntry& other, int currGen) const {
  186.     if ((getGeneration() == currGen) != (other.getGeneration() == currGen))
  187.         return getGeneration() == currGen;   // Old entries are less valuable
  188.     if ((getType() == TType::T_EXACT) != (other.getType() == TType::T_EXACT))
  189.         return getType() == TType::T_EXACT;         // Exact score more valuable than lower/upper bound
  190.     if (getDepth() != other.getDepth())
  191.         return getDepth() > other.getDepth();     // Larger depth is more valuable
  192.     return false;   // Otherwise, pretty much equally valuable
  193. }
  194.  
  195. inline U64
  196. TranspositionTable::TTEntry::getKey() const {
  197.     return key;
  198. }
  199.  
  200. inline void
  201. TranspositionTable::TTEntry::setKey(U64 k) {
  202.     key = k;
  203. }
  204.  
  205. inline void
  206. TranspositionTable::TTEntry::getMove(Move& m) const {
  207.     int move = getBits(0, 16);
  208.     m.setMove(move & 63, (move >> 6) & 63, (move >> 12) & 15, m.score());
  209. }
  210.  
  211. inline void
  212. TranspositionTable::TTEntry::setMove(const Move& m) {
  213.     int move = (short)(m.from() + (m.to() << 6) + (m.promoteTo() << 12));
  214.     setBits(0, 16, move);
  215. }
  216.  
  217. inline int
  218. TranspositionTable::TTEntry::getScore(int ply) const {
  219.     int sc = (S16)getBits(16, 16);
  220.     if (SearchConst::isWinScore(sc))
  221.         sc -= ply;
  222.     else if (SearchConst::isLoseScore(sc))
  223.         sc += ply;
  224.     return sc;
  225. }
  226.  
  227. inline void
  228. TranspositionTable::TTEntry::setScore(int score, int ply) {
  229.     if (SearchConst::isWinScore(score))
  230.         score += ply;
  231.     else if (SearchConst::isLoseScore(score))
  232.         score -= ply;
  233.     setBits(16, 16, score);
  234. }
  235.  
  236. inline bool
  237. TranspositionTable::TTEntry::isCutOff(int alpha, int beta, int ply, int depth) const {
  238.     using namespace SearchConst;
  239.     const int score = getScore(ply);
  240.     const int plyToMate = MATE0 - std::abs(getScore(0));
  241.     const int eDepth = getDepth();
  242.     const int eType = getType();
  243.     if ((eDepth >= depth) || (eDepth >= plyToMate*plyScale)) {
  244.         if ( (eType == TType::T_EXACT) ||
  245.             ((eType == TType::T_GE) && (score >= beta)) ||
  246.             ((eType == TType::T_LE) && (score <= alpha)))
  247.             return true;
  248.     }
  249.     return false;
  250. }
  251.  
  252. inline int
  253. TranspositionTable::TTEntry::getDepth() const {
  254.     return getBits(32, 10);
  255. }
  256.  
  257. inline void
  258. TranspositionTable::TTEntry::setDepth(int d) {
  259.     setBits(32, 10, d);
  260. }
  261.  
  262. inline int
  263. TranspositionTable::TTEntry::getGeneration() const {
  264.     return getBits(42, 4);
  265. }
  266.  
  267. inline void
  268. TranspositionTable::TTEntry::setGeneration(int g) {
  269.     setBits(42, 4, g);
  270. }
  271.  
  272. inline int
  273. TranspositionTable::TTEntry::getType() const {
  274.     return getBits(46, 2);
  275. }
  276.  
  277. inline void
  278. TranspositionTable::TTEntry::setType(int t) {
  279.     setBits(46, 2, t);
  280. }
  281.  
  282. inline int
  283. TranspositionTable::TTEntry::getEvalScore() const {
  284.     return (S16)getBits(48, 16);
  285. }
  286.  
  287. inline void
  288. TranspositionTable::TTEntry::setEvalScore(int s) {
  289.     setBits(48, 16, s);
  290. }
  291.  
  292. inline void
  293. TranspositionTable::TTEntry::setBits(int first, int size, unsigned int value) {
  294.     U64 mask = ((1ULL << size) - 1) << first;
  295.     data = (data & ~mask) | (((U64)value << first) & mask);
  296. }
  297.  
  298. inline unsigned int
  299. TranspositionTable::TTEntry::getBits(int first, int size) const {
  300.     U64 sizeMask = ((1ULL << size) - 1);
  301.     return (unsigned int)((data >> first) & sizeMask);
  302. }
  303.  
  304.  
  305. inline size_t
  306. TranspositionTable::getIndex(U64 key) const {
  307.     return (size_t)(key & (table.size() - 1));
  308. }
  309.  
  310. inline U64
  311. TranspositionTable::getStoredKey(U64 key) {
  312.     return key;
  313. }
  314.  
  315. inline TranspositionTable::TranspositionTable(int log2Size) {
  316.     reSize(log2Size);
  317. }
  318.  
  319. inline void
  320. TranspositionTable::probe(U64 key, TTEntry& result) {
  321.     size_t idx0 = getIndex(key);
  322.     U64 key2 = getStoredKey(key);
  323.     TTEntry ent;
  324.     ent.load(table[idx0]);
  325.     if (ent.getKey() == key2) {
  326.         if (ent.getGeneration() != generation) {
  327.             ent.setGeneration(generation);
  328.             ent.store(table[idx0]);
  329.         }
  330.         result = ent;
  331.         return;
  332.     }
  333.     size_t idx1 = idx0 ^ 1;
  334.     ent.load(table[idx1]);
  335.     if (ent.getKey() == key2) {
  336.         if (ent.getGeneration() != generation) {
  337.             ent.setGeneration(generation);
  338.             ent.store(table[idx1]);
  339.         }
  340.         result = ent;
  341.         return;
  342.     }
  343.     result.setType(TType::T_EMPTY);
  344. }
  345.  
  346. inline void
  347. TranspositionTable::prefetch(U64 key) {
  348. #ifdef HAS_PREFETCH
  349.     size_t idx0 = getIndex(key);
  350.     __builtin_prefetch(&table[idx0]);
  351. #endif
  352. }
  353.  
  354. inline void
  355. TranspositionTable::nextGeneration() {
  356.     generation = (generation + 1) & 15;
  357. }
  358.  
  359. inline void
  360. TranspositionTable::clear() {
  361.     TTEntry ent;
  362.     ent.clear();
  363.     for (size_t i = 0; i < table.size(); i++)
  364.         ent.store(table[i]);
  365. }
  366.  
  367. #endif /* TRANSPOSITIONTABLE_HPP_ */
  368.