Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoUctBookBuilder.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoUctBookBuilder.h */
00003 //----------------------------------------------------------------------------
00004 
00005 #ifndef GOBOOKBUILDER_H
00006 #define GOBOOKBUILDER_H
00007 
00008 #include <cmath>
00009 #include <iostream>
00010 #include <fstream>
00011 #include <set>
00012 #include "SgBookBuilder.h"
00013 #include "SgThreadedWorker.h"
00014 #include "GoBoard.h"
00015 #include "GoAutoBook.h"
00016 #include "GoBoardSynchronizer.h"
00017 
00018 //----------------------------------------------------------------------------
00019 
00020 /** Expands a Book using the given player to evaluate game positions.
00021     Supports multithreaded evaluation of children.
00022     @todo Copy settings from passed player to other players. */
00023 template<class PLAYER>
00024 class GoUctBookBuilder : public SgBookBuilder
00025 {
00026 public:
00027     GoUctBookBuilder(const GoBoard& brd);
00028     
00029     ~GoUctBookBuilder();
00030 
00031     //---------------------------------------------------------------------
00032 
00033     /** Sets the player to use. Settings are copied from this player
00034         to the players used for each thread.
00035         @todo Currently not used! Since it is not clear how to copy
00036         settings from one player to another nicely. */
00037     void SetPlayer(PLAYER& player);
00038 
00039     /** Sets the state to start work from. */
00040     void SetState(GoAutoBook& book);
00041 
00042     //---------------------------------------------------------------------    
00043 
00044     /** Number of players to use during leaf expansion. Each player
00045         may use a multi-threaded search. Should speed up the expansion
00046         of leaf states by a factor of (very close to) NumThreads(). */
00047     std::size_t NumThreads() const;
00048 
00049     /** See NumThreads() */
00050     void SetNumThreads(std::size_t num);
00051 
00052     /** Number of games to play when evaluation a state. */
00053     SgUctValue NumGamesPerEvaluation() const;
00054 
00055     /** See NumGamesPerEvaluation(). */
00056     void SetNumGamesPerEvaluation(SgUctValue num);
00057 
00058     /** Number of games to play when sorting children. */
00059     SgUctValue NumGamesPerSort() const;
00060 
00061     /** See NumGamesForSort() */
00062     void SetNumGamesPerSort(SgUctValue num);
00063 
00064     //---------------------------------------------------------------------    
00065 
00066     float InverseEval(float eval) const;
00067 
00068     bool IsLoss(float eval) const;
00069 
00070     float Value(const SgBookNode& node) const;
00071 
00072 protected:
00073     std::string MoveString(SgMove move) const;
00074 
00075     void PrintMessage(std::string msg);
00076 
00077     void PlayMove(SgMove move);
00078 
00079     void UndoMove(SgMove move);
00080 
00081     bool GetNode(SgBookNode& node) const;
00082 
00083     void WriteNode(const SgBookNode& node);
00084 
00085     void FlushBook();
00086 
00087     void EnsureRootExists();
00088 
00089     bool GenerateMoves(std::vector<SgMove>& moves, float& value);
00090 
00091     void GetAllLegalMoves(std::vector<SgMove>& moves);
00092 
00093     void EvaluateChildren(const std::vector<SgMove>& childrenToDo,
00094                           std::vector<std::pair<SgMove, float> >& scores);
00095     void Init();
00096 
00097     void StartIteration();
00098 
00099     void EndIteration();
00100 
00101     void BeforeEvaluateChildren();
00102 
00103     void AfterEvaluateChildren();
00104 
00105     void Fini();
00106 
00107     void ClearAllVisited();
00108     
00109     void MarkAsVisited();
00110     
00111     bool HasBeenVisited();
00112         
00113 private:
00114     /** Copyable worker. */
00115     class Worker
00116     {
00117     public:
00118         Worker(std::size_t id, PLAYER& player);
00119 
00120         float operator()(const SgMove& move);
00121 
00122     private:
00123         std::size_t m_id;
00124         
00125         PLAYER* m_player;
00126     };
00127 
00128     /** Book this builder is expanding */
00129     GoAutoBook* m_book;
00130    
00131     PLAYER* m_origPlayer;
00132 
00133     GoAutoBookState m_state;
00134 
00135     std::set<SgHashCode> m_visited;
00136 
00137     /** See NumberThreads() */
00138     std::size_t m_numThreads;
00139 
00140     /** See NumGamesPerEvaluation. */
00141     SgUctValue m_numGamesPerEvaluation;
00142 
00143     /** See NumGamesForSort() */
00144     SgUctValue m_numGamesPerSort;
00145 
00146     std::size_t m_numEvals;
00147 
00148     std::size_t m_numWidenings;
00149 
00150     std::size_t m_valueUpdates;
00151 
00152     std::size_t m_priorityUpdates;
00153 
00154     std::size_t m_internalNodes;
00155 
00156     std::size_t m_leafNodes;
00157 
00158     std::size_t m_terminalNodes;
00159 
00160     /** Players for each thread. */
00161     std::vector<PLAYER*> m_players;
00162 
00163     /** Workers for each thread. */
00164     std::vector<Worker> m_workers;
00165 
00166     SgThreadedWorker<SgMove,float,Worker>* m_threadedWorker;
00167 
00168     void CreateWorkers();
00169 
00170     void DestroyWorkers();
00171 };
00172 
00173 //----------------------------------------------------------------------------
00174 
00175 template<class PLAYER>
00176 inline std::size_t GoUctBookBuilder<PLAYER>::NumThreads() const
00177 {
00178     return m_numThreads;
00179 }
00180 
00181 template<class PLAYER>
00182 inline void GoUctBookBuilder<PLAYER>::SetNumThreads(std::size_t num)
00183 {
00184     m_numThreads = num;
00185 }
00186 
00187 template<class PLAYER>
00188 inline SgUctValue GoUctBookBuilder<PLAYER>::NumGamesPerEvaluation() const
00189 {
00190     return m_numGamesPerEvaluation;
00191 }
00192 
00193 template<class PLAYER>
00194 inline void GoUctBookBuilder<PLAYER>::SetNumGamesPerEvaluation(SgUctValue num)
00195 {
00196     m_numGamesPerEvaluation = num;
00197 }
00198 
00199 template<class PLAYER>
00200 inline SgUctValue GoUctBookBuilder<PLAYER>::NumGamesPerSort() const
00201 {
00202     return m_numGamesPerSort;
00203 }
00204 
00205 template<class PLAYER>
00206 inline void GoUctBookBuilder<PLAYER>::SetNumGamesPerSort(SgUctValue num)
00207 {
00208     m_numGamesPerSort = num;
00209 }
00210 
00211 //----------------------------------------------------------------------------
00212 
00213 template<class PLAYER>
00214 GoUctBookBuilder<PLAYER>::GoUctBookBuilder(const GoBoard& bd)
00215     : SgBookBuilder(), 
00216       m_book(0),
00217       m_origPlayer(0),
00218       m_state(bd),
00219       m_numThreads(1),
00220       m_numGamesPerEvaluation(10000),
00221       m_numGamesPerSort(10000)
00222 {
00223     SetAlpha(30.0);
00224     SetExpandWidth(8);
00225 }
00226 
00227 template<class PLAYER>
00228 GoUctBookBuilder<PLAYER>::~GoUctBookBuilder()
00229 {
00230 }
00231 
00232 //----------------------------------------------------------------------------
00233 
00234 /** Copies the player and board and creates the threads. */
00235 template<class PLAYER>
00236 void GoUctBookBuilder<PLAYER>::CreateWorkers()
00237 {
00238     PrintMessage("GoUctBookBuilder::CreateWorkers()\n");
00239     for (std::size_t i = 0; i < m_numThreads; ++i)
00240     {
00241         PLAYER* newPlayer = new PLAYER(m_state.Board());
00242 
00243         // TODO: COPY SETTINGS SOMEHOW
00244         //newPlayer->CopySettingsFrom(m_origPlayer);
00245         
00246         // Always search, don't use forced moves
00247         newPlayer->SetForcedOpeningMoves(false);
00248         // Ensure all games are played; ie, do not use early count abort.
00249         newPlayer->Search().SetMoveSelect(SG_UCTMOVESELECT_ESTIMATE);
00250         // Should be enough for a 100k search. Needs 10GB 8 threaded.
00251         newPlayer->Search().SetMaxNodes(8500000);
00252         newPlayer->SetWriteDebugOutput(false);
00253 
00254         m_players.push_back(newPlayer);
00255         m_workers.push_back(Worker(i, *m_players[i]));
00256     }
00257     m_threadedWorker 
00258         = new SgThreadedWorker<SgMove,float,Worker>(m_workers);
00259 }
00260 
00261 /** Destroys copied players, boards, and threads. */
00262 template<class PLAYER>
00263 void GoUctBookBuilder<PLAYER>::DestroyWorkers()
00264 {
00265     PrintMessage("GoUctBookBuilder::DestroyWorkers()\n");
00266     for (std::size_t i = 0; i < m_numThreads; ++i)
00267         delete m_players[i];
00268     delete m_threadedWorker;
00269     m_workers.clear();
00270     m_players.clear();
00271 }
00272 
00273 template<class PLAYER>
00274 void GoUctBookBuilder<PLAYER>::Init()
00275 {
00276     CreateWorkers();
00277 }
00278 
00279 template<class PLAYER>
00280 void GoUctBookBuilder<PLAYER>::Fini()
00281 {
00282     DestroyWorkers();
00283 }
00284 
00285 //----------------------------------------------------------------------------
00286 
00287 template<class PLAYER>
00288 GoUctBookBuilder<PLAYER>::Worker::Worker(std::size_t id, PLAYER& player)
00289 
00290     : m_id(id), 
00291       m_player(&player)
00292 {
00293 }
00294 
00295 template<class PLAYER>
00296 float GoUctBookBuilder<PLAYER>::Worker::operator()(const SgMove& move)
00297 {
00298     m_player->UpdateSubscriber();
00299     if (move >= 0)
00300         m_player->Board().Play(move);
00301     m_player->GenMove(SgTimeRecord(true, 9999), m_player->Board().ToPlay());
00302     GoUctSearch& search 
00303         = dynamic_cast<GoUctSearch&>(m_player->Search());
00304     float score = static_cast<float>(search.Tree().Root().Mean());
00305     return score;
00306 }
00307 
00308 //----------------------------------------------------------------------------
00309 
00310 template<class PLAYER>
00311 inline void GoUctBookBuilder<PLAYER>::SetPlayer(PLAYER& player)
00312 {
00313     m_origPlayer = &player;
00314 }
00315 
00316 template<class PLAYER>
00317 inline void GoUctBookBuilder<PLAYER>::SetState(GoAutoBook& book)
00318 {
00319     m_book = &book;
00320     m_state.Synchronize();
00321 }
00322 
00323 template<class PLAYER>
00324 inline std::string GoUctBookBuilder<PLAYER>::MoveString(SgMove move) const
00325 {
00326     return SgPointUtil::PointToString(move);
00327 }
00328 
00329 template<class PLAYER>
00330 void GoUctBookBuilder<PLAYER>::PrintMessage(std::string msg)
00331 {
00332     SgDebug() << msg;
00333 }
00334 
00335 template<class PLAYER>
00336 inline float GoUctBookBuilder<PLAYER>::InverseEval(float eval) const
00337 {
00338     return 1.f - eval;
00339 }
00340 
00341 template<class PLAYER>
00342 inline bool GoUctBookBuilder<PLAYER>::IsLoss(float eval) const
00343 {
00344     return eval < -100;
00345 }
00346 
00347 template<class PLAYER>
00348 void GoUctBookBuilder<PLAYER>::PlayMove(SgMove move)
00349 {
00350     m_state.Play(move);
00351 }
00352 
00353 template<class PLAYER>
00354 void GoUctBookBuilder<PLAYER>::UndoMove(SgMove move)
00355 {
00356     SG_UNUSED(move);
00357     m_state.Undo();
00358 }
00359 
00360 template<class PLAYER>
00361 bool GoUctBookBuilder<PLAYER>::GetNode(SgBookNode& node) const
00362 {
00363     return m_book->Get(m_state, node);
00364 }
00365 
00366 template<class PLAYER>
00367 void GoUctBookBuilder<PLAYER>::WriteNode(const SgBookNode& node)
00368 {
00369     m_book->Put(m_state, node);
00370 }
00371 
00372 template<class PLAYER>
00373 void GoUctBookBuilder<PLAYER>::FlushBook()
00374 {
00375     SgDebug() << "Flushing DB...\n";
00376     m_book->Flush();
00377 }
00378 
00379 template<class PLAYER>
00380 float GoUctBookBuilder<PLAYER>::Value(const SgBookNode& node) const
00381 {
00382     return node.m_value;
00383 }
00384 
00385 template<class PLAYER>
00386 void GoUctBookBuilder<PLAYER>::GetAllLegalMoves(std::vector<SgMove>& moves)
00387 {
00388     for (GoBoard::Iterator it(m_state.Board()); it; ++it)
00389         if (m_state.Board().IsLegal(*it))
00390             moves.push_back(*it);
00391 }
00392 
00393 /** Creates root node if necessary. */
00394 template<class PLAYER>
00395 void GoUctBookBuilder<PLAYER>::EnsureRootExists()
00396 {
00397     SgBookNode root;
00398     if (!GetNode(root))
00399     {
00400         BeforeEvaluateChildren();
00401         PrintMessage("Creating root node...\n");
00402         float value = m_workers[0](SG_NULLMOVE);
00403         WriteNode(SgBookNode(value));
00404     }
00405 }
00406 
00407 /** Computes an ordered set of moves to consider. */
00408 template<class PLAYER>
00409 bool GoUctBookBuilder<PLAYER>::GenerateMoves(std::vector<SgMove>& moves,
00410                                              float& value)
00411 {
00412     SG_UNUSED(value);
00413 
00414     // Search for a few seconds.
00415     SgDebug() << m_state.Board() << '\n';
00416     m_players[0]->SetMaxGames(m_numGamesPerSort);
00417     m_workers[0](SG_NULLMOVE);
00418     std::vector<std::pair<SgUctValue, SgMove> > ordered;
00419     // Store counts for each move in vector.
00420     {
00421         const SgUctTree& tree = m_players[0]->Search().Tree();
00422         const SgUctNode& root = tree.Root();
00423         for (GoBoard::Iterator it(m_state.Board()); it; ++it)
00424             if (m_state.Board().IsLegal(*it))
00425             {
00426                 SgMove move = *it;
00427                 const SgUctNode* node = 
00428                     SgUctTreeUtil::FindChildWithMove(tree, root, move);
00429                 if (node && node->PosCount() > 0)
00430                 {
00431                     ordered.push_back(std::make_pair(-node->PosCount(), move));
00432                 }
00433             }
00434     }
00435     // Sort moves based on count of this search. 
00436     std::stable_sort(ordered.begin(), ordered.end());
00437     for (std::size_t i = 0; i < ordered.size(); ++i)
00438         moves.push_back(ordered[i].second);
00439     SgDebug() << '\n';
00440     return false;
00441 }
00442 
00443 template<class PLAYER>
00444 void GoUctBookBuilder<PLAYER>::BeforeEvaluateChildren()
00445 {
00446     for (std::size_t i = 0; i < m_numThreads; ++i)
00447         m_players[i]->SetMaxGames(m_numGamesPerEvaluation);
00448 }
00449 
00450 template<class PLAYER>
00451 void GoUctBookBuilder<PLAYER>
00452 ::EvaluateChildren(const std::vector<SgMove>& childrenToDo,
00453                    std::vector<std::pair<SgMove, float> >& scores)
00454 {
00455     SgDebug() << "Evaluating children:";
00456     for (std::size_t i = 0; i < childrenToDo.size(); ++i)
00457         SgDebug() << ' ' << SgWritePoint(childrenToDo[i]);
00458     SgDebug() << '\n';
00459     m_threadedWorker->DoWork(childrenToDo, scores);
00460 }
00461 
00462 template<class PLAYER>
00463 void GoUctBookBuilder<PLAYER>::AfterEvaluateChildren()
00464 {
00465 }
00466 
00467 template<class PLAYER>
00468 void GoUctBookBuilder<PLAYER>::StartIteration()
00469 {
00470 }
00471 
00472 template<class PLAYER>
00473 void GoUctBookBuilder<PLAYER>::EndIteration()
00474 {
00475 }
00476 
00477 template<class PLAYER>
00478 void GoUctBookBuilder<PLAYER>::ClearAllVisited()
00479 {
00480     m_visited.clear();
00481 }
00482     
00483 template<class PLAYER>
00484 void GoUctBookBuilder<PLAYER>::MarkAsVisited()
00485 {
00486     m_visited.insert(m_state.GetHashCode());
00487 }
00488     
00489 template<class PLAYER>
00490 bool GoUctBookBuilder<PLAYER>::HasBeenVisited()
00491 {
00492     return m_visited.count(m_state.GetHashCode()) == 1;
00493 }
00494 
00495 //----------------------------------------------------------------------------
00496 
00497 #endif // GOBOOKBUILDER_HPP


Sun Mar 13 2011 Doxygen 1.7.1