alphaBeta2.h
Go to the documentation of this file.
00001 /* alphaBeta2.h
00002  */
00003 #ifndef OSL_ALPHA_BETA2_H
00004 #define OSL_ALPHA_BETA2_H
00005 
00006 #include "osl/search/realizationProbability.h"
00007 #include "osl/search/searchBase.h"
00008 #include "osl/search/searchState2.h"
00009 #include "osl/search/searchRecorder.h"
00010 #include "osl/search/passCounter.h"
00011 #include "osl/search/killerMoveTable.h"
00012 #include "osl/search/searchTimer.h"
00013 #include "osl/eval/evalTraits.h"
00014 #include "osl/eval/ml/openMidEndingEval.h"
00015 #include "osl/eval/progressEval.h"
00016 #include "osl/container/moveStack.h"
00017 #include "osl/container/moveLogProbVector.h"
00018 #include "osl/stat/average.h"
00019 #include "osl/oslConfig.h"
00020 #include <boost/scoped_array.hpp>
00021 #include <boost/noncopyable.hpp>
00022 #include <iosfwd>
00023 
00024 namespace osl
00025 {
00026   namespace search
00027   {
00028     class SimpleHashRecord;
00029     class SimpleHashTable;
00030     class MoveGenerator;
00031     struct MoveWithComment;
00032 
00033     class AlphaBeta2Window
00034     {
00035       CArray<int,2> values;
00036     public:
00037       explicit AlphaBeta2Window(int a=0) { values.fill(a); }
00038       AlphaBeta2Window(int a, int b) 
00039       {
00040         values[0] = a;
00041         values[1] = b;
00042       }
00043       AlphaBeta2Window(Player P, int a=0, int b=0) 
00044       {
00045         alpha(P) = a;
00046         beta(P) = b;
00047       }
00048       int& alpha(Player P) { return values[P]; }
00049       int& beta(Player P) { return values[alt(P)]; }
00050 
00051       int alpha(Player P) const { return values[P]; }
00052       int beta(Player P) const { return values[alt(P)]; }
00053       bool isConsistent() const { 
00054         return eval::notLessThan(BLACK, beta(BLACK), alpha(BLACK));
00055       }
00056       bool null() const { return values[0] == values[1]; }
00057       bool operator==(const AlphaBeta2Window& r) const
00058       {
00059         return values == r.values;
00060       }
00061     };
00062 
00066     template <class EvalT>
00067     struct AlphaBeta2Common
00068 #if OSL_WORDSIZE == 32
00069       : public misc::Align16New
00070 #endif
00071     {
00072       static int rootLimitBias() 
00073       {
00074         return 0;
00075       }
00076       static int leafLimit() 
00077       {
00078         static int value = 300 + rootLimitBias();
00079         return value;
00080       }
00081 
00082       enum { MaxDepth = SearchState2Core::MaxDepth };
00083       EvalT eval;
00084       PassCounter pass_count;
00085       enum MoveType { INITIAL, HASH=INITIAL, TACTICAL, KILLER, PASS, ALL, FINISH };
00087       CArray<MoveType, MaxDepth> move_type;
00088       CArray<bool, MaxDepth> in_pv;
00089       typedef FixedCapacityVector<Move,4> killer_t;
00090       CArray<killer_t, MaxDepth> killers;
00091       const MoveVector *root_ignore_moves; // acquaintance
00092       bool prediction_for_speculative_search;
00094       int multi_pv;
00095       
00096       explicit AlphaBeta2Common(const NumEffectState& s) 
00097         : eval(s), root_ignore_moves(0), prediction_for_speculative_search(false),
00098           multi_pv(0)
00099       {
00100         in_pv[0] = true;
00101       }
00102     };
00103     struct RootPV
00104     {
00105       SearchState2::PVVector pv;
00106       int depth, eval;
00107       RootPV(int root_limit, const SearchState2::PVVector &p, int v)
00108         : pv(p), depth(root_limit), eval(v)
00109       {
00110       }
00111     };
00112     struct AlphaBeta2SharedRoot
00113     {
00115       vector<int> root_values, root_values_for_iteration;
00116       vector<Move> best_move_for_iteration;
00118       vector<RootPV> last_pv;
00120       Move last_root_move;
00122       int last_root_value_update;
00123       AlphaBeta2SharedRoot() : last_root_value_update(0)
00124       {
00125       }
00126       void showLastPv(int limit) const;
00127       int sameBestMoves() const 
00128       {
00129         int ret = 0;
00130         for (int i=best_move_for_iteration.size()-2; i>=0; --i, ++ret)
00131           if (best_move_for_iteration[i] != best_move_for_iteration[i+1])
00132             break;
00133         return ret;
00134       }
00135     };
00136 
00137     template <class EvalT> struct AlphaBeta2Parallel;
00141     template <class EvalT>
00142     class AlphaBeta2Tree
00143       : public SearchBase<EvalT,SimpleHashTable,CountRecorder,RealizationProbability>,
00144         public SearchState2, public SearchTimer, protected AlphaBeta2Common<EvalT>, boost::noncopyable
00145     {
00146     public:
00147       typedef EvalT eval_t;
00148       typedef AlphaBeta2Common<EvalT> common_t;
00149       enum { MaxDepth = SearchState2Core::MaxDepth };
00150     protected:
00152       size_t node_count;
00153       FixedCapacityVector<MoveGenerator*, MaxDepth> generators;
00154       stat::Average mpn, mpn_cut, alpha_update, last_alpha_update;
00155       stat::Average ext, ext_limit;
00156       boost::shared_ptr<AlphaBeta2Parallel<EvalT> > shared;
00157       boost::shared_ptr<AlphaBeta2SharedRoot> shared_root;
00158     protected:
00159       static CArray<int, SearchState2Core::MaxDepth> depth_node_count;
00160       AlphaBeta2Tree(const NumEffectState& s, checkmate_t& checker,
00161                      SimpleHashTable *t, CountRecorder&);
00162       // share parallel data for split
00163       AlphaBeta2Tree(const AlphaBeta2Tree& src, AlphaBeta2Parallel<EvalT> *);
00164       ~AlphaBeta2Tree();
00165     private:
00166       void throwStop();
00167     public:
00168       struct BetaCut {};
00169       bool stopping() const
00170       { 
00171         return stop_tree || SearchTimer::stopping();
00172       }
00173       void testStop() { 
00174         throwIfNoMoreTime(this->recorder.allNodeCount());
00175         if (stop_tree)
00176           throw BetaCut();
00177       }
00178     public:
00179       typedef AlphaBeta2Window Window;
00180       size_t nodeCount() const { return node_count; }
00181       static int rootAlpha(Player P, int last_value, Progress16 progress);
00182       static int stableThreshold(Player P, int last_value);
00183 
00184       template <Player P>
00185       const MoveLogProb nextMove();
00186     protected:
00187       void updateRootPV(Player P, std::ostream&, int, Move);
00188       void addMultiPV(Player P, int, Move);
00189       bool isStable(Player P, int new_value) const;
00190       void showFailLow(int result, Move m) const;
00191     private:
00192       void showPV(std::ostream&, int, Move, char stable) const;
00193     public:
00194       template <Player P> struct NextMove;
00195       friend struct NextMove<BLACK>;
00196       friend struct NextMove<WHITE>;
00197       template <Player P> struct NextQMove;
00198       friend struct NextQMove<BLACK>;
00199       friend struct NextQMove<WHITE>;
00200     protected:
00209       template <Player P>
00210       int alphaBetaSearch(const MoveLogProb& move, Window window,
00211                           bool in_pv);
00212       template <Player P>
00213       int alphaBetaSearchAfterMove(const MoveLogProb& move, 
00214                                    Window window, bool in_pv);
00215       template <Player P> int quiesce(Window);
00216       template <Player P> int quiesceStable(Window);
00217       template <Player P> int quiesceExp(Window);
00218 
00219       template <Player P>
00220       int searchAllMoves(SimpleHashRecord*, Window w);
00221       template <Player P>
00222       int searchAllMoves(Move m, int limit_consumption, 
00223                          SimpleHashRecord*, Window w);
00224 
00226       template <Player P>
00227       bool tryCheckmate(SimpleHashRecord *record, bool in_pv, Move& checkmate_move);
00229       template <Player P>
00230       bool tryCheckmateAgain(SimpleHashRecord *record, Move& checkmate_move,
00231                              int node_count,
00232                              int best_value);
00233 
00235       template <Player P>
00236       void testThreatmate(SimpleHashRecord *record, bool in_pv);
00237 
00239       template <Player P>
00240       void examineMovesRoot(const MoveLogProbVector&, size_t, Window,
00241                             MoveLogProb&, int&);
00242 
00243       template <Player P> int quiesceRoot(Window, int depth_left, Move& best_move, DualThreatmateState);
00244       template <Player P> int quiesce(Window, int depth_left, DualThreatmateState);
00245       template <Player P>
00246       bool quiesceWithMove(Move, Window&, int, Move&, int&, const DualThreatmateState&);
00247 
00248       void updateCheckmateCount();
00249       bool tryPass(SimpleHashRecord *record, Player P) const;
00250       MoveGenerator& makeGenerator();
00251       static MoveGenerator *alloc();
00252       static void dealloc(MoveGenerator *);
00253 #ifdef OSL_SMP
00254     public:
00255       friend struct AlphaBeta2Parallel<EvalT>;
00256       struct NodeProperty;
00257       template <Player P> struct SearchJob;
00258       struct SearchJobData;
00259       struct Shared;
00260       friend struct Shared;
00261       friend struct SearchJob<BLACK>;
00262       friend struct SearchJob<WHITE>;
00263     protected:
00264       template <Player P>
00265       void examineMovesRootPar(const MoveLogProbVector&, size_t, Window,
00266                                MoveLogProb&, int&);
00267       void examineMovesRootPar(int tree_id);
00268       template <Player P>
00269       void testMoveRoot(int tree_id, const MoveLogProb&);
00270 
00271       template <Player P>
00272       bool examineMovesOther(Window& w, MoveLogProb& best_move, int& best_value, 
00273                              int& tried_moves, int& alpha_update, int& last_alpha_update);
00274       void examineMovesOther(int tree_id);
00275       template <Player P>
00276       bool testMoveOther(int tree_id, const MoveLogProb&, size_t index, bool in_pv);
00277 #endif
00278     };
00279 
00283     template <class EvalT>
00284     class AlphaBeta2
00285       : public AlphaBeta2Tree<EvalT>
00286     {
00287     public:
00288       typedef AlphaBeta2Tree<EvalT> base_t;
00289       typedef typename base_t::checkmate_t checkmate_t;
00290       typedef typename base_t::Window Window;
00291     public:
00292       AlphaBeta2(const NumEffectState& s, checkmate_t& checker,
00293                  SimpleHashTable *t, CountRecorder&);
00294       ~AlphaBeta2();
00295 
00302       template <Player P>
00303       int alphaBetaSearchRoot(Window window, MoveLogProb& best_move,
00304                               int limit);
00305       static const Window fullWindow(Player P)
00306       {
00307         return Window(P, base_t::winThreshold(alt(P)), base_t::winThreshold(P));
00308       }
00309       int alphaBetaSearchRoot(Window window, MoveLogProb& best_move, int limit)
00310       {
00311         const Player P = this->state().turn();
00312         if (P == BLACK)
00313           return alphaBetaSearchRoot<BLACK>(window, best_move, limit);
00314         else
00315           return alphaBetaSearchRoot<WHITE>(window, best_move, limit);
00316       }
00317       int alphaBetaSearchRoot(MoveLogProb& best_move, int limit);
00318     
00322       Move computeBestMoveIteratively(int limit,
00323                                       const int step=100, 
00324                                       int initialLimit=600,
00325                                       size_t nodeLimit=1600000,
00326                                       const TimeAssigned& assign=TimeAssigned(MilliSeconds::Interval(60*1000)),
00327                                       MoveWithComment *additional_info=0);
00328       bool isReasonableMove(Move move, int pawn_sacrifice=1);
00329       void setRootIgnoreMoves(const MoveVector *rim, bool prediction) 
00330       {
00331         assert(!prediction || rim);
00332         this->root_ignore_moves = rim;
00333         this->prediction_for_speculative_search = prediction;
00334       }
00335 
00336       static void showNodeDepth(std::ostream&);
00337       static void clearNodeDepth();
00338       void enableMultiPV(unsigned int width) { this->multi_pv = width; }
00339       const AlphaBeta2SharedRoot sharedRootInfo() const { return *(this->shared_root); }
00340     public:
00341       void setRoot(int limit);
00342       void makeMove(Move);
00343     private:
00344       enum PVCheckmateStatus {
00345         PVStable, PVThreatmateNotRecord, PVThreatmate, PVCheckmate, 
00346       };
00347       PVCheckmateStatus findCheckmateInPV(int verify_node, CArray<bool,2>& king_in_threat);
00348     }; // class AlphaBeta2
00349 
00350   } // namespace search
00351   typedef search::AlphaBeta2<eval::ProgressEval> AlphaBeta2ProgressEval;
00352   typedef search::AlphaBeta2<eval::ml::OpenMidEndingEval> AlphaBeta2OpenMidEndingEval;
00353 } // namespace osl
00354 
00355 #endif /* OSL_ALPHA_BETA2_H */
00356 // ;;; Local Variables:
00357 // ;;; mode:c++
00358 // ;;; c-basic-offset:2
00359 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines