All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
move_probability/featureSet.cc
Go to the documentation of this file.
1 /* featureSet.cc
2  */
7 #include "osl/record/csa.h"
8 #include "osl/misc/binaryIO.h"
9 #include "osl/oslConfig.h"
10 #include <boost/accumulators/accumulators.hpp>
11 #include <boost/accumulators/statistics/stats.hpp>
12 #include <boost/accumulators/statistics/mean.hpp>
13 #include <boost/accumulators/statistics/min.hpp>
14 #include <boost/accumulators/statistics/max.hpp>
15 #include <boost/foreach.hpp>
16 #include <boost/format.hpp>
17 #include <boost/thread/mutex.hpp>
18 #include <fstream>
19 #include <iomanip>
20 #include <iostream>
21 #include <cstdio>
22 
25 {
26 }
27 
30 {
31 }
32 
35 {
36  features.push_back(f);
37  if (light)
38  light_features.push_back(features.size()-1);
39 }
40 
43 {
44  offsets.resize(features.size()+1);
45  offsets[0] = 0;
46  for (size_t i=0; i<features.size(); ++i)
47  offsets[i+1] = offsets[i] + features[i].dimension();
48 }
49 
51 matchNoExp(const StateInfo& state, Move move, const double * weights) const
52 {
53  MoveInfo info(state, move);
54  assert(offsets.size() == features.size()+1);
55  double sum = 0.0;
56  for (size_t i=0; i<features.size(); ++i) {
57  sum += features[i].match(state, info, offsets[i], weights);
58  }
59  return sum;
60 }
61 
63 matchExp(const StateInfo& state, Move move, const double * weights) const
64 {
65  return exp(matchNoExp(state, move, weights));
66 }
67 
69 matchLight(const StateInfo& state, Move move, const double * weights) const
70 {
71  MoveInfo info(state, move);
72  assert(offsets.size() == features.size()+1);
73  double sum = 0.0;
74  BOOST_FOREACH(size_t i, light_features) {
75  sum += features[i].match(state, info, offsets[i], weights);
76  }
77  return sum;
78 }
79 
80 
82 analyze(const StateInfo& state, Move move, const double * weights) const
83 {
84  MoveInfo info(state, move);
85  std::cerr << record::csa::show(move) << "\n";
86  vector<std::pair<double, std::string> > out;
87  for (size_t i=0; i<features.size(); ++i) {
88  double s = features[i].match(state, info, offsets[i], weights);
89  if (s)
90  out.push_back(make_pair(s, features[i].name()));
91  }
92  std::sort(out.begin(), out.end());
93  std::reverse(out.begin(), out.end());
94  for (size_t i=0; i<out.size(); ++i) {
95  std::cerr << boost::format("%16s %6.2f ") % out[i].second % out[i].first;
96  if (i % 3 == 2)
97  std::cerr << "\n";
98  }
99  if (out.size() % 3 != 0)
100  std::cerr << "\n";
101 }
102 
105  const double * weights) const
106 {
107  assert(! state.dirty);
108  MoveVector moves;
109  LegalMoves::generate(*state.state, moves);
110  double sum = 0.0;
111  FixedCapacityVector<Move,128> unpromote_moves;
112  BOOST_FOREACH(Move move, moves) {
113  double score = matchExp(state, move, weights);
114  out.push_back(WeightedMove(score, move));
115  sum += score;
116  }
117  return sum;
118 }
119 
122  double sum, MoveLogProbVector& out)
123 {
124  static const double scale = 100.0 / log(0.5);
125  BOOST_FOREACH(WeightedMove move, rating) {
126  double p = move.first/sum;
127  if (std::isnan(p) || p <= 1.0/(1<<12))
128  p = 1.0/(1<<12);
129  const int logp = std::max(50, static_cast<int>(log(p)*scale));
130  out.push_back(MoveLogProb(move.second, logp));
131  }
132  out.sortByProbability();
133 }
134 
136 generateLogProb(const StateInfo& state, MoveLogProbVector& out,
137  const double * weights) const
138 {
140  double sum = generateRating(state, moves, weights);
141  ratingToLogProb(moves, sum, out);
142 }
143 
145 load(const char *base_filename, double * weights) const
146 {
147  std::string filename = std::string(base_filename) + ".txt";
148  std::fill(weights, weights+dimension(), 0.0);
149  std::ifstream is(filename.c_str());
150  for (int i=0; i<dimension(); ++i) {
151  is >> weights[i];
152  if (! is) {
153  std::cerr << "load failed at " << i << " in " << dimension()
154  << " file " << filename << "\n";
155  break;
156  }
157  }
158  return is;
159 }
160 
162 load_binary(const char *base_filename, double * weights) const
163 {
164  std::string filename = std::string(base_filename) + ".bin";
165  std::fill(weights, weights+dimension(), 0.0);
166  std::ifstream is(filename.c_str(), std::ios_base::binary);
168  for (int i=0; i<dimension(); ++i) {
169  if (! reader.hasNext()) {
170  std::cerr << "load failed at " << i << " in " << dimension()
171  << " file " << filename << "\n";
172  return false;
173  }
174  double value = reader.read();
175  weights[i] = value;
176  }
177  return true;
178 }
179 
181 showSummary(const double * weights) const
182 {
183  for (size_t i=0; i<features.size(); ++i) {
184  const Feature& f = features[i];
185 #if (__GNUC_MINOR__ < 5)
186  using namespace boost::accumulators;
187  accumulator_set<double, stats<tag::mean, tag::min, tag::max> > acc;
188 #endif
189  int zero = 0;
190  for (int j=offsets[i]; j<offsets[i+1]; ++j)
191  if (weights[j]) {
192 #if (__GNUC_MINOR__ < 5)
193  acc(weights[j]);
194 #endif
195  }
196  else
197  ++zero;
198  std::cerr << std::setw(16) << f.name()
199  << " dim " << std::setw(5) << f.dimension() - zero
200  << "/" << std::setw(5) << f.dimension()
201 #if (__GNUC_MINOR__ < 5)
202  << " min " << std::setw(6) << min(acc)
203  << " max " << std::setw(6) << max(acc)
204  << " mean " << std::setw(6) << mean(acc)
205 #endif
206  << "\n";
207  }
208 }
209 
210 
211 
212 boost::scoped_array<double> osl::move_probability::
214 boost::scoped_array<double> osl::move_probability::
216 
218 StandardFeatureSet() : initialized(false)
219 {
220  pushBack(new TakeBackFeature, 1);
221  pushBack(new CheckFeature, 1);
222  pushBack(new SeeFeature, 1);
223  pushBack(new ContinueCapture, 1);
224  pushBack(new DropCaptured);
225  pushBack(new SquareY, 1);
226  pushBack(new SquareX, 1);
227  pushBack(new KingRelativeY, 1);
228  pushBack(new KingRelativeX, 1);
229  pushBack(new FromEffect, 1);
230  pushBack(new ToEffect, 1);
231  pushBack(new FromEffectLong, 1);
232  pushBack(new ToEffectLong, 1);
233  pushBack(new Pattern(0,-1)); // U
234  pushBack(new Pattern(1,-1)); // UL
235  pushBack(new Pattern(1,0)); // L
236  pushBack(new Pattern(0,1)); // D
237  pushBack(new Pattern(1,1)); // DL
238  pushBack(new Pattern(1,-2)); // UUL
239  pushBack(new Pattern(0,-2)); // UU
240  pushBack(new Pattern(0,2)); // DD
241  pushBack(new Pattern(2,0)); // LL
242  pushBack(new Pattern(1,2)); // DDL
245  pushBack(new PawnAttack);
246  pushBack(new CapturePtype, 1);
247  pushBack(new BlockLong);
248  pushBack(new BlockLongFrom);
249  pushBack(new LanceAttack);
250  pushBack(new BishopAttack);
251  pushBack(new RookAttack);
253  pushBack(new SendOff);
255  pushBack(new OpposingPawn);
257  pushBack(new LongRecapture);
259  pushBack(new AddEffectLong);
260  pushBack(new King5x5Ptype);
261  pushBack(new KingBlockade);
262  pushBack(new CoverFork);
264  pushBack(new LureDefender);
265  pushBack(new CoverPawn);
268  pushBack(new BookMove);
269  addFinished();
270 }
271 
274 {
275 }
276 
280 {
281  static StandardFeatureSet the_instance;
282  the_instance.setUp(verbose);
283  return the_instance;
284 }
285 
288 {
289  return instance(true).ok();
290 }
291 
292 namespace osl
293 {
294  namespace move_probability
295  {
297  }
298 }
301 {
302  boost::mutex::scoped_lock lk(standardfeatureset_lock);
303  static bool initialized = false;
304  if (initialized)
305  return true;
306  initialized = true;
307  weights.reset(new double[dimension()]);
308  std::string filename = OslConfig::home();
309  filename += "/data/move-order";
310  if (verbose)
311  std::cerr << "loading " << filename << ".bin ";
312  const bool success = load_binary(filename.c_str(), &weights[0]);
313  if (verbose)
314  std::cerr << (success ? "success" : "failed\a") << "\n";
315 
316  filename = OslConfig::home();
317  filename += "/data/move-tactical.txt";
318  const int tactical_dimension = 8*4;
319  tactical_weights.reset(new double[tactical_dimension]);
320  if (verbose)
321  std::cerr << "loading " << filename << " ";
322  std::ifstream is(filename.c_str());
323  for (int i=0; i<tactical_dimension; ++i)
324  is >> tactical_weights[i];
325  if (verbose)
326  std::cerr << (is ? "success" : "failed\a") << "\n";
327  this->initialized = success && is;
328  return this->initialized;
329 }
330 
332 generateLogProb(const StateInfo& state, MoveLogProbVector& out) const
333 {
334  FeatureSet::generateLogProb(state, out, &weights[0]);
335 }
336 
338 generateLogProb2(const StateInfo& state, MoveLogProbVector& out) const
339 {
341  double sum = FeatureSet::generateRating(state, moves, &weights[0]);
342  double elapsed = 0.0, welapsed = 0.0, last_p = 1.0;
343  std::sort(moves.begin(), moves.end());
344  for (int i=moves.size()-1; i>=0; --i) {
345  WeightedMove move = moves[i];
346  static const double scale = 100.0 / log(0.5);
347  if (i+1<(int)moves.size())
348  welapsed = std::max(welapsed, std::min(moves[i+1].first,move.first*4));
349  double p = move.first/(sum-elapsed+welapsed);
350  if (std::isnan(p) || p <= 1.0/(1<<12))
351  p = 1.0/(1<<12);
352  else
353  p = std::min(last_p, p);
354  int logp = std::max(50, static_cast<int>(log(p)*scale));
355  if (moves.size() - i <= 8)
356  logp = std::min(logp, 300);
357  else if (moves.size() - i <= 16)
358  logp = std::min(logp, 500);
359  out.push_back(MoveLogProb(move.second, logp));
360  elapsed += move.first;
361  welapsed = (welapsed+move.first)*(moves.size()-i)/moves.size();
362  }
363 }
364 
366 generateLogProb(const StateInfo& state, int /*limit*/, MoveLogProbVector& out, bool /*in_pv*/) const
367 {
368  generateLogProb2(state, out);
369 }
370 
372 matchLight(const StateInfo& state, Move move) const
373 {
374  return FeatureSet::matchLight(state, move, &weights[0]);
375 }
376 
378 matchExp(const StateInfo& state, Move move) const
379 {
380  return FeatureSet::matchExp(state, move, &weights[0]);
381 }
382 
384 matchNoExp(const StateInfo& state, Move move) const
385 {
386  return FeatureSet::matchNoExp(state, move, &weights[0]);
387 }
388 
390 logProbTakeBack(const StateInfo& state, Move target) const
391 {
392  const int progress8 = state.progress8();
393  const double sum = matchLight(state, target);
394  return tacticalLogProb(progress8*4 + 0, sum);
395 }
396 
398 logProbSeePlus(const StateInfo& state, Move target) const
399 {
400  const int progress8 = state.progress8();
401  const double sum = matchLight(state, target);
402  return tacticalLogProb(progress8*4 + 2, sum);
403 }
404 
406 tacticalLogProb(int offset, double sum) const
407 {
408  static const double scale = 100.0 / log(0.5);
409  double x = tactical_weights[offset] * sum + tactical_weights[offset+1];
410  double p = 1/(1.0+exp(-x));
411  return std::max(50, static_cast<int>(log(p)*scale));
412 }
413 
414 
415 
416 
417 // ;;; Local Variables:
418 // ;;; mode:c++
419 // ;;; c-basic-offset:2
420 // ;;; End:
421