searchRecorder.cc
Go to the documentation of this file.
00001 /* searchRecorder.cc
00002  */
00003 #include "osl/search/searchRecorder.h"
00004 #include "osl/search/realizationProbability.h"
00005 #include "osl/eval/evalTraits.h"
00006 #include "osl/state/simpleState.h"
00007 #include "osl/moveLogProb.h"
00008 #include "osl/record/csa.h"
00009 #include <fstream>
00010 #include <iostream>
00011 #include <cassert>
00012 #ifndef _MSC_VER
00013 #  include <unistd.h>
00014 #endif
00015 
00016 #ifndef MINIMAL
00017 const char *checkmateFileName = "currentCheck.csa";
00018 #endif
00019 
00021 #define SELECT_CHECKMATE_LOG
00022 
00024 // #define CHECKMATE_SEARCHER_DEBUG
00025 
00026 /* ------------------------------------------------------------------------- */
00027 
00028 osl::search::CountRecorder::CountRecorder()
00029   : node_count(0), quiescence_count(0), checkmate_count(0)
00030 {
00031 }
00032 
00033 osl::search::CountRecorder::~CountRecorder()
00034 {
00035 }
00036 
00037 void osl::search::
00038 CountRecorder::recordInvalidMoveInTable(const SimpleState& state,
00039                                         const MoveLogProb& move, int limit) const
00040 {
00041   std::cerr << "?? invalid move in table " << move.move() << " " << move.logProb()
00042             << " limit " << limit << "\n"
00043             << state;
00044 }
00045 
00046 void osl::search::CountRecorder::resetNodeCount()
00047 {
00048   node_count = quiescence_count = checkmate_count = 0;
00049 }
00050 
00051 void osl::search::
00052 CountRecorder::finishSearch(Move /*best_move*/, double sec, bool verbose) const
00053 {
00054   if (! verbose)
00055     return;
00056   reportCount(std::cerr, sec);
00057 }
00058 
00059 void osl::search::
00060 CountRecorder::reportCount(std::ostream& os) const
00061 {
00062   os << "#normal : " << nodeCount() << ", ";
00063   os << "#quiescence: " << quiescenceCount() << ", ";
00064   os << "#checkmate : " << checkmateCount() << "\n";
00065 }
00066 
00067 void osl::search::
00068 CountRecorder::reportCount(std::ostream& os, double seconds) const
00069 {
00070   const double total = nodeCount() + quiescenceCount() + checkmateCount();
00071   os << "#total : " << total
00072      << " in " << seconds << " sec., " << total/seconds << " nodes/sec."
00073      << " (quiesce " << 100.0*quiescenceCount()/total << "%,"
00074      << " checkmate " << 100.0*checkmateCount()/total << "%)\n";
00075 }
00076 
00077 /* ------------------------------------------------------------------------- */
00078 
00079 #ifndef MINIMAL
00080 static bool showAllValues = false;
00081 struct osl::search::SearchRecorder::Recorder
00082 {
00083   std::ofstream os;
00085   int current_depth;
00087   int initial_limit;
00088   int log_margin;
00089   
00090   Recorder(const char *filename) 
00091     : os(filename),
00092       current_depth(0), initial_limit(0),
00093       log_margin(RealizationProbability::TableMove)
00094   {
00095   }
00096   std::ostream& stream()
00097   {
00098     assert(os);
00099 #if 0
00100     os << current_depth << ':';
00101 #endif
00102     for (int i=0; i<=current_depth; ++i)
00103       os << '*';
00104     os << ' ';
00105     return os;
00106   }
00108   bool notSoDeep(int limit) const
00109   {
00110     return 
00111 #ifdef SELECT_CHECKMATE_LOG
00112       (limit <= initial_limit) // SearchTable::CheckmateSpecialDepth が来ることがある
00113       && 
00114 #endif
00115       (initial_limit - limit) <= log_margin;
00116   }
00117   void flush()
00118   {
00119 #if 1
00120     os << std::flush;
00121 #endif    
00122   }
00123 };
00124 
00125 osl::search::
00126 SearchRecorder::SearchRecorder(const char *filename)
00127   : recorder(new Recorder(filename))
00128 {
00129 }
00130 
00131 osl::search::
00132 SearchRecorder::~SearchRecorder()
00133 {
00134 }
00135 
00136 void osl::search::
00137 SearchRecorder::setLogMargin(int margin)
00138 {
00139   recorder->log_margin = margin;
00140 }
00141 
00142 void osl::search::
00143 SearchRecorder::tryMove(const MoveLogProb& m, int last_f, int limit) const
00144 {
00145   ++recorder->current_depth;
00146   if (recorder->notSoDeep(limit-100)) // 末端ではtryMove を無視
00147   {
00148     std::ostream& os = stream();
00149     os << "==> ";
00150     csaShow(os, m.move());
00151     os << " " << m.logProb() << "\t" 
00152        << "last_f: " << last_f << " limit: " << limit << "\n";
00153     recorder->flush();
00154   }
00155 }
00156 
00157 void osl::search::
00158 SearchRecorder::retryMove(const MoveLogProb& m, int last_f, int limit,
00159                         int retryCount) const
00160 {
00161   ++recorder->current_depth;
00162   if (recorder->notSoDeep(limit)) // 再探索は必ず記録しないとややこしい
00163   {
00164     std::ostream& os = stream();
00165     os << "ex" << retryCount << "> ";
00166     csaShow(os, m.move());
00167     os << " " << m.logProb() << "\t" 
00168        << "last_f: " << last_f << " limit: " << limit << "\n";
00169     recorder->flush();
00170   }
00171 }
00172 
00173 void osl::search::
00174 SearchRecorder::recordValue(const MoveLogProb& m, int val, bool betterMove, int limit) const
00175 {
00176   if (recorder->notSoDeep(limit)
00177       && (showAllValues || betterMove))
00178   {
00179     std::ostream& os = stream();
00180     os << "<== " << val << "\t";
00181     csaShow(os, m.move());
00182     os << "\n";
00183     recorder->flush();    
00184   }
00185   CountRecorder::recordValue(m,val,betterMove,limit);
00186   --recorder->current_depth;
00187 }
00188 
00189 static const char *lowerChar(osl::Player p) 
00190 {
00191   return (p == osl::BLACK) ? "B (lb)>" : "W (lb)<";
00192 }
00193 static const char *higherChar(osl::Player p) 
00194 {
00195   return (p == osl::BLACK) ? "B (ub)<" : "W (ub)>";
00196 }
00197 
00198 void osl::search::
00199 SearchRecorder::tableHitLowerBound(Player p, int val, int last_f, int limit) const
00200 {
00201   if (recorder->notSoDeep(limit))
00202   {
00203     stream() << "==| table answered " << lowerChar(p) << val
00204              << " for " << p << " last_f " << last_f << "\n";
00205     recorder->flush();
00206   }
00207 }
00208 
00209 void osl::search::
00210 SearchRecorder::tableHitUpperBound(Player p, int val, int last_f, int limit) const
00211 {
00212   if (recorder->notSoDeep(limit))
00213   {
00214     stream() << "==| table answered " << higherChar(p) << val
00215              << " for " << p << " last_f " << last_f << "\n";
00216     recorder->flush();
00217   }  
00218 }
00219 
00220 void osl::search::
00221 SearchRecorder::tableStoreLowerBound(Player p, const MoveLogProb& best_move, int val, int limit) const
00222 {
00223   const Move move = best_move.move();
00224   assert(move.isInvalid() || move.isValidOrPass()); 
00225   // TODO: lower bound は invalid はないはず?
00226   if (recorder->notSoDeep(limit-100)) // 末端は無視
00227   {
00228     std::ostream& os = stream();
00229     os << "|== table store " << lowerChar(p) << val << " ";
00230     csaShow(os, move);
00231     os << " limit " << limit << "\n";
00232     recorder->flush();
00233   }
00234 }
00235 
00236 void osl::search::
00237 SearchRecorder::tableStoreUpperBound(Player p, const MoveLogProb& best_move, int val, int limit) const
00238 {
00239   const Move move = best_move.move();
00240   assert(move.isInvalid() || move.isValidOrPass());
00241   if (recorder->notSoDeep(limit-100)) // 末端は無視
00242   {
00243     std::ostream& os = stream();
00244     os << "|== table store " << higherChar(p) << val << " ";
00245     csaShow(os, move);
00246     os << " limit " << limit << "\n";
00247     recorder->flush();
00248   }
00249 }
00250 
00251 void osl::search::
00252 SearchRecorder::recordTopLevelLowFail(const MoveLogProb& /* best */, int last_f) const
00253 {
00254   stream() << "low fail,  last_f=" << last_f << "\n";
00255   reportCount(stream());
00256 }
00257 void osl::search::
00258 SearchRecorder::recordTopLevelHighFail(const MoveLogProb& best_move, int last_f) const
00259 {
00260   stream() << "high fail, last_f=" << last_f << " " << best_move << "\n";
00261   reportCount(stream());
00262 }
00263 
00264 void osl::search::
00265 SearchRecorder::startSearch(int limit) const
00266 {
00267   stream() << "\nnew search: limit " << limit 
00268            << ", log " << recorder->log_margin << "\n";
00269   recorder->initial_limit = limit;
00270   CountRecorder::startSearch(limit);
00271 }
00272 void osl::search::
00273 SearchRecorder::finishSearch(Move best_move, double sec, bool verbose) const
00274 {
00275   stream() << "search finished\t" << best_move << "\n";
00276   CountRecorder::finishSearch(best_move, sec, verbose);
00277 }
00278 
00279 void osl::search::
00280 SearchRecorder::gotoCheckmateSearch(const SimpleState& 
00281 #ifdef CHECKMATE_SEARCHER_DEBUG
00282                                     state
00283 #endif
00284                                     , int 
00285 #ifdef CHECKMATE_SEARCHER_DEBUG
00286                                     nodeLimit
00287 #endif
00288   ) const
00289 {
00290 #ifdef CHECKMATE_SEARCHER_DEBUG
00291   std::ofstream os(checkmateFileName, std::ios::app);
00292   os << state;
00293   os << nodeLimit << "\n";
00294 #endif
00295 }
00296 
00297 void osl::search::
00298 SearchRecorder::backFromCheckmateSearch() const
00299 {
00300 #ifdef CHECKMATE_SEARCHER_DEBUG
00301   std::ofstream os(checkmateFileName, std::ios::app);
00302   os << "done\n";
00303 #endif
00304 }
00305 
00306 std::ostream& osl::search::
00307 SearchRecorder::stream() const
00308 {
00309   return recorder->stream();
00310 }
00311 #endif
00312 
00313 /* ------------------------------------------------------------------------- */
00314 // ;;; Local Variables:
00315 // ;;; mode:c++
00316 // ;;; c-basic-offset:2
00317 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines