dfpnstat.cc
Go to the documentation of this file.
00001 #include "osl/checkmate/dfpn.h"
00002 #include "osl/checkmate/dfpnParallel.h"
00003 #include "osl/record/csaString.h"
00004 #include "osl/record/csaRecord.h"
00005 #include "osl/record/csaIOError.h"
00006 #include "osl/state/numEffectState.h"
00007 #include "osl/misc/perfmon.h"
00008 #include "osl/misc/milliSeconds.h"
00009 
00010 #include "osl/move_generator/legalMoves.h"
00011 #include "osl/checkmate/dfpnRecord.h"
00012 #include "osl/hash/hashRandomPair.h"
00013 #include "osl/oslConfig.h"
00014 
00015 #include <boost/scoped_ptr.hpp>
00016 #include <boost/foreach.hpp>
00017 #include <string>
00018 #include <iostream>
00019 #include <iomanip>
00020 #include <fstream>
00021 #include <cstdlib>
00022 #include <unistd.h>
00023 
00024 #include <bitset>
00025 
00026 using namespace osl;
00027 using namespace osl::checkmate;
00028 using namespace osl::misc;
00029 
00030 unsigned int dovetailing_seed = 0;
00031 unsigned int dovetailing_prob = 0;
00032 
00033 bool verbose=false;
00034 unsigned long long total_cycles=0;
00035 bool show_escape_filename = false;
00036 bool force_attack = false;
00037 int num_checkmate=0, num_nocheckmate=0, num_escape=0, num_unkown=0;
00038 double total_nodes=0, total_tables=0;
00039 int limit = 100000;
00040 bool blocking_verify = true;
00041 size_t table_growth_limit = 8000000;
00042 bool debug = false;
00043 int forward_moves = 0;
00044 
00045 template<class DfpnSearch>
00046 void search(DfpnSearch&, const char *filename);
00047 void usage(const char *program_name)
00048 {
00049   std::cerr << "usage: " << program_name << " [-d] [-v] [-f] [-l limit] [-N] csa-files\n";
00050 }
00051 int main(int argc, char **argv)
00052 {
00053   const char *program_name = argv[0];
00054   bool error_flag = false;
00055   int parallel = 0;
00056   extern char *optarg;
00057   extern int optind;
00058 
00059   char c;
00060   while ((c = getopt(argc, argv, "dfl:N:F:s:p:t:vh")) != EOF)
00061   {
00062     switch(c)
00063     {
00064     case 's':   dovetailing_seed = static_cast<unsigned int>(atoi(optarg));
00065       break;
00066     case 'p':   dovetailing_prob = static_cast<unsigned int>(atoi(optarg));
00067       break;
00068     case 'd':   debug = true;
00069       break;
00070     case 'f':   force_attack = true;
00071       break;
00072     case 'F':   forward_moves = atoi(optarg);
00073       break;
00074     case 'l':   limit = atoi(optarg);
00075       break;
00076     case 'N':   parallel = atoi(optarg);
00077       break;
00078     case 't':   table_growth_limit = atoi(optarg);
00079       break;
00080 #if 0
00081     case 'V':   blocking_verify = false;
00082       break;
00083 #endif
00084     case 'v':   verbose = true;
00085       break;
00086     default:    error_flag = true;
00087     }
00088   }
00089   argc -= optind;
00090   argv += optind;
00091 
00092   if (error_flag || (argc < 1)) {
00093     usage(program_name);
00094     return 1;
00095   }
00096   OslConfig::setDfpnMaxDepth(1600);     // sufficient for microcosmos
00097   if (dovetailing_prob > 0)
00098     HashRandomPair::setUp(dovetailing_seed, dovetailing_prob);
00099   try
00100   {
00101     for (int i=0; i<argc; ++i)
00102     {
00103       if (parallel) 
00104       {
00105 #ifdef OSL_DFPN_SMP
00106         DfpnParallel dfpn(parallel);
00107         search(dfpn, argv[i]);
00108 #else
00109         std::cerr << "to use parallel dfpn, try compile with -DOSL_SMP or -DOSL_DFPN_SMP\n";
00110         return 1;
00111 #endif
00112       }
00113       else 
00114       {
00115         Dfpn dfpn;
00116         search(dfpn, argv[i]);
00117       }
00118       total_cycles = 0;
00119     }
00120     std::cerr << "check " << num_checkmate << " nocheckmate " << num_nocheckmate << " escape " << num_escape
00121               << " unknown " << num_unkown << "\n";
00122     std::cerr << "total nodes " << total_nodes 
00123               << " tables " << total_tables << "\n";
00124   }
00125   catch (std::exception& e)
00126   {
00127     std::cerr << e.what() << "\n";
00128     return 1;
00129   }
00130 }
00131 
00132 double real_seconds = 0.0;
00133 
00134 template <class DfpnSearch>
00135 void analyzeCheckmate(DfpnSearch& searcher, const NumEffectState& state, Move checkmate_move)
00136 {
00137   NumEffectState new_state = state;
00138   std::cerr << state << " " << checkmate_move << "\n";
00139   new_state.makeMove(checkmate_move);
00140   HashKey key(new_state);
00141   const DfpnTable& table = searcher.currentTable();
00142   DfpnRecordBase record = table.probe(key, PieceStand(WHITE, new_state));
00143   std::cerr << record.proof_disproof << " " << std::bitset<64>(record.solved) << "\n";
00144 
00145   MoveVector moves;
00146   LegalMoves::generate(new_state, moves);
00147   for (size_t i=0; i<moves.size(); ++i) {
00148     NumEffectState tmp = new_state;
00149     tmp.makeMove(moves[i]);
00150     DfpnRecordBase record = table.probe(key.newHashWithMove(moves[i]), PieceStand(WHITE, tmp));
00151     std::cerr << moves[i] << " " << record.proof_disproof << " " << record.best_move << "\n";
00152   }
00153 
00154   {
00155     Dfpn::DfpnMoveVector moves;
00156     if (state.turn() == BLACK)
00157       Dfpn::generateEscape<BLACK>(new_state, false, Square(), moves);
00158     else
00159       Dfpn::generateEscape<WHITE>(new_state, false, Square(), moves);
00160     std::cerr << "Escape " << moves.size()<< "\n";
00161     moves.clear();
00162     if (state.turn() == BLACK)
00163       Dfpn::generateEscape<BLACK>(new_state, true, Square(), moves);
00164     else
00165       Dfpn::generateEscape<BLACK>(new_state, true, Square(), moves);
00166     std::cerr << "Escape full " << moves.size() << "\n";
00167   }
00168 }
00169 
00170 template <class DfpnSearch>
00171 void testWinOrLose(const char *filename,
00172                    DfpnSearch& searcher,
00173                    const SimpleState& sstate, int limit,
00174                    ProofDisproof& result, Move& best_move,
00175                    const vector<Move>& moves)
00176 {
00177   const Player P = sstate.turn();
00178   NumEffectState state(sstate);
00179   const PathEncoding path(state.turn());
00180   const Square my_king = state.kingSquare(P);
00181   if ((! force_attack) 
00182       && ! my_king.isPieceStand() && state.inCheck(P))
00183   {
00184     // 相手から王手がかかっている
00185     MilliSeconds timer = MilliSeconds::now();
00186     misc::PerfMon clock;
00187     result = searcher.hasEscapeMove(state, HashKey(state), path, limit, Move::PASS(alt(P)));
00188     total_cycles += clock.stop();
00189     real_seconds = timer.elapsedSeconds();
00190 
00191     if (verbose)
00192       std::cerr << result << "\n";
00193     if (result.isCheckmateSuccess()) {
00194       ++num_checkmate;
00195     }
00196     else {
00197       if (result.isCheckmateFail())
00198         ++num_escape;
00199       else {
00200         assert(! result.isFinal());
00201         ++num_unkown;
00202       }
00203     }
00204     return;
00205   }
00206 
00207   Move checkmate_move;
00208   vector<Move> pv;
00209   MilliSeconds timer = MilliSeconds::now();
00210   PerfMon clock;
00211   result = searcher.
00212     hasCheckmateMove(state, HashKey(state), path, limit, checkmate_move, Move(), &pv);
00213   total_cycles += clock.stop();
00214   real_seconds = timer.elapsedSeconds();
00215   if (verbose)
00216     std::cerr << result << "\n";
00217 
00218   if (result.isCheckmateSuccess()) {
00219     ++num_checkmate;
00220     best_move = checkmate_move;
00221     if (verbose) {
00222       std::cerr << checkmate_move << "\n";
00223       for (size_t i=0; i<pv.size(); ++i) {
00224         std::cerr << std::setw(4) << std::setfill(' ') << i+1
00225                   << ' ' << record::csa::show(pv[i]) << " ";
00226         if (i % 6 == 5) 
00227           std::cerr << "\n";
00228       }
00229       if (pv.size() % 6 != 0)
00230           std::cerr << "\n";
00231     }
00232     if (debug) {
00233       // analyzeCheckmate(searcher, state, checkmate_move);
00234       if (! moves.empty())
00235         searcher.analyze(path, state, moves);
00236     }
00237   }
00238   else {
00239     if (result.isFinal())
00240       ++num_nocheckmate;
00241     else
00242       ++num_unkown;
00243     if (debug)
00244       searcher.analyze(path, state, moves);
00245   }
00246 }
00247 
00248 template <class DfpnSearch>
00249 void search(DfpnSearch& searcher, const char *filename)
00250 {
00251   NumEffectState state;
00252   vector<Move> moves;
00253   try {
00254     CsaFile file(filename);
00255     state = file.getInitialState();
00256     moves = file.getRecord().getMoves();
00257     int forward_here = std::min(forward_moves, (int)moves.size());
00258     for (int i=0; i<forward_here; ++i)
00259       state.makeMove(moves[i]);
00260     moves.erase(moves.begin(), moves.begin()+forward_here);
00261   }
00262   catch (CsaIOError&) {
00263     std::cerr << "\nskipping " << filename << "\n";
00264     return;
00265   }
00266   if (verbose)
00267     std::cerr << "\nsolving " << filename << "\n";
00268   
00269   // searcher.setBlockingVerify(blocking_verify);
00270   const bool attack = force_attack
00271     || state.kingSquare(state.turn()).isPieceStand()
00272     || ! state.inCheck(state.turn());
00273   DfpnTable table(attack ? state.turn() : alt(state.turn()));
00274   table.setGrowthLimit(table_growth_limit);
00275   searcher.setTable(&table);
00276   ProofDisproof result;
00277   Move best_move;
00278   testWinOrLose(filename, searcher, state, limit, result, best_move, moves);
00279   const size_t table_used = searcher.currentTable().size();
00280   total_nodes += searcher.nodeCount();
00281   total_tables += table_used;
00282 
00283   if (verbose) {
00284     PerfMon::message(total_cycles, "total ", 
00285                      searcher.nodeCount());
00286     PerfMon::message(total_cycles, "unique", table_used);
00287     std::cerr << "real " << real_seconds << " sec. nps " << searcher.nodeCount()/real_seconds << "\n";
00288   }
00289   std::cout << filename << "\t" << searcher.nodeCount() 
00290             << "\t" << table_used << "\t" << real_seconds
00291             << " " << result;
00292   if (best_move.isNormal())
00293     std::cout << " " << record::csa::show(best_move);
00294   std::cout << "\n" << std::flush;
00295 }
00296 
00297 
00298 /* ------------------------------------------------------------------------- */
00299 // ;;; Local Variables:
00300 // ;;; mode:c++
00301 // ;;; c-basic-offset:2
00302 // ;;; coding:utf-8
00303 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines