- /* 
-     Texel - A UCI chess engine. 
-     Copyright (C) 2012-2013  Peter Ă–sterlund, peterosterlund2@gmail.com 
-   
-     This program is free software: you can redistribute it and/or modify 
-     it under the terms of the GNU General Public License as published by 
-     the Free Software Foundation, either version 3 of the License, or 
-     (at your option) any later version. 
-   
-     This program is distributed in the hope that it will be useful, 
-     but WITHOUT ANY WARRANTY; without even the implied warranty of 
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-     GNU General Public License for more details. 
-   
-     You should have received a copy of the GNU General Public License 
-     along with this program.  If not, see <http://www.gnu.org/licenses/>. 
- */ 
-   
- /* 
-  * treeLogger.hpp 
-  * 
-  *  Created on: Feb 25, 2012 
-  *      Author: petero 
-  */ 
-   
- #ifndef TREELOGGER_HPP_ 
- #define TREELOGGER_HPP_ 
-   
- #include "util/util.hpp" 
- #include "move.hpp" 
- #include "parallel.hpp" 
-   
- #include <vector> 
- #include <type_traits> 
- #include <utility> 
- #include <cstring> 
- #include <fstream> 
-   
-   
- class TreeLoggerWriter; 
- class TreeLoggerWriterDummy; 
-   
- /** Change to TreeLoggerWriter to enable tree logging. */ 
- using TreeLogger = TreeLoggerWriterDummy; 
-   
-   
- class Position; 
-   
- namespace Serializer { 
-     template <typename Type> 
-     typename std::enable_if<std::is_integral<Type>::value, U8*>::type 
-     putBytes(U8* buffer, Type value) { 
-         int s = sizeof(value); 
-         memcpy(buffer, &value, s); 
-         return buffer + s; 
-     } 
-   
-     template <int N> 
-     static U8* serialize(U8* buffer) { 
-         static_assert(N >= 0, "Buffer too small"); 
-         return buffer; 
-     } 
-   
-     /** Store a sequence of values in a byte buffer. */ 
-     template <int N, typename Type0, typename... Types> 
-     static U8* serialize(U8* buffer, Type0 value0, Types... values) { 
-         const int s = sizeof(Type0); 
-         buffer = putBytes(buffer, value0); 
-         return serialize<N-s>(buffer, values...); 
-     } 
-   
-     template <typename Type> 
-     typename std::enable_if<std::is_integral<Type>::value, const U8*>::type 
-     getBytes(const U8* buffer, Type& value) { 
-         int s = sizeof(value); 
-         memcpy(&value, buffer, s); 
-         return buffer + s; 
-     } 
-   
-     template <int N> 
-     static const U8* deSerialize(const U8* buffer) { 
-         static_assert(N >= 0, "Buffer too small"); 
-         return buffer; 
-     } 
-   
-     /** Retrieve a sequence of values from a byte buffer. */ 
-     template <int N, typename Type0, typename... Types> 
-     static const U8* deSerialize(const U8* buffer, Type0& value0, Types&... values) { 
-         const int s = sizeof(Type0); 
-         buffer = getBytes(buffer, value0); 
-         return deSerialize<N-s>(buffer, values...); 
-     } 
- } 
-   
- /** Base class for logging search trees to file. */ 
- class TreeLoggerBase { 
-     friend class TreeLoggerTest; 
- protected: 
-     /** 
-      * Rules for the log file format 
-      * - A log file contains a search tree dump for one thread. 
-      * - The file contains information for 0 or more searches. 
-      * - The log file for thread 0 contains information for a single search. 
-      * - Information for one search tree starts with a Position0 record and 
-      *   ends at the next Position0 record or at the end of the file. 
-      * - A start entry may not have a corresponding end entry. This happens 
-      *   if the search was interrupted. 
-      * - Start and end entries are properly nested (assuming the end entries exist) 
-      *   s1.index < s2.index => e1.index > e2.index 
-      */ 
-   
-     enum class EntryType : U8 { 
-         POSITION_INCOMPLETE, // First entry in file has this type when endIndex 
-                              // has not yet been computed for all StartEntries. 
-         POSITION_PART0,      // Position entry, first part. 
-         POSITION_PART1,      // Position entry, second part. 
-         POSITION_PART2,      // Position entry, third part. 
-         NODE_START,          // Start of a search node. 
-         NODE_END             // End of a search node. 
-     }; 
-   
-     static const U32 endMark = 0xffffffff; 
-   
-     struct Position0 { 
-         U32 nextIndex;     // Index of next position, or endMark for last position. 
-         U64 word0; 
-         U64 word1; 
-   
-         template <int N> U8* serialize(U8 buffer[N]) const { 
-             return Serializer::serialize<N>(buffer, nextIndex, word0, word1); 
-         } 
-         template <int N> void deSerialize(const U8 buffer[N]) { 
-             Serializer::deSerialize<N>(buffer, nextIndex, word0, word1); 
-         } 
-     }; 
-   
-     struct Position1 { 
-         U32 t0Index; 
-         U64 word2; 
-         U64 word3; 
-   
-         template <int N> U8* serialize(U8 buffer[N]) const { 
-             return Serializer::serialize<N>(buffer, t0Index, word2, word3); 
-         } 
-         template <int N> void deSerialize(const U8 buffer[N]) { 
-             Serializer::deSerialize<N>(buffer, t0Index, word2, word3); 
-         } 
-     }; 
-   
-     struct Position2 { 
-         U64 word4; 
-         U8 owningThread; 
-         U8 moveNo; 
-         U32 parentIndex;    // Index in owning threads tree log 
-   
-         template <int N> U8* serialize(U8 buffer[N]) const { 
-             return Serializer::serialize<N>(buffer, word4, owningThread, moveNo, parentIndex); 
-         } 
-         template <int N> void deSerialize(const U8 buffer[N]) { 
-             Serializer::deSerialize<N>(buffer, word4, owningThread, moveNo, parentIndex); 
-         } 
-     }; 
-   
-     struct StartEntry { 
-         U32 endIndex; 
-         U32 parentIndex;    // Points to NODE_START or POSITION_PART0 node. 
-         U16 move; 
-         S16 alpha; 
-         S16 beta; 
-         U8 ply; 
-         U16 depth; 
-         U32 t0Index;        // Current entry in thread 0 
-   
-         Move getMove() const { 
-             Move ret; 
-             ret.setMove(move & 63, (move >> 6) & 63, (move >> 12) & 15, 0); 
-             return ret; 
-         } 
-   
-         template <int N> U8* serialize(U8 buffer[N]) const { 
-             return Serializer::serialize<N>(buffer, endIndex, parentIndex, move, 
-                                             alpha, beta, ply, depth, t0Index); 
-         } 
-         template <int N> void deSerialize(const U8 buffer[N]) { 
-             Serializer::deSerialize<N>(buffer, endIndex, parentIndex, move, 
-                                        alpha, beta, ply, depth, t0Index); 
-         } 
-     }; 
-   
-     struct EndEntry { 
-         U32 startIndex; 
-         S16 score; 
-         U8 scoreType; 
-         S16 evalScore; 
-         U64 hashKey; 
-         U32 t0Index;        // Current entry in thread 0 
-   
-         template <int N> U8* serialize(U8 buffer[N]) const { 
-             return Serializer::serialize<N>(buffer, startIndex, score, scoreType, 
-                                             evalScore, hashKey, t0Index); 
-         } 
-         template <int N> void deSerialize(const U8 buffer[N]) { 
-             Serializer::deSerialize<N>(buffer, startIndex, score, scoreType, 
-                                        evalScore, hashKey, t0Index); 
-         } 
-     }; 
-   
-     struct Entry { 
-         EntryType type; 
-         union { 
-             Position0 p0; 
-             Position1 p1; 
-             Position2 p2; 
-             StartEntry se; 
-             EndEntry ee; 
-         }; 
-   
-         static const int bufSize = 22; 
-         using Buffer = U8[bufSize]; 
-   
-         void serialize(U8 buffer[bufSize]) const { 
-             U8* ptr = buffer; 
-             using UType = std::underlying_type<EntryType>::type; 
-             const int su = sizeof(UType); 
-             UType uType = static_cast<UType>(type); 
-             ptr = Serializer::serialize<bufSize>(ptr, uType); 
-             switch (type) { 
-             case EntryType::POSITION_INCOMPLETE: p0.serialize<bufSize-su>(ptr); break; 
-             case EntryType::POSITION_PART0:      p0.serialize<bufSize-su>(ptr); break; 
-             case EntryType::POSITION_PART1:      p1.serialize<bufSize-su>(ptr); break; 
-             case EntryType::POSITION_PART2:      p2.serialize<bufSize-su>(ptr); break; 
-             case EntryType::NODE_START:          se.serialize<bufSize-su>(ptr); break; 
-             case EntryType::NODE_END:            ee.serialize<bufSize-su>(ptr); break; 
-             } 
-         } 
-   
-         void deSerialize(U8 buffer[bufSize]) { 
-             const U8* ptr = buffer; 
-             using UType = std::underlying_type<EntryType>::type; 
-             const int su = sizeof(UType); 
-             UType uType; 
-             ptr = Serializer::deSerialize<bufSize>(ptr, uType); 
-             type = static_cast<EntryType>(uType); 
-             switch (type) { 
-             case EntryType::POSITION_INCOMPLETE: p0.deSerialize<bufSize-su>(ptr); break; 
-             case EntryType::POSITION_PART0:      p0.deSerialize<bufSize-su>(ptr); break; 
-             case EntryType::POSITION_PART1:      p1.deSerialize<bufSize-su>(ptr); break; 
-             case EntryType::POSITION_PART2:      p2.deSerialize<bufSize-su>(ptr); break; 
-             case EntryType::NODE_START:          se.deSerialize<bufSize-su>(ptr); break; 
-             case EntryType::NODE_END:            ee.deSerialize<bufSize-su>(ptr); break; 
-             } 
-         } 
-     }; 
-   
-     Entry entry; 
-     U8 entryBuffer[Entry::bufSize]; 
- }; 
-   
- /** Writer class for logging search trees to file. */ 
- class TreeLoggerWriter : public TreeLoggerBase { 
- public: 
-     /** Constructor. */ 
-     TreeLoggerWriter(); 
-   
-     /** Destructor. */ 
-     ~TreeLoggerWriter(); 
-   
-     /** Open log file for writing. */ 
-     void open(const std::string& filename, ParallelData& pd, int threadNo); 
-   
-     /** Flush write cache and close log file. */ 
-     void close(); 
-   
-     /** Return true if log file is opened. */ 
-     bool isOpened() const; 
-   
-     /** Log information for new position to search. 
-      * Return index of position entry. */ 
-     U64 logPosition(const Position& pos, int owningThread, U64 parentIndex, int moveNo); 
-   
-     /** 
-      * Log information when entering a search node. 
-      * @param parentId     Index of parent node. 
-      * @param m            Move made to go from parent node to this node 
-      * @param alpha        Search parameter 
-      * @param beta         Search parameter 
-      * @param ply          Search parameter 
-      * @param depth        Search parameter 
-      * @return node index 
-      */ 
-     U64 logNodeStart(U64 parentIndex, const Move& m, int alpha, int beta, int ply, int depth); 
-   
-     /** 
-      * Log information when leaving a search node. 
-      * @param startIndex Pointer to corresponding start node entry. 
-      * @param score      Computed score for this node. 
-      * @param scoreType  See TranspositionTable, T_EXACT, T_GE, T_LE. 
-      * @param evalScore  Score returned by evaluation function at this node, if known. 
-      * @return node index 
-      */ 
-     U64 logNodeEnd(U64 startIndex, int score, int scoreType, int evalScore, U64 hashKey); 
-   
- private: 
-     /** Write position entries to end of file. */ 
-     void writePosition(const Position& pos, int owningThread, U64 parentIndex, int moveNo); 
-   
-     /** Write entry to end of file. Uses internal buffering, flushed in close(). */ 
-     void appendEntry(const Entry& entry); 
-   
-   
-     bool opened; 
-     std::ofstream os; 
-     U64 nextIndex; 
-   
-     ParallelData* pd; 
-     int threadNo; 
-   
-     static const int writeCacheSize = 1024; 
-     U8 writeCache[Entry::bufSize * writeCacheSize]; 
-     int nInWriteCache; 
- }; 
-   
- /** Dummy version of TreeLoggerWriter. */ 
- class TreeLoggerWriterDummy { 
- public: 
-     TreeLoggerWriterDummy() { } 
-     void open(const std::string& filename, ParallelData& pd, int threadNo) { } 
-     void close() { } 
-     bool isOpened() const { return false; } 
-     U64 logPosition(const Position& pos, int owningThread, U64 parentIndex, int moveNo) { return 0; } 
-     U64 logNodeStart(U64 parentIndex, const Move& m, int alpha, int beta, int ply, int depth) { return 0; } 
-     U64 logNodeEnd(U64 startIndex, int score, int scoreType, int evalScore, U64 hashKey) { return 0; } 
- }; 
-   
- /** 
-  * Reader/analysis class for a search tree dumped to a file. 
-  */ 
- class TreeLoggerReader : public TreeLoggerBase { 
- public: 
-     /** Constructor. */ 
-     TreeLoggerReader(const std::string& filename); 
-   
-     void close(); 
-   
-     /** Main loop of the interactive tree browser. */ 
-     static void main(const std::string& filename); 
-   
- private: 
-     /** Compute endIndex for all StartNode entries. */ 
-     void computeForwardPointers(); 
-   
-     /** Write forward pointer data to disk. */ 
-     void flushForwardPointerData(std::vector<std::pair<U64,U64>>& toWrite); 
-   
-     /** Get root node information. */ 
-     void getRootNode(U64 index, Position& pos); 
-     void getRootNode(U64 index, Position& pos, int& owningThread, 
-                      U64& parentIndex, int& moveNo, U64& t0Index); 
-   
-     /** Read an entry. */ 
-     void readEntry(U64 index, Entry& entry); 
-   
-     /** Write an entry. */ 
-     void writeEntry(U64 index, const Entry& entry); 
-   
-     /** Run the interactive analysis main loop. */ 
-     void mainLoop(); 
-   
-     bool isMove(std::string cmdStr) const; 
-   
-     /** Return all nodes with a given hash key. */ 
-     void getNodesForHashKey(U64 hashKey, std::vector<U64>& nodes, U64 maxEntry); 
-   
-     /** Get hash key from an input string. */ 
-     U64 getHashKey(std::string& s, U64 defKey) const; 
-   
-     /** Get integer parameter from an input string. */ 
-     static int getArg(const std::string& s, int defVal); 
-   
-     /** Get a list of integer parameters from an input string. */ 
-     void getArgs(const std::string& s, int defVal, std::vector<int>& args); 
-   
-     /** Get a string parameter from an input string. */ 
-     static std::string getArgStr(const std::string& s, const std::string& defVal); 
-   
-     void printHelp(); 
-   
-     /** Read start/end entries for a tree node. Return true if the end entry exists. */ 
-     bool readEntries(int index, StartEntry& se, EndEntry& ee); 
-   
-     /** Find the parent node to a node. */ 
-     S64 findParent(S64 index); 
-   
-     /** Find all children of a node. */ 
-     void findChildren(S64 index, std::vector<U64>& childs); 
-   
-     /** Get node position in parents children list. */ 
-     int getChildNo(U64 index); 
-   
-     /** Get list of nodes from root position to a node. */ 
-     void getNodeSequence(U64 index, std::vector<U64>& nodes); 
-   
-     /** Find list of moves from root node to a node. 
-      * Return root node index. */ 
-     U64 getMoveSequence(U64 index, std::vector<Move>& moves); 
-   
-     /** Find the position corresponding to a node. */ 
-     Position getPosition(U64 index); 
-   
-     void printNodeInfo(U64 index, int childNo = -1, const std::string& filterMove = ""); 
-   
-   
-     std::fstream fs; 
-     S64 filePos;        // Current file read position (seekg) 
-     U64 numEntries; 
- }; 
-   
-   
- inline 
- TreeLoggerWriter::TreeLoggerWriter() 
-     : opened(false), nextIndex(0), pd(nullptr), threadNo(-1), nInWriteCache(0) { 
- } 
-   
- inline 
- TreeLoggerWriter::~TreeLoggerWriter() { 
-     close(); 
- } 
-   
- inline bool 
- TreeLoggerWriter::isOpened() const { 
-     return opened; 
- } 
-   
- inline U64 
- TreeLoggerWriter::logPosition(const Position& pos, int owningThread, U64 parentIndex, int moveNo) { 
-     U64 ret = nextIndex; 
-     if (threadNo == 0) 
-         pd->t0Index = (U32)ret; 
-     writePosition(pos, owningThread, parentIndex, moveNo); 
-     return ret; 
- } 
-   
- inline U64 
- TreeLoggerWriter::logNodeStart(U64 parentIndex, const Move& m, int alpha, int beta, int ply, int depth) { 
-     if (!opened) 
-         return 0; 
-     if (threadNo == 0) 
-         pd->t0Index = (U32)nextIndex; 
-     entry.type = EntryType::NODE_START; 
-     entry.se.endIndex = -1; 
-     entry.se.parentIndex = (U32)parentIndex; 
-     entry.se.move = m.from() + (m.to() << 6) + (m.promoteTo() << 12); 
-     entry.se.alpha = alpha; 
-     entry.se.beta = beta; 
-     entry.se.ply = ply; 
-     entry.se.depth = depth; 
-     entry.se.t0Index = pd->t0Index; 
-     appendEntry(entry); 
-     return nextIndex++; 
- } 
-   
- inline U64 
- TreeLoggerWriter::logNodeEnd(U64 startIndex, int score, int scoreType, int evalScore, U64 hashKey) { 
-     if (!opened) 
-         return 0; 
-     if (threadNo == 0) 
-         pd->t0Index = (U32)nextIndex; 
-     entry.type = EntryType::NODE_END; 
-     entry.ee.startIndex = (U32)startIndex; 
-     entry.ee.score = score; 
-     entry.ee.scoreType = scoreType; 
-     entry.ee.evalScore = evalScore; 
-     entry.ee.hashKey = hashKey; 
-     entry.ee.t0Index = pd->t0Index; 
-     appendEntry(entry); 
-     return nextIndex++; 
- } 
-   
- inline void 
- TreeLoggerReader::getRootNode(U64 index, Position& pos) { 
-     int owningThread; 
-     U64 parentIndex; 
-     int moveNo; 
-     U64 t0Index; 
-     getRootNode(index, pos, owningThread, parentIndex, moveNo, t0Index); 
- } 
-   
- #endif /* TREELOGGER_HPP_ */ 
-