All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
dfpnstat.cc
Go to the documentation of this file.
1 #include "osl/checkmate/dfpn.h"
3 #include "osl/record/csaString.h"
4 #include "osl/record/csaRecord.h"
7 #include "osl/misc/perfmon.h"
9 
13 #include "osl/oslConfig.h"
14 
15 #include <boost/scoped_ptr.hpp>
16 #include <boost/foreach.hpp>
17 #include <string>
18 #include <iostream>
19 #include <iomanip>
20 #include <fstream>
21 #include <cstdlib>
22 #include <unistd.h>
23 
24 #include <bitset>
25 
26 using namespace osl;
27 using namespace osl::checkmate;
28 using namespace osl::misc;
29 
30 unsigned int dovetailing_seed = 0;
31 unsigned int dovetailing_prob = 0;
32 
33 bool verbose=false;
34 unsigned long long total_cycles=0;
35 bool show_escape_filename = false;
36 bool force_attack = false;
39 int limit = 100000;
40 bool blocking_verify = true;
41 size_t table_growth_limit = 8000000;
42 bool debug = false;
43 int forward_moves = 0;
44 
45 template<class DfpnSearch>
46 void search(DfpnSearch&, const char *filename);
47 void usage(const char *program_name)
48 {
49  std::cerr << "usage: " << program_name << " [-d] [-v] [-f] [-l limit] [-N] csa-files\n";
50 }
51 int main(int argc, char **argv)
52 {
53  const char *program_name = argv[0];
54  bool error_flag = false;
55  int parallel = 0;
56  extern char *optarg;
57  extern int optind;
58 
59  char c;
60  while ((c = getopt(argc, argv, "dfl:N:F:s:p:t:vh")) != EOF)
61  {
62  switch(c)
63  {
64  case 's': dovetailing_seed = static_cast<unsigned int>(atoi(optarg));
65  break;
66  case 'p': dovetailing_prob = static_cast<unsigned int>(atoi(optarg));
67  break;
68  case 'd': debug = true;
69  break;
70  case 'f': force_attack = true;
71  break;
72  case 'F': forward_moves = atoi(optarg);
73  break;
74  case 'l': limit = atoi(optarg);
75  break;
76  case 'N': parallel = atoi(optarg);
77  break;
78  case 't': table_growth_limit = atoi(optarg);
79  break;
80 #if 0
81  case 'V': blocking_verify = false;
82  break;
83 #endif
84  case 'v': verbose = true;
85  break;
86  default: error_flag = true;
87  }
88  }
89  argc -= optind;
90  argv += optind;
91 
92  if (error_flag || (argc < 1)) {
93  usage(program_name);
94  return 1;
95  }
96  OslConfig::setDfpnMaxDepth(1600); // sufficient for microcosmos
97  if (dovetailing_prob > 0)
98  HashRandomPair::setUp(dovetailing_seed, dovetailing_prob);
99  try
100  {
101  for (int i=0; i<argc; ++i)
102  {
103  if (parallel)
104  {
105 #ifdef OSL_DFPN_SMP
106  DfpnParallel dfpn(parallel);
107  search(dfpn, argv[i]);
108 #else
109  std::cerr << "to use parallel dfpn, try compile with -DOSL_SMP or -DOSL_DFPN_SMP\n";
110  return 1;
111 #endif
112  }
113  else
114  {
115  Dfpn dfpn;
116  search(dfpn, argv[i]);
117  }
118  total_cycles = 0;
119  }
120  std::cerr << "check " << num_checkmate << " nocheckmate " << num_nocheckmate << " escape " << num_escape
121  << " unknown " << num_unkown << "\n";
122  std::cerr << "total nodes " << total_nodes
123  << " tables " << total_tables << "\n";
124  }
125  catch (std::exception& e)
126  {
127  std::cerr << e.what() << "\n";
128  return 1;
129  }
130 }
131 
132 double real_seconds = 0.0;
133 
134 template <class DfpnSearch>
135 void analyzeCheckmate(DfpnSearch& searcher, const NumEffectState& state, Move checkmate_move)
136 {
137  NumEffectState new_state = state;
138  std::cerr << state << " " << checkmate_move << "\n";
139  new_state.makeMove(checkmate_move);
140  HashKey key(new_state);
141  const DfpnTable& table = searcher.currentTable();
142  DfpnRecordBase record = table.probe(key, PieceStand(WHITE, new_state));
143  std::cerr << record.proof_disproof << " " << std::bitset<64>(record.solved) << "\n";
144 
145  MoveVector moves;
146  LegalMoves::generate(new_state, moves);
147  for (size_t i=0; i<moves.size(); ++i) {
148  NumEffectState tmp = new_state;
149  tmp.makeMove(moves[i]);
150  DfpnRecordBase record = table.probe(key.newHashWithMove(moves[i]), PieceStand(WHITE, tmp));
151  std::cerr << moves[i] << " " << record.proof_disproof << " " << record.best_move << "\n";
152  }
153 
154  {
156  if (state.turn() == BLACK)
157  Dfpn::generateEscape<BLACK>(new_state, false, Square(), moves);
158  else
159  Dfpn::generateEscape<WHITE>(new_state, false, Square(), moves);
160  std::cerr << "Escape " << moves.size()<< "\n";
161  moves.clear();
162  if (state.turn() == BLACK)
163  Dfpn::generateEscape<BLACK>(new_state, true, Square(), moves);
164  else
165  Dfpn::generateEscape<BLACK>(new_state, true, Square(), moves);
166  std::cerr << "Escape full " << moves.size() << "\n";
167  }
168 }
169 
170 template <class DfpnSearch>
171 void testWinOrLose(const char *filename,
172  DfpnSearch& searcher,
173  const SimpleState& sstate, int limit,
174  ProofDisproof& result, Move& best_move,
175  const vector<Move>& moves)
176 {
177  const Player P = sstate.turn();
178  NumEffectState state(sstate);
179  const PathEncoding path(state.turn());
180  const Square my_king = state.kingSquare(P);
181  if ((! force_attack)
182  && ! my_king.isPieceStand() && state.inCheck(P))
183  {
184  // 相手から王手がかかっている
185  MilliSeconds timer = MilliSeconds::now();
186  misc::PerfMon clock;
187  result = searcher.hasEscapeMove(state, HashKey(state), path, limit, Move::PASS(alt(P)));
188  total_cycles += clock.stop();
189  real_seconds = timer.elapsedSeconds();
190 
191  if (verbose)
192  std::cerr << result << "\n";
193  if (result.isCheckmateSuccess()) {
194  ++num_checkmate;
195  }
196  else {
197  if (result.isCheckmateFail())
198  ++num_escape;
199  else {
200  assert(! result.isFinal());
201  ++num_unkown;
202  }
203  }
204  return;
205  }
206 
207  Move checkmate_move;
208  vector<Move> pv;
209  MilliSeconds timer = MilliSeconds::now();
210  PerfMon clock;
211  result = searcher.
212  hasCheckmateMove(state, HashKey(state), path, limit, checkmate_move, Move(), &pv);
213  total_cycles += clock.stop();
214  real_seconds = timer.elapsedSeconds();
215  if (verbose)
216  std::cerr << result << "\n";
217 
218  if (result.isCheckmateSuccess()) {
219  ++num_checkmate;
220  best_move = checkmate_move;
221  if (verbose) {
222  std::cerr << checkmate_move << "\n";
223  for (size_t i=0; i<pv.size(); ++i) {
224  std::cerr << std::setw(4) << std::setfill(' ') << i+1
225  << ' ' << record::csa::show(pv[i]) << " ";
226  if (i % 6 == 5)
227  std::cerr << "\n";
228  }
229  if (pv.size() % 6 != 0)
230  std::cerr << "\n";
231  }
232  if (debug) {
233  // analyzeCheckmate(searcher, state, checkmate_move);
234  if (! moves.empty())
235  searcher.analyze(path, state, moves);
236  }
237  }
238  else {
239  if (result.isFinal())
240  ++num_nocheckmate;
241  else
242  ++num_unkown;
243  if (debug)
244  searcher.analyze(path, state, moves);
245  }
246 }
247 
248 template <class DfpnSearch>
249 void search(DfpnSearch& searcher, const char *filename)
250 {
251  NumEffectState state;
252  vector<Move> moves;
253  try {
254  CsaFile file(filename);
255  state = file.getInitialState();
256  moves = file.getRecord().getMoves();
257  int forward_here = std::min(forward_moves, (int)moves.size());
258  for (int i=0; i<forward_here; ++i)
259  state.makeMove(moves[i]);
260  moves.erase(moves.begin(), moves.begin()+forward_here);
261  }
262  catch (CsaIOError&) {
263  std::cerr << "\nskipping " << filename << "\n";
264  return;
265  }
266  if (verbose)
267  std::cerr << "\nsolving " << filename << "\n";
268 
269  // searcher.setBlockingVerify(blocking_verify);
270  const bool attack = force_attack
271  || state.kingSquare(state.turn()).isPieceStand()
272  || ! state.inCheck(state.turn());
273  DfpnTable table(attack ? state.turn() : alt(state.turn()));
275  searcher.setTable(&table);
277  Move best_move;
278  testWinOrLose(filename, searcher, state, limit, result, best_move, moves);
279  const size_t table_used = searcher.currentTable().size();
280  total_nodes += searcher.nodeCount();
281  total_tables += table_used;
282 
283  if (verbose) {
284  PerfMon::message(total_cycles, "total ",
285  searcher.nodeCount());
286  PerfMon::message(total_cycles, "unique", table_used);
287  std::cerr << "real " << real_seconds << " sec. nps " << searcher.nodeCount()/real_seconds << "\n";
288  }
289  std::cout << filename << "\t" << searcher.nodeCount()
290  << "\t" << table_used << "\t" << real_seconds
291  << " " << result;
292  if (best_move.isNormal())
293  std::cout << " " << record::csa::show(best_move);
294  std::cout << "\n" << std::flush;
295 }
296 
297 
298 /* ------------------------------------------------------------------------- */
299 // ;;; Local Variables:
300 // ;;; mode:c++
301 // ;;; c-basic-offset:2
302 // ;;; coding:utf-8
303 // ;;; End: