00001
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 class 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 static int value = OslConfig::useLogLinearProbability() ? 200 : 0;
00075 return value;
00076 }
00077 static int leafLimit()
00078 {
00079 static int value = 300 + rootLimitBias();
00080 return value;
00081 }
00082
00083 enum { MaxDepth = SearchState2Core::MaxDepth };
00084 EvalT eval;
00085 PassCounter pass_count;
00086 enum MoveType { INITIAL, HASH=INITIAL, TACTICAL, KILLER, PASS, ALL, FINISH };
00088 CArray<MoveType, MaxDepth> move_type;
00089 CArray<bool, MaxDepth> in_pv;
00090 typedef FixedCapacityVector<Move,4> killer_t;
00091 CArray<killer_t, MaxDepth> killers;
00092 const MoveVector *root_ignore_moves;
00093 bool prediction_for_speculative_search;
00095 int multi_pv;
00096
00097 explicit AlphaBeta2Common(const NumEffectState& s)
00098 : eval(s), root_ignore_moves(0), prediction_for_speculative_search(false),
00099 multi_pv(0)
00100 {
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> last_root_value;
00117 vector<RootPV> last_pv;
00119 Move last_root_move;
00121 int last_root_value_update;
00122 AlphaBeta2SharedRoot() : last_root_value_update(0)
00123 {
00124 }
00125 void showLastPv(int limit) const;
00126 };
00127
00128 template <class EvalT> class AlphaBeta2Parallel;
00132 template <class EvalT>
00133 class AlphaBeta2Tree
00134 : public SearchBase<EvalT,SimpleHashTable,CountRecorder,RealizationProbability>,
00135 public SearchState2, public SearchTimer, protected AlphaBeta2Common<EvalT>, boost::noncopyable
00136 {
00137 public:
00138 typedef EvalT eval_t;
00139 typedef AlphaBeta2Common<EvalT> common_t;
00140 enum { MaxDepth = SearchState2Core::MaxDepth };
00141 protected:
00143 size_t node_count;
00144 FixedCapacityVector<MoveGenerator*, MaxDepth> generators;
00145 stat::Average mpn, mpn_cut, alpha_update, last_alpha_update;
00146 stat::Average ext, ext_limit;
00147 boost::shared_ptr<AlphaBeta2Parallel<EvalT> > shared;
00148 boost::shared_ptr<AlphaBeta2SharedRoot> shared_root;
00149 protected:
00150 static CArray<int, SearchState2Core::MaxDepth> depth_node_count;
00151 AlphaBeta2Tree(const NumEffectState& s, checkmate_t& checker,
00152 SimpleHashTable *t, CountRecorder&);
00153
00154 AlphaBeta2Tree(const AlphaBeta2Tree& src, AlphaBeta2Parallel<EvalT> *);
00155 ~AlphaBeta2Tree();
00156 private:
00157 void throwStop();
00158 public:
00159 struct BetaCut {};
00160 bool stopping() const
00161 {
00162 return stop_tree || SearchTimer::stopping();
00163 }
00164 void testStop() {
00165 throwIfNoMoreTime(this->recorder.allNodeCount());
00166 if (stop_tree)
00167 throw BetaCut();
00168 }
00169 public:
00170 typedef AlphaBeta2Window Window;
00171 size_t nodeCount() const { return node_count; }
00172 static int rootAlpha(Player P, int last_value, Progress16 progress);
00173 static int stableThreshold(Player P, int last_value);
00174
00175 template <Player P>
00176 const MoveLogProb nextMove();
00177 protected:
00178 void updateRootPV(Player P, std::ostream&, int, Move);
00179 void addMultiPV(Player P, int, Move);
00180 bool isStable(Player P, int new_value) const;
00181 void showFailLow(int result, Move m) const;
00182 private:
00183 void showPV(std::ostream&, int, Move, char stable) const;
00184 public:
00185 template <Player P> struct NextMove;
00186 friend class NextMove<BLACK>;
00187 friend class NextMove<WHITE>;
00188 template <Player P> class NextQMove;
00189 friend class NextQMove<BLACK>;
00190 friend class NextQMove<WHITE>;
00191 protected:
00200 template <Player P>
00201 int alphaBetaSearch(const MoveLogProb& move, Window window,
00202 bool in_pv);
00203 template <Player P>
00204 int alphaBetaSearchAfterMove(const MoveLogProb& move,
00205 Window window, bool in_pv);
00206 template <Player P> int quiesce(Window);
00207 template <Player P> int quiesceStable(Window);
00208 template <Player P> int quiesceExp(Window);
00209
00210 template <Player P>
00211 int searchAllMoves(SimpleHashRecord*, Window w);
00212 template <Player P>
00213 int searchAllMoves(Move m, int limit_consumption,
00214 SimpleHashRecord*, Window w);
00215
00217 template <Player P>
00218 bool tryCheckmate(SimpleHashRecord *record, bool in_pv, Move& checkmate_move);
00220 template <Player P>
00221 bool tryCheckmateAgain(SimpleHashRecord *record, Move& checkmate_move,
00222 int node_count,
00223 int best_value);
00224
00226 template <Player P>
00227 void testThreatmate(SimpleHashRecord *record, bool in_pv);
00228
00230 template <Player P>
00231 void examineMovesRoot(const MoveLogProbVector&, size_t, Window,
00232 MoveLogProb&, int&);
00233
00234 template <Player P> int quiesceRoot(Window, int depth_left, Move& best_move, DualThreatmateState);
00235 template <Player P> int quiesce(Window, int depth_left, DualThreatmateState);
00236 template <Player P>
00237 bool quiesceWithMove(Move, Window&, int, Move&, int&, const DualThreatmateState&);
00238
00239 void updateCheckmateCount();
00240 bool tryPass(SimpleHashRecord *record, Player P) const;
00241 MoveGenerator& makeGenerator();
00242 static MoveGenerator *alloc();
00243 static void dealloc(MoveGenerator *);
00244 #ifdef OSL_SMP
00245 public:
00246 friend class AlphaBeta2Parallel<EvalT>;
00247 struct NodeProperty;
00248 template <Player P> struct SearchJob;
00249 struct SearchJobData;
00250 struct Shared;
00251 friend class Shared;
00252 friend class SearchJob<BLACK>;
00253 friend class SearchJob<WHITE>;
00254 protected:
00255 template <Player P>
00256 void examineMovesRootPar(const MoveLogProbVector&, size_t, Window,
00257 MoveLogProb&, int&);
00258 void examineMovesRootPar(int tree_id);
00259 template <Player P>
00260 void testMoveRoot(int tree_id, const MoveLogProb&);
00261
00262 template <Player P>
00263 bool examineMovesOther(Window& w, MoveLogProb& best_move, int& best_value,
00264 int& tried_moves, int& alpha_update, int& last_alpha_update);
00265 void examineMovesOther(int tree_id);
00266 template <Player P>
00267 bool testMoveOther(int tree_id, const MoveLogProb&, size_t index, bool in_pv);
00268 #endif
00269 };
00270
00274 template <class EvalT>
00275 class AlphaBeta2
00276 : public AlphaBeta2Tree<EvalT>
00277 {
00278 public:
00279 typedef AlphaBeta2Tree<EvalT> base_t;
00280 typedef typename base_t::checkmate_t checkmate_t;
00281 typedef typename base_t::Window Window;
00282 public:
00283 AlphaBeta2(const NumEffectState& s, checkmate_t& checker,
00284 SimpleHashTable *t, CountRecorder&);
00285 ~AlphaBeta2();
00286
00293 template <Player P>
00294 int alphaBetaSearchRoot(Window window, MoveLogProb& best_move,
00295 int limit);
00296 static const Window fullWindow(Player P)
00297 {
00298 return Window(P, base_t::winThreshold(alt(P)), base_t::winThreshold(P));
00299 }
00300 int alphaBetaSearchRoot(Window window, MoveLogProb& best_move, int limit)
00301 {
00302 const Player P = this->state().getTurn();
00303 if (P == BLACK)
00304 return alphaBetaSearchRoot<BLACK>(window, best_move, limit);
00305 else
00306 return alphaBetaSearchRoot<WHITE>(window, best_move, limit);
00307 }
00308 int alphaBetaSearchRoot(MoveLogProb& best_move, int limit);
00309
00313 Move computeBestMoveIteratively(int limit,
00314 const int step=100,
00315 int initialLimit=600,
00316 size_t nodeLimit=1600000,
00317 const TimeAssigned& assign=TimeAssigned(MilliSeconds::Interval(60*1000)),
00318 MoveWithComment *additional_info=0);
00319 bool isReasonableMove(Move move, int pawn_sacrifice=1);
00320 void setRootIgnoreMoves(const MoveVector *rim, bool prediction)
00321 {
00322 assert(!prediction || rim);
00323 this->root_ignore_moves = rim;
00324 this->prediction_for_speculative_search = prediction;
00325 }
00326
00327 static void showNodeDepth(std::ostream&);
00328 static void clearNodeDepth();
00329 void enableMultiPV(unsigned int width) { this->multi_pv = width; }
00330 const AlphaBeta2SharedRoot sharedRootInfo() const { return *(this->shared_root); }
00331 public:
00332 void setRoot(int limit);
00333 void makeMove(Move);
00334 private:
00335 enum PVCheckmateStatus {
00336 PVStable, PVThreatmateNotRecord, PVThreatmate, PVCheckmate,
00337 };
00338 PVCheckmateStatus findCheckmateInPV(int verify_node, CArray<bool,2>& king_in_threat);
00339 };
00340
00341 }
00342 typedef search::AlphaBeta2<eval::ProgressEval> AlphaBeta2ProgressEval;
00343 typedef search::AlphaBeta2<eval::ml::OpenMidEndingEval> AlphaBeta2OpenMidEndingEval;
00344 }
00345
00346 #endif
00347
00348
00349
00350