Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

SgUctSearch.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file SgUctSearch.h
00003     Class SgUctSearch and helper classes. */
00004 //----------------------------------------------------------------------------
00005 
00006 #ifndef SG_UCTSEARCH_H
00007 #define SG_UCTSEARCH_H
00008 
00009 #include <fstream>
00010 #include <vector>
00011 #include <boost/scoped_array.hpp>
00012 #include <boost/shared_ptr.hpp>
00013 #include <boost/thread/barrier.hpp>
00014 #include <boost/thread/condition.hpp>
00015 #include <boost/thread/mutex.hpp>
00016 #include <boost/thread/recursive_mutex.hpp>
00017 #include <boost/thread/thread.hpp>
00018 #include "SgBlackWhite.h"
00019 #include "SgBWArray.h"
00020 #include "SgTimer.h"
00021 #include "SgUctTree.h"
00022 #include "SgMpiSynchronizer.h"
00023 
00024 #define SG_UCTFASTLOG 1
00025 #if SG_UCTFASTLOG
00026 #include "SgFastLog.h"
00027 #endif
00028 
00029 //----------------------------------------------------------------------------
00030 
00031 /** @defgroup sguctgroup Monte Carlo tree search
00032     Game-independent Monte Carlo tree search using UCT.
00033 
00034     The main class SgUctSearch keeps a tree with statistics for each node
00035     visited more than a certain number of times, and then continues with
00036     random playout (not necessarily uniform random).
00037     Within the tree, the move with the highest upper confidence bound is
00038     chosen according to the basic UCT formula:
00039     @f[ \bar{X}_j + c \sqrt{\frac{\log{n}}{T_j(n)}} @f]
00040     with:
00041     - @f$ j @f$ the move index
00042     - @f$ X_{j,\gamma} @f$ reward for move @f$ j @f$ at sample @f$ \gamma @f$
00043     - @f$ n @f$ number of times the father node was visited
00044     - @f$ T_j(n) @f$ number of times the move has been played
00045     - @f$ c @f$ an appropriate constant
00046 
00047     References:
00048     - Kocsis, Szepesvari:
00049       <a href="http://zaphod.aml.sztaki.hu/papers/ecml06.pdf">
00050       Bandit based Monte-Carlo Planning</a>
00051     - Auer, Cesa-Bianchi, Fischer:
00052       <a href="http://homes.dsi.unimi.it/~cesabian/Pubblicazioni/ml-02.pdf">
00053       Finite-time Analysis of the Multiarmed Bandit Problem</a>
00054     - Gelly, Wang, Munos, Teytaud:
00055       <a href="http://hal.inria.fr/docs/00/12/15/16/PDF/RR-6062.pdf">
00056       Modification of UCT with patterns in Monte-Carlo Go</a>
00057     - Silver, Gelly:
00058       <a href=
00059       "http://imls.engr.oregonstate.edu/www/htdocs/proceedings/icml2007/papers/387.pdf">
00060       Combining Online and Offline Knowledge in UCT</a>
00061 
00062     @see
00063     - @ref sguctsearchlockfree
00064     - @ref sguctsearchweights
00065     - @ref sguctsearchproven */
00066 
00067 /** @page sguctsearchlockfree Lock-free mode in SgUctSearch
00068 
00069 The basic idea of the lock-free mode in SgUctSearch is to share a tree between
00070 multiple threads without using any locks. Because of specific requirements on
00071 the memory model of the hardware platform, lock-free mode is an optional
00072 feature of the SgUctSearch and needs to be enabled explicitly.
00073 
00074 @section sguctsearchlockfreetree Modifying the Tree Structure
00075 
00076 The first change to make the lock-free search work is in the handling of
00077 concurrent changes to the structure of the tree. SgUctSearch never deletes
00078 nodes during a search; new nodes are created in a pre-allocated memory array.
00079 In the lock-free algorithm, each thread has its own memory array for creating
00080 new nodes. Only after the nodes are fully created and initialized, are they
00081 linked to the parent node. This can cause some memory overhead, because if
00082 several threads expand the same node only the children created by the last
00083 thread will be used in future simulations. It can also happen that some of the
00084 children that are lost already received value updates; these updates will be
00085 lost.
00086 
00087 The child information of a node consists of two variables: a pointer to the
00088 first child in the array, and the number of children. To avoid that another
00089 thread sees an inconsistent state of these variables, all threads assume that
00090 the number of children is valid if the pointer to the first child is not null.
00091 Linking a parent to a new set of children requires first writing the number of
00092 children, then the pointer to the first child. The compiler is prevented from
00093 reordering the writes by declaring these variables as volatile.
00094 
00095 @section sguctsearchlockfreevalues Updating Values
00096 
00097 The move and RAVE values are stored in the nodes as counts and mean values.
00098 The mean values are updated using an incremental algorithm. Updating them
00099 without protection by a mutex can cause updates of the mean to be lost with or
00100 without increment of the count, as well as updates of the mean occurring
00101 without increment of the count. It could also happen that one thread reads the
00102 count and mean while they are written by another thread, and the first thread
00103 sees an erroneous state that exists only temporarily. In practice, these
00104 faulty updates occur with a low probability and will have only a small effect
00105 on the counts and mean values. They are intentionally ignored.
00106 
00107 The only problematic case is if a count is zero, because the mean value is
00108 undefined if the count is zero, and this case has a special meaning at several
00109 places in the search. For example, the computation of the values for the
00110 selection of children in the in-tree phase distinguishes three cases: if the
00111 move count and RAVE count is non-zero, the value will be computed as a
00112 weighted linear combination of both mean values, if the move count is zero,
00113 only the RAVE mean is used, and if both counts are zero, a configurable
00114 constant value, the first play urgency, is used. To avoid this problem, all
00115 threads assume that a mean value is only valid if the corresponding count is
00116 non-zero. Updating a value requires first writing the new mean value, then the
00117 new count. The compiler is prevented from reordering the writes by declaring
00118 the counts and mean values as volatile.
00119 
00120 @section sguctsearchlockfreeplatform Platform Requirements
00121 
00122 There are some requirements on the memory model of the platform to make the
00123 lock-free search algorithm work. Writes of certain basic types (size_t, int,
00124 float, pointers) must be atomic. Writes by one thread must be seen by other
00125 threads in the same order. The IA-32 and Intel-64 CPU architectures, which are
00126 used in most modern standard computers, guarantee these assumptions. They also
00127 synchronize CPU caches after writes. (See
00128 <a href="http://download.intel.com/design/processor/manuals/253668.pdf">
00129 Intel 64 and IA-32 Architectures Software Developer's Manual</a>, chapter
00130 7.1 Locked Atomic Operations and 7.2 Memory Ordering). */
00131 
00132 /** @page sguctsearchweights Estimator weights in SgUctSearch
00133     The weights of the estimators (move value, RAVE value) are chosen by
00134     assuming that the estimators are uncorrelated and modeling the mean
00135     squared error of estimator @f$ i @f$ by a function that depends on the
00136     number of samples and parameter constants, which represent the variance
00137     and bias of the estimator and need to be determined experimentally:
00138 
00139     @f[
00140     w_i = \frac{1}{Z} \frac{1}{{\rm MSE}_i}
00141     \qquad Z = \sum_i \frac{1}{{\rm MSE}_i}
00142     \qquad {\rm MSE}_i = \frac{c_{\rm variance}}{N_i} + c_{\rm bias}^2
00143     @f]
00144 
00145     Note that this formula is nearly equivalent to the formula suggested
00146     by David Silver on the Computer Go mailing list for the case of two
00147     estimators (move value and RAVE value) and used in newer versions of MoGo.
00148     However, MoGo uses the measured variance of the current RAVE value (for
00149     both the move weight and RAVE weight) instead variance parameter
00150     constants.
00151 
00152     The formula is then reformulated to use different constants that describe
00153     the initial steepness and final asymptotic value of the unnormalized
00154     weight:
00155 
00156     @f[
00157     Z w_i =
00158     \frac{c_{\rm initial}}
00159          {\frac{1}{N} + \frac{c_{\rm initial}}{c_{\rm final}}}
00160     @f]
00161 
00162     with:
00163     - @f$ N @f$ sample count of the estimator
00164     - @f$ c_{\rm initial} @f$ Initial weight parameter; this is they weight if
00165       @f$ N = 1 @f$ and @f$ c_{\rm final} \gg c_{\rm initial} @f$
00166     - @f$ c_{\rm final} @f$ Final weight parameter; this is they weight if
00167       @f$ N \rightarrow \infty @f$
00168 
00169     For the move value, @f$ c_{\rm bias} = 0 @f$, and the variance can become
00170     part of the normalization constant, so the weight is simply
00171     @f$ N_{\rm move} @f$.
00172     If no estimator has a sample count yet, the first-play-urgency parameter
00173     is used for the value estimate. */
00174 
00175 /** @page sguctsearchproven Proven Nodes in SgUctSearch
00176 
00177     When expanding a node (or computing knowledge at a node) it is
00178     possible the derived class can prove that the state corresponding
00179     to the node is a proven win or loss. Note this differs from a
00180     terminal node since a terminal node by definition has no children,
00181     whereas a proven node can have any number of children.
00182 
00183     Any in-tree phase that encounters a proven node is immediately
00184     terminated and the result passed back up the tree just as if a
00185     playout (with the value corresponding to the proven value) had
00186     been performed.
00187 
00188     The existence of proven nodes in a SgUctTree does not change the
00189     move selection in any way. For example: a node with both winning
00190     and losing children will continue to select children without
00191     regard to their proven value. This means losing children will not
00192     be avoided and winning children will not be chosen except as a
00193     result of the playouts recorded as those children are visisted
00194     (the values of which would now be perfectly accurate).
00195 
00196     Proven values are not currently passed up the tree like in a
00197     min-max search. It would be possible to pass back winning moves,
00198     that is, mark the parent of winning moves as winning, but it is
00199     not possible mark a node as losing if all its moves are
00200     losing. This is because it is possible progressive widening (or
00201     other heuristics) are being used by the derived state and in such
00202     a case it may not be true that all the current children being
00203     losses implies the parent state is a loss. */
00204 
00205 //----------------------------------------------------------------------------
00206 
00207 /** Game result, sequence and nodes of one Monte-Carlo game in SgUctSearch.
00208     @ingroup sguctgroup */
00209 struct SgUctGameInfo
00210 {
00211     /** The game result of the playout(s).
00212         The result is from the view of the player at the root. */
00213     std::vector<SgUctValue> m_eval;
00214 
00215     /** The sequence of the in-tree phase. */
00216     std::vector<SgMove> m_inTreeSequence;
00217 
00218     /** The sequence of the playout(s).
00219         For convenient usage, they also include the moves from
00220         m_inTreeSequence, even if they are the same for each playout. */
00221     std::vector<std::vector<SgMove> > m_sequence;
00222 
00223     /** Was the playout aborted due to maxGameLength (stored for each
00224         playout). */
00225     std::vector<bool> m_aborted;
00226 
00227     /** Nodes visited in the in-tree phase. */
00228     std::vector<const SgUctNode*> m_nodes;
00229 
00230     /** Flag to skip RAVE update for moves of the playout(s).
00231         For convenient usage, the index corresponds to the move number from
00232         the root position on, even if the flag is currently only used for
00233         moves in the playout phase, so the flag is false for all moves in the
00234         in-tree phase. */
00235     std::vector<std::vector<bool> > m_skipRaveUpdate;
00236 
00237     void Clear(std::size_t numberPlayouts);
00238 };
00239 
00240 //----------------------------------------------------------------------------
00241 
00242 /** Move selection strategy after search is finished.
00243     @ingroup sguctgroup */
00244 enum SgUctMoveSelect
00245 {
00246     /** Select move with highest mean value. */
00247     SG_UCTMOVESELECT_VALUE,
00248 
00249     /** Select move with highest count. */
00250     SG_UCTMOVESELECT_COUNT,
00251 
00252     /** Use UCT bound (or combined bound if RAVE is enabled). */
00253     SG_UCTMOVESELECT_BOUND,
00254 
00255     /** Use the weighted sum of UCT and RAVE value (but without
00256         bias terms). */
00257     SG_UCTMOVESELECT_ESTIMATE
00258 };
00259 
00260 //----------------------------------------------------------------------------
00261 
00262 /** Base class for the thread state.
00263     Subclasses must be thread-safe, it must be possible to use different
00264     instances of this class in different threads (after construction, the
00265     constructor does not need to be thread safe). Beware not to use classes
00266     that are not thread-safe, because they use global variables
00267     (e.g. SgRandom::Global())
00268     @note Technically it is possible to use a non-thread safe implementation
00269     of subclasses, as long as the search is run with only one thread.
00270     @ingroup sguctgroup */
00271 class SgUctThreadState
00272 {
00273 public:
00274     /** Number of the thread between 0 and SgUctSearch::NumberThreads() - 1 */
00275     const unsigned int m_threadId;
00276 
00277     bool m_isSearchInitialized;
00278 
00279     /** Flag indicating the a node could not be expanded, because the
00280         maximum tree size was reached. */
00281     bool m_isTreeOutOfMem;
00282 
00283     SgUctGameInfo m_gameInfo;
00284 
00285     /** Local variable for SgUctSearch::UpdateRaveValues().
00286         Reused for efficiency. Stores the first time a move was played
00287         by the color to play at the root position (move is used as an index,
00288         do m_moveRange must be > 0); numeric_limits<size_t>::max(), if the
00289         move was not played. */
00290     boost::scoped_array<std::size_t> m_firstPlay;
00291 
00292     /** Local variable for SgUctSearch::UpdateRaveValues().
00293         Like m_firstPlayToPlay, but for opponent color. */
00294     boost::scoped_array<std::size_t> m_firstPlayOpp;
00295 
00296     /** Local variable for SgUctSearch::PlayInTree().
00297         Reused for efficiency. */
00298     std::vector<SgUctMoveInfo> m_moves;
00299 
00300     /** Local variable for SgUctSearch::CheckCountAbort().
00301         Reused for efficiency. */
00302     std::vector<SgMove> m_excludeMoves;
00303 
00304     /** Thread's counter for Randomized Rave in SgUctSearch::SelectChild(). */
00305     int m_randomizeCounter;
00306 
00307     SgUctThreadState(unsigned int threadId, int moveRange = 0);
00308 
00309     virtual ~SgUctThreadState();
00310 
00311     /** @name Pure virtual functions */
00312     // @{
00313 
00314     /** Evaluate end-of-game position.
00315         Will only be called if GenerateAllMoves() or GeneratePlayoutMove()
00316         returns no moves. Should return larger values if position is better
00317         for the player to move. */
00318     virtual SgUctValue Evaluate() = 0;
00319 
00320     /** Execute a move.
00321         @param move The move */
00322     virtual void Execute(SgMove move) = 0;
00323 
00324     /** Execute a move in the playout phase.
00325         For optimization if the subclass uses uses a different game state
00326         representation in the playout phase. Otherwise the function can be
00327         implemented in the subclass by simply calling Execute().
00328         @param move The move */
00329     virtual void ExecutePlayout(SgMove move) = 0;
00330 
00331     /** Generate moves.
00332         Moves will be explored in the order of the returned list.
00333         If return is true, trees under children will be deleted.
00334         @param count Number of times node has been visited. For knowledge-
00335         based computations.
00336         @param[out] moves The generated moves or empty list at end of game
00337         @param[out] provenType */
00338     virtual bool GenerateAllMoves(SgUctValue count, 
00339                                   std::vector<SgUctMoveInfo>& moves,
00340                                   SgUctProvenType& provenType) = 0;
00341 
00342     /** Generate random move.
00343         Generate a random move in the play-out phase (outside the UCT tree).
00344         @param[out] skipRaveUpdate This value should be set to true, if the
00345         move should be excluded from RAVE updates. Otherwise it can be
00346         ignored.
00347         @return The move or SG_NULLMOVE at the end of the game. */
00348     virtual SgMove GeneratePlayoutMove(bool& skipRaveUpdate) = 0;
00349 
00350     /** Start search.
00351         This function should do any necessary preparations for playing games
00352         in the thread, like initializing the thread's copy of the game state
00353         from the global game state. The function does not have to be
00354         thread-safe. */
00355     virtual void StartSearch() = 0;
00356 
00357     /** Take back moves played in the in-tree phase. */
00358     virtual void TakeBackInTree(std::size_t nuMoves) = 0;
00359 
00360     /** Take back moves played in the playout phase.
00361         The search engine does not assume that the moves are really taken back
00362         after this function is called. If the subclass implements the playout
00363         in s separate state, which is initialized in StartPlayout() and does
00364         not support undo, the implementation of this function can be left
00365         empty in the subclass. */
00366     virtual void TakeBackPlayout(std::size_t nuMoves) = 0;
00367 
00368     // @} // name
00369 
00370 
00371     /** @name Virtual functions */
00372     // @{
00373 
00374     /** Function that will be called by PlayGame() before the game.
00375         Default implementation does nothing. */
00376     virtual void GameStart();
00377 
00378     /** Function that will be called at the beginning of the playout phase.
00379         Will be called only once (not once per playout!). Can be used for
00380         example to save some state of the current position for more efficient
00381         implementation of TakeBackPlayout().
00382         Default implementation does nothing. */
00383     virtual void StartPlayouts();
00384 
00385     /** Function that will be called at the beginning of each playout.
00386         Default implementation does nothing. */
00387     virtual void StartPlayout();
00388 
00389     /** Function that will be called after each playout.
00390         Default implementation does nothing. */
00391     virtual void EndPlayout();
00392 
00393     // @} // name
00394 };
00395 
00396 //----------------------------------------------------------------------------
00397 
00398 class SgUctSearch;
00399 
00400 /** Create game specific thread state.
00401     @see SgUctThreadState
00402     @ingroup sguctgroup */
00403 class SgUctThreadStateFactory
00404 {
00405 public:
00406     virtual ~SgUctThreadStateFactory();
00407 
00408     virtual SgUctThreadState* Create(unsigned int threadId,
00409                                      const SgUctSearch& search) = 0;
00410 };
00411 
00412 //----------------------------------------------------------------------------
00413 
00414 /** Statistics of the last search performed by SgUctSearch. */
00415 struct SgUctSearchStat
00416 {
00417     double m_time;
00418 
00419     /** Number of nodes for which the knowledge threshold was exceeded. */ 
00420     SgUctValue m_knowledge;
00421 
00422     /** Games per second.
00423         Useful values only if search time is higher than resolution of
00424         SgTime::Get(). */
00425     double m_gamesPerSecond;
00426 
00427     SgStatisticsExt<SgUctValue,SgUctValue> m_gameLength;
00428 
00429     SgStatisticsExt<SgUctValue,SgUctValue> m_movesInTree;
00430 
00431     SgUctStatistics m_aborted;
00432 
00433     void Clear();
00434 
00435     void Write(std::ostream& out) const;
00436 };
00437 
00438 //----------------------------------------------------------------------------
00439 
00440 /** Optional parameters to SgUctSearch::Search() to allow early aborts.
00441     If early abort is used, the search will be aborted after a fraction of the
00442     resources (max time, max nodes) are spent, if the value is a clear win
00443     (above a threshold). */
00444 struct SgUctEarlyAbortParam
00445 {
00446     /** The threshold to define what a clear win is. */
00447     SgUctValue m_threshold;
00448 
00449     /** The minimum number of games to allow an early abort.
00450         For a very low number of simulations, the value can be very
00451         unreliable. */
00452     SgUctValue m_minGames;
00453 
00454     /** The inverse fraction of the total resources (max time, max nodes),
00455         after which the early abort check is performed. */
00456     SgUctValue m_reductionFactor;
00457 };
00458 
00459 //----------------------------------------------------------------------------
00460 
00461 /** Monte Carlo tree search using UCT.
00462     The evaluation function is assumed to be in <code>[0..1]</code> and
00463     inverted with <code>1 - eval</code>.
00464     @ingroup sguctgroup */
00465 class SgUctSearch
00466 {
00467 public:
00468     static SgUctValue InverseEval(SgUctValue eval);
00469 
00470     static SgUctValue InverseEstimate(SgUctValue eval);
00471 
00472     /** Constructor.
00473         @param threadStateFactory The tread state factory (takes ownership).
00474         Can be null and set later (before using the search) with
00475         SetThreadStateFactory to allow multi-step construction.
00476         @param moveRange Upper integer limit (exclusive) used for move
00477         representation. Certain enhancements of SgUctSearch (e.g. Rave())
00478         need to store data in arrays using the move as an index for
00479         efficient implementation. If the game does not use a small integer
00480         range for its move representation, this parameter should be 0.
00481         Then, enhancements that require a small move range cannot be enabled. */
00482     SgUctSearch(SgUctThreadStateFactory* threadStateFactory,
00483                 int moveRange = 0);
00484 
00485     virtual ~SgUctSearch();
00486 
00487     void SetThreadStateFactory(SgUctThreadStateFactory* factory);
00488 
00489     /** @name Pure virtual functions */
00490     // @{
00491 
00492     /** Convert move to string (game dependent).
00493         This function needs to be thread-safe. */
00494     virtual std::string MoveString(SgMove move) const = 0;
00495 
00496     /** Evaluation value to use if evaluation is unknown.
00497         This value will be used, if games are aborted, because they exceed
00498         the maximum game length.
00499         This function needs to be thread-safe. */
00500     virtual SgUctValue UnknownEval() const = 0;
00501 
00502     // @} // name
00503 
00504 
00505     /** @name Virtual functions */
00506     // @{
00507 
00508     /** Hook function that will be called by Search() after each game.
00509         Default implementation does nothing.
00510         This function does not need to be thread-safe.
00511         @param gameNumber The number of this iteration.
00512         @param threadId
00513         @param info The game info of the thread which played this iteration.
00514         @warning If LockFree() is enabled, this function will be called from
00515         multiple threads without locking. The subclass should handle this
00516         case appropriately by using its own lock or disabling functionality
00517         that will not work without locking. */
00518     virtual void OnSearchIteration(SgUctValue gameNumber,
00519                                    unsigned int threadId,
00520                                    const SgUctGameInfo& info);
00521 
00522     /** Hook function that will be called by StartSearch().
00523         Default implementation calls m_mpiSynchronizer.StartSearch().
00524         This function does not need to be thread-safe. */
00525     virtual void OnStartSearch();
00526 
00527     /** Hook function that will be called when search
00528     completes.  Default implementation calls
00529     m_mpiSynchronizer.EndSearch().  This function
00530     does not need to be thread-safe. */
00531     virtual void OnEndSearch();
00532 
00533     virtual void OnThreadStartSearch(SgUctThreadState& state);
00534 
00535     virtual void OnThreadEndSearch(SgUctThreadState& state);
00536 
00537     virtual SgUctValue GamesPlayed() const;
00538 
00539     // @} // name
00540 
00541 
00542     /** @name Search functions */
00543     // @{
00544 
00545     /** Get a list of all generated moves.
00546         Sets up thread state 0 for a seach and calls GenerateAllMoves
00547         of the thread state. */
00548     void GenerateAllMoves(std::vector<SgUctMoveInfo>& moves);
00549 
00550     /** Play a single game.
00551         Plays a single game using the thread state of the first thread.
00552         Call StartSearch() before calling this function. */
00553     void PlayGame();
00554 
00555     /** Start search.
00556         Initializes search for current position and clears statistics.
00557         @param rootFilter Moves to filter at the root node
00558         @param initTree The tree to initialize the search with. 0 for no
00559         initialization. The trees are actually swapped, not copied. */
00560     void StartSearch(const std::vector<SgMove>& rootFilter
00561                      = std::vector<SgMove>(),
00562                      SgUctTree* initTree = 0);
00563 
00564     void EndSearch();
00565 
00566     /** Calls StartSearch() and then PlayGame() in a loop.
00567         @param maxGames The maximum number of games (greater or equal
00568         one). The number of games includes the ones already counted in
00569         the initialization tree (see parameter initTree).
00570         @param maxTime The maximum time in seconds.
00571         @param[out] sequence The move sequence with the best value.
00572         @param rootFilter Moves to filter at the root node
00573         @param initTree The tree to initialize the search with. 0 for no
00574         initialization. The trees are actually swapped, not copied.
00575         @param earlyAbort See SgUctEarlyAbortParam. Null means not to do an
00576         early abort.
00577         @return The value of the root position. */
00578     SgUctValue Search(SgUctValue maxGames, double maxTime,
00579                       std::vector<SgMove>& sequence,
00580                       const std::vector<SgMove>& rootFilter
00581                       = std::vector<SgMove>(),
00582                       SgUctTree* initTree = 0,
00583                       SgUctEarlyAbortParam* earlyAbort = 0);
00584 
00585     /** Do a one-ply Monte-Carlo search instead of the UCT search.
00586         @param maxGames
00587         @param maxTime
00588         @param[out] value The value of the best move */
00589     SgPoint SearchOnePly(SgUctValue maxGames, double maxTime,
00590                          SgUctValue& value);
00591 
00592     /** Find child node with best move.
00593         @param node The father node.
00594         @param excludeMoves Optional list of moves to ignore in the children
00595         nodes.
00596         @return The best child or 0 if no child nodes exists. */
00597     const SgUctNode*
00598     FindBestChild(const SgUctNode& node,
00599                   const std::vector<SgMove>* excludeMoves = 0) const;
00600 
00601     /** Extract sequence of best moves from root node.
00602         @param[out] sequence The resulting sequence. */
00603     void FindBestSequence(std::vector<SgMove>& sequence) const;
00604 
00605     /** Return the bound of a move.
00606         This is the bound that was used for move selection. It can be the
00607         pure UCT bound or the combined bound if RAVE is used.
00608         @param useRave Whether rave should be used or not.
00609         @param node The node corresponding to the position
00610         @param child The node corresponding to the move */
00611     SgUctValue GetBound(bool useRave, const SgUctNode& node, 
00612                         const SgUctNode& child) const;
00613 
00614     // @} // name
00615 
00616 
00617     /** @name Search data */
00618     // @{
00619 
00620     /** Info for last game.
00621         Returns the last game info of the first thread.
00622         This function is not thread-safe. */
00623     const SgUctGameInfo& LastGameInfo() const;
00624 
00625     /** One-line summary text for last game.
00626         Contains: move, count and mean for all nodes; result
00627         Returns the last game info of the first thread.
00628         This function is not thread-safe. */
00629     std::string LastGameSummaryLine() const;
00630 
00631     /** See parameter earlyAbort in Search() */
00632     bool WasEarlyAbort() const;
00633 
00634     const SgUctTree& Tree() const;
00635 
00636     /** Get temporary tree.
00637         Returns a tree that is compatible in size and number of allocators
00638         to the tree of the search. This tree is used by the search itself as
00639         a temporary tree for certain operations during the search, but can be
00640         used by other code while the search is not running. */
00641     SgUctTree& GetTempTree();
00642 
00643     // @} // name
00644 
00645 
00646     /** @name Parameters */
00647     // @{
00648 
00649     /** Constant c in the bias term.
00650         This constant corresponds to 2 C_p in the original UCT paper.
00651         The default value is 0.7, which works well in 9x9 Go. */
00652     float BiasTermConstant() const;
00653 
00654     /** See BiasTermConstant() */
00655     void SetBiasTermConstant(float biasTermConstant);
00656 
00657     /** Points at which to recompute children.  
00658         Specifies the number of visits at which GenerateAllMoves() is
00659         called again at the node. This is to allow multiple knowledge
00660         computations to occur as a node becomes more
00661         important. Returned move info will be merged with info in the
00662         tree. This is can be used prune, add children, give a bonus to
00663         a move, etc. */
00664     std::vector<SgUctValue> KnowledgeThreshold() const;
00665 
00666     /** See KnowledgeThreshold() */
00667     void SetKnowledgeThreshold(const std::vector<SgUctValue>& counts);
00668 
00669     /** Maximum number of nodes in the tree.
00670         @note The search owns two trees, one of which is used as a temporary
00671         tree for some operations (see GetTempTree()). This functions sets
00672         the maximum number of nodes per tree. */
00673     std::size_t MaxNodes() const;
00674 
00675     /** See MaxNodes()
00676         @param maxNodes Maximum number of nodes (>= 1) */
00677     void SetMaxNodes(std::size_t maxNodes);
00678 
00679     /** The number of threads to use during the search. */
00680     unsigned int NumberThreads() const;
00681 
00682     /** See SetNumberThreads() */
00683     void SetNumberThreads(unsigned int n);
00684 
00685     /** Lock-free usage of multi-threaded search.
00686         @ref sguctsearchlockfree */
00687     bool LockFree() const;
00688 
00689     /** See LockFree() */
00690     void SetLockFree(bool enable);
00691 
00692     /** See SetRandomizeRaveFrequency() */
00693     int RandomizeRaveFrequency() const;
00694 
00695     /** Randomly turns off rave with given frequency -
00696         once in every frequency child selections.
00697         Helps in rare cases where rave ignores the best move. 
00698         Set frequency to 0 to switch it off. */
00699     void SetRandomizeRaveFrequency(int frequency);
00700 
00701     /** Don't update RAVE value if opponent played the same move first.
00702         Default is false (since it depends on the game and move
00703         representation, if it should be used). */
00704     bool RaveCheckSame() const;
00705 
00706     /** See RaveCheckSame() */
00707     void SetRaveCheckSame(bool enable);
00708 
00709     /** First play urgency.
00710         The value for unexplored moves. According to UCT they should
00711         always be preferred to moves, that have been played at least once.
00712         According to the MoGo tech report, it can be useful to use smaller
00713         values (as low as 1) to encorouge early exploitation.
00714         Default value is 10000.
00715         @see @ref sguctsearchweights */
00716     SgUctValue FirstPlayUrgency() const;
00717 
00718     /** See FirstPlayUrgency() */
00719     void SetFirstPlayUrgency(SgUctValue firstPlayUrgency);
00720 
00721     /** Log one-line summary for each game during Search() to a file.
00722         @todo File name still is hard-coded to "uctsearch.log" */
00723     bool LogGames() const;
00724 
00725     /** See LogGames() */
00726     void SetLogGames(bool enable);
00727 
00728     /** Maximum game length.
00729         If the number of moves in a game exceed this length, it will be
00730         counted as a loss.
00731         The default is @c numeric_limits<size_t>::max() */
00732     std::size_t MaxGameLength() const;
00733 
00734     /** See MaxGameLength() */
00735     void SetMaxGameLength(std::size_t maxGameLength);
00736 
00737     /** Required number of simulations to expand a node in the tree.
00738         The default is 2, which means a node will be expanded on the second
00739         visit. */
00740     SgUctValue ExpandThreshold() const;
00741 
00742     /** See ExpandThreshold() */
00743     void SetExpandThreshold(SgUctValue expandThreshold);
00744 
00745     /** The number of playouts per simulated game.
00746         Useful for multi-threading to increase the workload of the threads.
00747         Default is 1. */
00748     std::size_t NumberPlayouts() const;
00749 
00750     void SetNumberPlayouts(std::size_t n);
00751 
00752     /** Use the RAVE algorithm (Rapid Action Value Estimation).
00753         See Gelly, Silver 2007 in the references in the class description.
00754         In difference to the original description of the RAVE algorithm,
00755         no "RAVE bias term" is used. The estimated value of a move is the
00756         weighted mean of the move value and the RAVE value and then a
00757         single UCT-like bias term is added.
00758         @see RaveWeightFunc */
00759     bool Rave() const;
00760 
00761     /** See Rave() */
00762     void SetRave(bool enable);
00763 
00764     /** See SgUctMoveSelect */
00765     SgUctMoveSelect MoveSelect() const;
00766 
00767     /** See SgUctMoveSelect */
00768     void SetMoveSelect(SgUctMoveSelect moveSelect);
00769 
00770     /** See @ref sguctsearchweights. */
00771     float RaveWeightInitial() const;
00772 
00773     /** See @ref sguctsearchweights. */
00774     void SetRaveWeightInitial(float value);
00775 
00776     /** See @ref sguctsearchweights. */
00777     float RaveWeightFinal() const;
00778 
00779     /** See @ref sguctsearchweights. */
00780     void SetRaveWeightFinal(float value);
00781 
00782     /** Weight RAVE updates.
00783         Gives more weight to moves that are closer to the position for which
00784         the RAVE statistics are stored. The weighting function is linearly
00785         decreasing from 2 to 0 with the move number from the position for
00786         which the RAVE statistics are stored to the end of the simulated game. */
00787     bool WeightRaveUpdates() const;
00788 
00789     /** See WeightRaveUpdates() */
00790     void SetWeightRaveUpdates(bool enable);
00791 
00792     /** Whether search uses virtual loss. */
00793     bool VirtualLoss() const;
00794 
00795     /** See VirtualLoss() */
00796     void SetVirtualLoss(bool enable);
00797 
00798     /** Prune nodes with low counts if tree is full.
00799         This will prune nodes below a minimum count, if the tree gets full
00800         during a search. The minimum count is PruneMinCount() at the beginning
00801         of the search and is doubled every time a pruning operation does not
00802         reduce the tree by at least a factor of 2. The creation of the pruned
00803         tree uses the temporary tree (see GetTempTree()). */
00804     bool PruneFullTree() const;
00805 
00806     /** See PruneFullTree() */
00807     void SetPruneFullTree(bool enable);
00808 
00809     /** See PruneFullTree() */
00810     SgUctValue PruneMinCount() const;
00811 
00812     /** See PruneFullTree() */
00813     void SetPruneMinCount(SgUctValue n);
00814 
00815     /** Terminate the search if the counts can no longer be represented
00816         precisely by SgUctValue.
00817         Default is true. */
00818     bool CheckFloatPrecision() const;
00819 
00820     /** See CheckFloatPrecision() */
00821     void SetCheckFloatPrecision(bool enable);
00822 
00823     void SetMpiSynchronizer(const SgMpiSynchronizerHandle &synchronizerHandle);
00824 
00825     SgMpiSynchronizerHandle MpiSynchronizer();
00826 
00827     const SgMpiSynchronizerHandle MpiSynchronizer() const;
00828 
00829     // @} // name
00830 
00831 
00832     /** @name Statistics */
00833     // @{
00834 
00835     const SgUctSearchStat& Statistics() const;
00836 
00837     void WriteStatistics(std::ostream& out) const;
00838 
00839     // @} // name
00840 
00841     /** Get state of one of the threads.
00842         Requires: ThreadsCreated() */
00843     SgUctThreadState& ThreadState(int i) const;
00844 
00845     /** Check if threads are already created.
00846         The threads are created at the beginning of the first search
00847         (to allow multi-step construction with setting the policy after
00848         the constructor call). */
00849     bool ThreadsCreated() const;
00850 
00851     /** Create threads.
00852         The threads are created at the beginning of the first search
00853         (to allow multi-step construction with setting the policy after
00854         the constructor call). This function needs to be called explicitely
00855         only, if a thread state is going to be used before the first search. */
00856     void CreateThreads();
00857 
00858 private:
00859     typedef boost::recursive_mutex::scoped_lock GlobalLock;
00860 
00861     friend class Thread;
00862 
00863     class Thread
00864     {
00865     public:
00866         std::auto_ptr<SgUctThreadState> m_state;
00867 
00868         Thread(SgUctSearch& search, std::auto_ptr<SgUctThreadState> state);
00869 
00870         ~Thread();
00871 
00872         void StartPlay();
00873 
00874         void WaitPlayFinished();
00875 
00876     private:
00877         /** Copyable function object that invokes Thread::operator().
00878             Needed because the the constructor of boost::thread copies the
00879             function object argument. */
00880         class Function
00881         {
00882         public:
00883             Function(Thread& thread);
00884 
00885             void operator()();
00886 
00887         private:
00888             Thread& m_thread;
00889         };
00890 
00891         friend class Thread::Function;
00892 
00893         SgUctSearch& m_search;
00894 
00895         bool m_quit;
00896 
00897         boost::barrier m_threadReady;
00898 
00899         boost::mutex m_startPlayMutex;
00900 
00901         boost::mutex m_playFinishedMutex;
00902 
00903         boost::condition m_startPlay;
00904 
00905         boost::condition m_playFinished;
00906 
00907         boost::mutex::scoped_lock m_playFinishedLock;
00908 
00909         GlobalLock m_globalLock;
00910 
00911         /** The thread.
00912             Order dependency: must be constructed as the last member, because
00913             the constructor starts the thread. */
00914         boost::thread m_thread;
00915 
00916         void operator()();
00917 
00918         void PlayGames();
00919     };
00920 
00921     std::auto_ptr<SgUctThreadStateFactory> m_threadStateFactory;
00922 
00923     /** See LogGames() */
00924     bool m_logGames;
00925 
00926     /** See Rave() */
00927     bool m_rave;
00928    
00929     /** See KnowledgeThreshold() */
00930     std::vector<SgUctValue> m_knowledgeThreshold;
00931 
00932     /** Flag indicating that the search was terminated because the maximum
00933         time or number of games was reached. */
00934     volatile bool m_aborted;
00935     
00936     volatile bool m_isTreeOutOfMemory;
00937 
00938     std::auto_ptr<boost::barrier> m_searchLoopFinished;
00939 
00940     /** See SgUctEarlyAbortParam. */
00941     bool m_wasEarlyAbort;
00942 
00943     /** See SgUctEarlyAbortParam.
00944         The auto pointer is empty, if no early abort is used. */
00945     std::auto_ptr<SgUctEarlyAbortParam> m_earlyAbort;
00946 
00947     /** See SgUctMoveSelect */
00948     SgUctMoveSelect m_moveSelect;
00949 
00950     /** See RaveCheckSame() */
00951     bool m_raveCheckSame;
00952 
00953     /** See SetRandomizeRaveFrequency() */
00954     int m_randomizeRaveFrequency;
00955 
00956     /** See LockFree() */
00957     bool m_lockFree;
00958 
00959     /** See WeightRaveUpdates() */
00960     bool m_weightRaveUpdates;
00961 
00962     /** See PruneFullTree() */
00963     bool m_pruneFullTree;
00964 
00965     /** See CheckFloatPrecision() */
00966     bool m_checkFloatPrecision;
00967 
00968     /** See NumberThreads() */
00969     unsigned int m_numberThreads;
00970 
00971     /** See NumberPlayouts() */
00972     std::size_t m_numberPlayouts;
00973 
00974     /** See MaxNodes() */
00975     std::size_t m_maxNodes;
00976 
00977     /** See PruneMinCount() */
00978     SgUctValue m_pruneMinCount;
00979 
00980     /** See parameter moveRange in constructor */
00981     const int m_moveRange;
00982 
00983     /** See MaxGameLength() */
00984     std::size_t m_maxGameLength;
00985 
00986     /** See ExpandThreshold() */
00987     SgUctValue m_expandThreshold;
00988 
00989     /** Number of games limit for the current search. */
00990     SgUctValue m_maxGames;
00991 
00992     /** Number of games played in the current search. */
00993     SgUctValue m_numberGames;
00994 
00995     SgUctValue m_startRootMoveCount;
00996 
00997     /** Interval in number of games in which to check time abort.
00998         Avoids that the potentially expensive SgTime::Get() is called after
00999         every game. The interval is updated dynamically according to the
01000         current games/sec, such that it is called ten times per second
01001         (if the total search time is at least one second, otherwise ten times
01002         per total maximum search time) */
01003     SgUctValue m_checkTimeInterval;
01004 
01005     volatile SgUctValue m_nextCheckTime;
01006 
01007     double m_lastScoreDisplayTime;
01008 
01009     /** See BiasTermConstant() */
01010     float m_biasTermConstant;
01011 
01012     /** See FirstPlayUrgency() */
01013     SgUctValue m_firstPlayUrgency;
01014 
01015     /** See @ref sguctsearchweights. */
01016     float m_raveWeightInitial;
01017 
01018     /** See @ref sguctsearchweights. */
01019     float m_raveWeightFinal;
01020 
01021     /** 1 / m_raveWeightInitial precomputed for efficiency */
01022     SgUctValue m_raveWeightParam1;
01023 
01024     /** m_raveWeightInitial / m_raveWeightFinal precomputed for efficiency */
01025     SgUctValue m_raveWeightParam2;
01026 
01027     /** Time limit for current search. */
01028     double m_maxTime;
01029 
01030     /** See VirtualLoss() */
01031     bool m_virtualLoss;
01032 
01033     std::string m_logFileName;
01034 
01035     SgTimer m_timer;
01036 
01037     SgUctTree m_tree;
01038 
01039     /** See GetTempTree() */
01040     SgUctTree m_tempTree;
01041 
01042     /** See parameter rootFilter in function Search() */
01043     std::vector<SgMove> m_rootFilter;
01044 
01045     std::ofstream m_log;
01046 
01047     /** Mutex for protecting global variables during multi-threading.
01048         Currently, only the play-out phase of games is thread safe, therefore
01049         this lock is always locked elsewhere (in-tree phase, updating of
01050         values and statistics, etc.) */
01051     boost::recursive_mutex m_globalMutex;
01052 
01053     SgUctSearchStat m_statistics;
01054 
01055     /** List of threads.
01056         The elements are owned by the vector (shared_ptr is only used because
01057         auto_ptr should not be used with standard containers) */
01058     std::vector<boost::shared_ptr<Thread> > m_threads;
01059 
01060 #if SG_UCTFASTLOG
01061     SgFastLog m_fastLog;
01062 #endif
01063 
01064     boost::shared_ptr<SgMpiSynchronizer> m_mpiSynchronizer;
01065 
01066 
01067     void ApplyRootFilter(std::vector<SgUctMoveInfo>& moves);
01068 
01069     void PropagateProvenStatus(const vector<const SgUctNode*>& nodes);
01070 
01071     bool CheckAbortSearch(SgUctThreadState& state);
01072 
01073     bool CheckEarlyAbort() const;
01074 
01075     bool CheckCountAbort(SgUctThreadState& state,
01076                          SgUctValue remainingGames) const;
01077 
01078     void Debug(const SgUctThreadState& state, const std::string& textLine);
01079 
01080     void DeleteThreads();
01081 
01082     void ExpandNode(SgUctThreadState& state, const SgUctNode& node);
01083 
01084     void CreateChildren(SgUctThreadState& state, const SgUctNode& node,
01085                         bool deleteChildTrees);
01086 
01087     SgUctValue GetBound(bool useRave, SgUctValue logPosCount,
01088                         const SgUctNode& child) const;
01089 
01090     SgUctValue GetValueEstimate(bool useRave, const SgUctNode& child) const;
01091 
01092     SgUctValue GetValueEstimateRave(const SgUctNode& child) const;
01093 
01094     SgUctValue Log(SgUctValue x) const;
01095 
01096     bool NeedToComputeKnowledge(const SgUctNode* current);
01097 
01098     void PlayGame(SgUctThreadState& state, GlobalLock* lock);
01099 
01100     bool PlayInTree(SgUctThreadState& state, bool& isTerminal);
01101 
01102     bool PlayoutGame(SgUctThreadState& state, std::size_t playout);
01103 
01104     void PrintSearchProgress(double currTime) const;
01105     
01106     void SearchLoop(SgUctThreadState& state, GlobalLock* lock);
01107 
01108     const SgUctNode& SelectChild(int& randomizeCounter, const SgUctNode& node);
01109 
01110     std::string SummaryLine(const SgUctGameInfo& info) const;
01111 
01112     void UpdateCheckTimeInterval(double time);
01113 
01114     void UpdateDynRaveBias();
01115 
01116     void UpdateRaveValues(SgUctThreadState& state);
01117 
01118     void UpdateRaveValues(SgUctThreadState& state, std::size_t playout);
01119 
01120     void UpdateRaveValues(SgUctThreadState& state, std::size_t playout,
01121                           SgUctValue eval, std::size_t i,
01122                           const std::size_t firstPlay[],
01123                           const std::size_t firstPlayOpp[]);
01124 
01125     void UpdateStatistics(const SgUctGameInfo& info);
01126 
01127     void UpdateTree(const SgUctGameInfo& info);
01128 };
01129 
01130 inline float SgUctSearch::BiasTermConstant() const
01131 {
01132     return m_biasTermConstant;
01133 }
01134 
01135 inline bool SgUctSearch::CheckFloatPrecision() const
01136 {
01137     return m_checkFloatPrecision;
01138 }
01139 
01140 inline SgUctValue SgUctSearch::ExpandThreshold() const
01141 {
01142     return m_expandThreshold;
01143 }
01144 
01145 inline SgUctValue SgUctSearch::FirstPlayUrgency() const
01146 {
01147     return m_firstPlayUrgency;
01148 }
01149 
01150 inline SgUctValue SgUctSearch::InverseEval(SgUctValue eval)
01151 {
01152     return (1 - eval);
01153 }
01154 
01155 inline SgUctValue SgUctSearch::InverseEstimate(SgUctValue eval)
01156 {
01157     return (1 - eval);
01158 }
01159 
01160 inline bool SgUctSearch::LockFree() const
01161 {
01162     return m_lockFree;
01163 }
01164 
01165 inline const SgUctGameInfo& SgUctSearch::LastGameInfo() const
01166 {
01167     return ThreadState(0).m_gameInfo;
01168 }
01169 
01170 inline bool SgUctSearch::LogGames() const
01171 {
01172     return m_logGames;
01173 }
01174 
01175 inline std::size_t SgUctSearch::MaxGameLength() const
01176 {
01177     return m_maxGameLength;
01178 }
01179 
01180 inline std::size_t SgUctSearch::MaxNodes() const
01181 {
01182     return m_maxNodes;
01183 }
01184 
01185 inline SgUctMoveSelect SgUctSearch::MoveSelect() const
01186 {
01187     return m_moveSelect;
01188 }
01189 
01190 inline unsigned int SgUctSearch::NumberThreads() const
01191 {
01192     return m_numberThreads;
01193 }
01194 
01195 inline std::size_t SgUctSearch::NumberPlayouts() const
01196 {
01197     return m_numberPlayouts;
01198 }
01199 
01200 inline void SgUctSearch::PlayGame()
01201 {
01202     PlayGame(ThreadState(0), 0);
01203 }
01204 
01205 inline bool SgUctSearch::PruneFullTree() const
01206 {
01207     return m_pruneFullTree;
01208 }
01209 
01210 inline SgUctValue SgUctSearch::PruneMinCount() const
01211 {
01212     return m_pruneMinCount;
01213 }
01214 
01215 inline bool SgUctSearch::Rave() const
01216 {
01217     return m_rave;
01218 }
01219 
01220 inline bool SgUctSearch::RaveCheckSame() const
01221 {
01222     return m_raveCheckSame;
01223 }
01224 
01225 inline float SgUctSearch::RaveWeightInitial() const
01226 {
01227     return m_raveWeightInitial;
01228 }
01229 
01230 inline float SgUctSearch::RaveWeightFinal() const
01231 {
01232     return m_raveWeightFinal;
01233 }
01234 
01235 inline void SgUctSearch::SetBiasTermConstant(float biasTermConstant)
01236 {
01237     m_biasTermConstant = biasTermConstant;
01238 }
01239 
01240 inline void SgUctSearch::SetCheckFloatPrecision(bool enable)
01241 {
01242     m_checkFloatPrecision = enable;
01243 }
01244 
01245 inline void SgUctSearch::SetExpandThreshold(SgUctValue expandThreshold)
01246 {
01247     SG_ASSERT(expandThreshold >= 0);
01248     m_expandThreshold = expandThreshold;
01249 }
01250 
01251 inline void SgUctSearch::SetFirstPlayUrgency(SgUctValue firstPlayUrgency)
01252 {
01253     m_firstPlayUrgency = firstPlayUrgency;
01254 }
01255 
01256 inline void SgUctSearch::SetLockFree(bool enable)
01257 {
01258     m_lockFree = enable;
01259 }
01260 
01261 inline void SgUctSearch::SetLogGames(bool enable)
01262 {
01263     m_logGames = enable;
01264 }
01265 
01266 inline void SgUctSearch::SetMaxGameLength(std::size_t maxGameLength)
01267 {
01268     m_maxGameLength = maxGameLength;
01269 }
01270 
01271 inline void SgUctSearch::SetMaxNodes(std::size_t maxNodes)
01272 {
01273     m_maxNodes = maxNodes;
01274     if (m_threads.size() > 0) // Threads already created
01275         m_tree.SetMaxNodes(m_maxNodes);
01276 }
01277 
01278 inline void SgUctSearch::SetMoveSelect(SgUctMoveSelect moveSelect)
01279 {
01280     m_moveSelect = moveSelect;
01281 }
01282 
01283 inline std::vector<SgUctValue> SgUctSearch::KnowledgeThreshold() const
01284 {
01285     return m_knowledgeThreshold;
01286 }
01287 
01288 inline void 
01289 SgUctSearch::SetKnowledgeThreshold(const std::vector<SgUctValue>& t)
01290 {
01291     m_knowledgeThreshold = t;
01292 }
01293 
01294 inline void SgUctSearch::SetNumberPlayouts(std::size_t n)
01295 {
01296     SG_ASSERT(n >= 1);
01297     m_numberPlayouts = n;
01298 }
01299 
01300 inline void SgUctSearch::SetPruneFullTree(bool enable)
01301 {
01302     m_pruneFullTree = enable;
01303 }
01304 
01305 inline void SgUctSearch::SetPruneMinCount(SgUctValue n)
01306 {
01307     m_pruneMinCount = n;
01308 }
01309 
01310 inline void SgUctSearch::SetMpiSynchronizer(const SgMpiSynchronizerHandle 
01311                                             &synchronizerHandle)
01312 {
01313     m_mpiSynchronizer = SgMpiSynchronizerHandle(synchronizerHandle);
01314 }
01315 
01316 inline SgMpiSynchronizerHandle SgUctSearch::MpiSynchronizer()
01317 {
01318     return SgMpiSynchronizerHandle(m_mpiSynchronizer);
01319 }
01320 
01321 inline const SgMpiSynchronizerHandle SgUctSearch::MpiSynchronizer() const
01322 {
01323     return SgMpiSynchronizerHandle(m_mpiSynchronizer);
01324 }
01325 
01326 inline int SgUctSearch::RandomizeRaveFrequency() const
01327 {
01328     return m_randomizeRaveFrequency;
01329 }
01330 
01331 inline void SgUctSearch::SetRandomizeRaveFrequency(int frequency)
01332 {
01333     m_randomizeRaveFrequency = frequency;    
01334 }
01335 
01336 inline void SgUctSearch::SetRaveCheckSame(bool enable)
01337 {
01338     m_raveCheckSame = enable;
01339 }
01340 
01341 inline void SgUctSearch::SetRaveWeightFinal(float value)
01342 {
01343     m_raveWeightFinal = value;
01344 }
01345 
01346 inline void SgUctSearch::SetRaveWeightInitial(float value)
01347 {
01348     m_raveWeightInitial = value;
01349 }
01350 
01351 inline void SgUctSearch::SetWeightRaveUpdates(bool enable)
01352 {
01353     m_weightRaveUpdates = enable;
01354 }
01355 
01356 inline bool SgUctSearch::VirtualLoss() const
01357 {
01358     return m_virtualLoss;
01359 }
01360 
01361 inline void SgUctSearch::SetVirtualLoss(bool enable)
01362 {
01363     m_virtualLoss = enable;
01364 }
01365 
01366 inline const SgUctSearchStat& SgUctSearch::Statistics() const
01367 {
01368     return m_statistics;
01369 }
01370 
01371 inline bool SgUctSearch::ThreadsCreated() const
01372 {
01373     return (m_threads.size() > 0);
01374 }
01375 
01376 inline SgUctThreadState& SgUctSearch::ThreadState(int i) const
01377 {
01378     SG_ASSERT(static_cast<std::size_t>(i) < m_threads.size());
01379     return *m_threads[i]->m_state;
01380 }
01381 
01382 inline const SgUctTree& SgUctSearch::Tree() const
01383 {
01384     return m_tree;
01385 }
01386 
01387 inline bool SgUctSearch::WasEarlyAbort() const
01388 {
01389     return m_wasEarlyAbort;
01390 }
01391 
01392 inline bool SgUctSearch::WeightRaveUpdates() const
01393 {
01394     return m_weightRaveUpdates;
01395 }
01396 
01397 //----------------------------------------------------------------------------
01398 
01399 #endif // SG_UCTSEARCH_H


Sun Mar 13 2011 Doxygen 1.7.1