All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
rating/featureSet.cc
Go to the documentation of this file.
1 /* featureSet.cc
2  */
4 #include "osl/config.h"
5 #include "osl/rating/group.h"
19 #include "osl/stat/variance.h"
20 #include "osl/oslConfig.h"
21 #include <boost/format.hpp>
22 #include <boost/foreach.hpp>
23 #include <map>
24 #include <iostream>
25 #include <fstream>
26 #include <sstream>
27 #include <iomanip>
28 #include <stdexcept>
29 #include <cmath>
30 
31 // statistics for each feature
32 // #define RATING_STAT
33 // show statistics loaded for each feature
34 // #define VERBOSE_RATING
35 // statistics between rating and limit
36 // #define RATING_STAT2
37 
38 const int MinRating = -4000;
39 
41 {
47  average(0), variance(0), probability(0)
48  {
49  }
50 };
51 
52 
55  : capture_group(-1), checkmate_if_capture_group(-1), sendoff_group(-1)
56 {
57 }
58 
61 {
62 #ifdef RATING_STAT
63  showStatistics(std::cerr);
64 #endif
65 }
66 
68 FeatureSet::makeRange(size_t group) const
69 {
70  int first = 0;
71  for (size_t i=0; i<groups.size(); ++i) {
72  if (i == group)
73  return std::make_pair(first, first+groups[i].size());
74  first += groups[i].size();
75  }
76  assert(0);
77  abort();
78 }
79 
80 void osl::rating::
82 {
83  assert(normal_groups.size() == groups.size());
84  weights.resize(features.size(), 1.0);
85  weightslog10.resize(features.size(), 1);
86  assert(weights.size() == features.size());
87  ranges.resize(groups.size());
88  for (size_t i=0; i<groups.size(); ++i)
89  ranges[i] = makeRange(i);
90  variance_match.resize(groups.size());
91  variance_all.resize(groups.size());
92  frequency.resize(groups.size());
93  statistics.resize(groups.size());
94 }
95 
96 void osl::rating::
98 {
99  add(new Group(f));
100 }
101 
102 void osl::rating::
104 {
105  features.reserve(features.size()+g->size());
106  for (size_t i=0; i<g->size(); ++i) {
107  features.push_back(&(*g)[i]);
108  }
109  groups.push_back(g);
110  effective_in_check.push_back(g->effectiveInCheck());
111 }
112 
113 void osl::rating::
115 {
116  normal_groups.push_back(true);
117  addCommon(g);
118 }
119 
120 void osl::rating::
122 {
123  capture_group = normal_groups.size();
124  normal_groups.push_back(false);
125  addCommon(g);
126 }
127 
128 void osl::rating::
130 {
131  sendoff_group = normal_groups.size();
132  normal_groups.push_back(false);
133  addCommon(g);
134 }
135 
136 void osl::rating::
138 {
139  checkmate_if_capture_group = normal_groups.size();
140  normal_groups.push_back(false);
141  addCommon(g);
142 }
143 
144 bool osl::rating::
145 FeatureSet::tryLoad(const std::string& input_directory)
146 {
147  bool result = true;
148  for (size_t i=0; i<groups.size(); ++i) {
149  const bool success = groups[i].load(input_directory, ranges[i], weights);
150  if (! success && result)
151  std::cerr << "warning: rating load failed " << groups[i].group_name << " " << i
152  << " in " << input_directory << "\n";
153  result &= success;
154  }
155  for (size_t i=0; i<features.size(); ++i)
156  weightslog10[i] = static_cast<int>(400*log10(weights[i]));
157 #ifndef RATING_STAT
158  std::string filename = input_directory + "/statistics.txt";
159  std::ifstream is(filename.c_str());
160  typedef std::map<std::string,Statistics> map_t;
161  map_t table;
162  std::string name;
163  double a, s, p, dummy;
164  while (is >> name >> a >> s >> dummy >> dummy >> p) {
165  Statistics& stat = table[name];
166  stat.average = a;
167  stat.variance = s*s;
168  stat.probability = p;
169  }
170  for (size_t i=0; i<groups.size(); ++i) {
171  double a = 0.0, v = 0.0;
172  for (size_t j=i+1; j<groups.size(); ++j) {
173  map_t::iterator q = table.find(groups[j].group_name);
174  if (q == table.end()) {
175  result = false;
176  break;
177  }
178  a += q->second.probability * q->second.average;
179  v += q->second.probability * q->second.variance;
180  }
181  statistics[i] = table[groups[i].group_name];
182  statistics[i].average_after = static_cast<int>(a);
183  statistics[i].sigma_after = static_cast<int>(sqrt(v)*3);
184 # ifdef VERBOSE_RATING
185  std::cerr << groups[i].group_name
186  << " " << statistics[i].average_after
187  << " " << statistics[i].sigma_after << "\n";
188 # endif
189  }
190 #endif
191  return result;
192 }
193 
194 void osl::rating::
195 FeatureSet::setWeight(size_t feature_id, const double& value)
196 {
197  weights[feature_id] = value;
198  weightslog10[feature_id] = static_cast<int>(400*log10(value));
199 }
200 
201 void osl::rating::
202 FeatureSet::generateRating(const NumEffectState& state, const RatingEnv& env,
203  int limit, RatedMoveVector& out, bool in_pv_or_all) const
204 {
205 #if (defined RATING_STAT) || (defined RATING_STAT2)
206  in_pv_or_all = true;
207 #endif
208  MoveVector moves;
209  const bool in_check = state.inCheck();
210  // generate legal moves except for pawn drop checkmate
211  if (in_check)
212  GenerateEscapeKing::generate(state, moves);
213  else
214  GenerateAllMoves::generate(state.turn(), state, moves);
215 
216  for (size_t i=0; i<moves.size(); ++i) {
217  if (moves[i].ptype() == KING) {
218  if (state.hasEffectAt(alt(state.turn()), moves[i].to()))
219  continue;
220  } else {
221  if (! in_check && env.my_pin.any() && ! moves[i].isDrop()
223  continue;
224  }
225 
226  if (in_pv_or_all)
227  out.push_back(makeRate(state, in_check, env, moves[i]));
228  else {
229  RatedMove r = makeRateWithCut(state, in_check, env, limit, moves[i]);
230  if (r.rating() > MinRating)
231  out.push_back(r);
232  }
233  }
234  out.sort();
235 }
236 
237 // width 4, [0,80]
238 static const osl::CArray2d<int, 8, 20> order_to_depth = {{
239  { 186, 213, 243, 247, 249, 255, 252, 258, 263, 269, 267, 279, 295, 295, 295, 295, 295, 295, 295, 295, },
240  { 191, 245, 283, 300, 313, 315, 319, 323, 326, 339, 321, 347, 334, 346, 328, 368, 328, 328, 328, 328, },
241  { 183, 250, 304, 328, 346, 352, 373, 366, 365, 379, 396, 379, 392, 416, 420, 374, 423, 378, 395, 399, },
242  { 184, 253, 312, 346, 358, 378, 389, 407, 409, 403, 404, 421, 432, 395, 421, 444, 444, 461, 411, 408, },
243  { 190, 256, 319, 350, 373, 397, 397, 403, 420, 431, 415, 450, 424, 416, 436, 447, 456, 439, 429, 428, },
244  { 197, 262, 324, 357, 374, 390, 407, 423, 415, 425, 436, 444, 458, 455, 439, 474, 451, 466, 464, 457, },
245  { 202, 268, 332, 360, 381, 386, 416, 416, 418, 433, 447, 446, 452, 462, 479, 468, 467, 486, 483, 459, },
246  { 205, 270, 330, 361, 383, 394, 410, 418, 427, 438, 438, 452, 446, 445, 447, 463, 475, 472, 483, 485, },
247 }};
248 static const osl::CArray2d<int, 8, 20> order_to_width = {{
249  { 262, 445, 584, 685, 788, 890, 982,1067,1120,1148, 1137,1156,1182,1231,1259, 1343,1352,1359,1359,1359, },
250  { 265, 456, 577, 665, 745, 809, 874, 938, 997,1061, 1088,1154,1179,1231,1259, 1343,1352,1359,1359,1359, },
251  { 260, 467, 596, 680, 751, 807, 872, 908, 951,1003, 1054,1072,1117,1168,1198, 1188,1267,1259,1311,1344, },
252  { 261, 467, 599, 688, 747, 810, 861, 914, 948, 975, 1008,1055,1092,1084,1142, 1189,1214,1254,1231,1258, },
253  { 264, 463, 595, 679, 746, 808, 844, 885, 933, 973, 987,1049,1048,1068,1115, 1151,1184,1191,1209,1233, },
254  { 268, 459, 588, 673, 732, 788, 840, 887, 910, 950, 989,1022,1059,1078,1088, 1144,1144,1180,1201,1216, },
255  { 271, 459, 587, 664, 727, 771, 835, 866, 899, 942, 984,1006,1037,1069,1105, 1114,1134,1173,1188,1186, },
256  { 272, 458, 581, 661, 725, 773, 824, 863, 902, 940, 966,1005,1023,1047,1074, 1113,1145,1163,1193,1214, },
257 }};
258 
259 const int sc_width = 100, sc_length = 18, sc_start = -400;
260 static const osl::CArray2d<int, 8, sc_length> score_to_depth = {{
261  { 263, 271, 274, 270, 278, 253, 235, 201, 171, 151, 111, 95, 83, 76, 78, 65, 71, 61,},
262  { 330, 334, 328, 316, 312, 304, 284, 256, 218, 188, 159, 136, 113, 103, 92, 87, 82, 71,},
263  { 377, 374, 376, 368, 356, 337, 311, 278, 246, 203, 175, 146, 131, 118, 107, 96, 81, 65,},
264  { 415, 424, 406, 396, 376, 345, 315, 276, 243, 211, 179, 155, 138, 121, 110, 91, 80, 62,},
265  { 423, 422, 433, 423, 405, 381, 341, 313, 276, 243, 210, 182, 158, 142, 123, 104, 85, 73,},
266  { 442, 451, 448, 437, 417, 395, 364, 333, 297, 267, 234, 202, 178, 158, 133, 107, 91, 76,},
267  { 446, 447, 455, 439, 427, 402, 373, 339, 307, 274, 242, 212, 188, 162, 133, 111, 92, 75,},
268  { 467, 468, 469, 453, 433, 412, 389, 365, 334, 301, 268, 236, 205, 177, 153, 131, 116, 101,},
269 }};
270 static const osl::CArray2d<int, 8, sc_length> score_to_width = {{
271  { 978, 880, 786, 676, 586, 475, 383, 302, 239, 208, 167, 153, 134, 127, 126, 100, 100, 82,},
272  { 1020, 935, 836, 730, 634, 549, 472, 412, 351, 312, 269, 232, 190, 167, 143, 127, 112, 95,},
273  { 1095, 998, 910, 810, 715, 623, 543, 471, 407, 338, 291, 246, 216, 189, 160, 140, 115, 90,},
274  { 1106,1031, 929, 829, 730, 635, 551, 469, 402, 341, 290, 249, 217, 186, 159, 127, 108, 85,},
275  { 1185,1092, 1011, 913, 811, 717, 617, 538, 459, 391, 331, 285, 242, 210, 176, 143, 114, 96,},
276  { 1224,1150, 1058, 957, 853, 755, 658, 573, 493, 424, 363, 308, 262, 223, 181, 142, 116, 96,},
277  { 1224,1134, 1057, 953, 857, 759, 666, 579, 501, 432, 373, 315, 267, 220, 178, 141, 115, 93,},
278  { 1296,1201, 1115,1009, 904, 807, 717, 638, 563, 492, 425, 363, 305, 254, 210, 172, 145, 123,},
279 }};
280 
281 const int rsc_length = 15;
282 static const osl::CArray2d<int, 8, rsc_length> relative_score_to_depth = {{
283  { 193, 220, 235, 249, 256, 263, 268, 274, 279, 284, 283, 279, 292, 267, 272, },
284  { 220, 243, 263, 273, 287, 300, 306, 308, 317, 325, 328, 339, 319, 336, 323, },
285  { 215, 242, 267, 287, 302, 314, 329, 340, 347, 360, 367, 364, 349, 387, 374, },
286  { 209, 243, 267, 293, 317, 332, 347, 360, 372, 383, 387, 387, 395, 398, 405, },
287  { 216, 244, 276, 303, 322, 344, 360, 374, 378, 397, 405, 414, 408, 400, 424, },
288  { 220, 251, 278, 307, 331, 355, 365, 381, 398, 406, 418, 423, 414, 433, 403, },
289  { 226, 254, 284, 311, 336, 354, 378, 390, 408, 418, 420, 448, 414, 446, 408, },
290  { 219, 250, 283, 310, 333, 356, 377, 391, 403, 417, 426, 426, 440, 445, 452, },
291 }};
292 static const osl::CArray2d<int, 8, rsc_length> relative_score_to_width = {{
293  { 214, 285, 357, 442, 520, 596, 669, 742, 816, 881, 928, 972,1045,1079,1143, },
294  { 237, 302, 374, 442, 519, 595, 662, 731, 799, 870, 925, 994,1031,1112,1159, },
295  { 230, 294, 367, 442, 517, 595, 675, 746, 815, 884, 951,1012,1060,1149,1185, },
296  { 224, 292, 361, 441, 524, 602, 682, 758, 833, 904, 964,1028,1105,1164,1223, },
297  { 231, 295, 369, 449, 525, 611, 692, 771, 839, 922, 985,1041,1094,1150,1239, },
298  { 235, 301, 370, 450, 532, 616, 690, 769, 851, 920, 991,1054,1100,1194,1217, },
299  { 240, 300, 373, 448, 527, 607, 693, 768, 845, 919, 981,1066,1094,1191,1218, },
300  { 233, 294, 364, 435, 511, 591, 674, 753, 832, 917, 993,1065,1157,1224,1300, },
301 }};
302 
303 inline int make_prob(int score, int order, int limit, int highest, int progress8, bool in_pv_or_all)
304 {
305  const int order_index = std::min((int)order/4, 19);
306  int result = limit+1;
307  if (order_to_width[progress8][order_index] <= limit) {
308  result = (order == 0) ? 100 : order_to_depth[progress8][order_index];
309  }
310  score = std::max(sc_start, score);
311  highest = std::max(sc_start, highest);
312  const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
313  if (limit > 600 && score_to_width[progress8][score_index] <= limit) {
314  result = std::min(result, score_to_depth[progress8][score_index]);
315  }
316  if (limit > 700 && order > 0 && in_pv_or_all) {
317  const int rscore_index = std::min((highest - score)/100, rsc_length-1);
318  assert(rscore_index >= 0);
319  if (relative_score_to_width[progress8][rscore_index] <= limit)
320  result = std::min(result, relative_score_to_depth[progress8][rscore_index]);
321  }
322  return result;
323 }
324 
325 #ifdef RATING_STAT2
326 namespace osl
327 {
328  namespace
329  {
330  CArray2d<CArray<stat::Average,8>,14,40> data; // selected/generated for each range
331  CArray2d<CArray<double,8>,14,80> selected_all;
332  void add_stat(int limit, int rating, bool added, int progress8)
333  {
334  limit = std::min(limit, 999);
335  limit -= 300;
336  limit = std::max(limit, 0);
337  rating = std::max(-999,rating);
338  rating = std::min(999,rating);
339  data[limit/50][(rating+1000)/50][progress8].add(added);
340  if (added)
341  selected_all[limit/50][(rating+1000)/25][progress8] += 1.0;
342  }
343  struct Reporter
344  {
345  ~Reporter()
346  {
347  std::cerr << "limit " << 0*50+300 << " - " << (data.size1()-1)*50+300 << "\n";
348  for (int p=0; p<8; ++p)
349  {
350  std::cerr << "progress8 " << p << "\n ";
351  for (size_t j=0; j<data.size1(); ++j)
352  {
353  size_t i=0;
354  for (; i<data.size2(); ++i)
355  if (data[j][i][p].getAverage() > 0.05)
356  break;
357  std::cerr << (boost::format("%+4d, ") % static_cast<int>(i)*50-1000);
358  }
359  std::cerr << "\n";
360  }
361  std::cerr << "limit " << 0*50+300 << " - " << (selected_all.size1()-1)*50+300 << "\n";
362  CArray<double, 3> prob = {{ 0.01, 0.03, 0.05 }};
363  for (size_t pp=0; pp<prob.size(); ++pp) {
364  std::cerr << "prob " << prob[pp] << "\n";
365  for (int p=0; p<8; ++p)
366  {
367  std::cerr << "progress8 " << p << "\n ";
368  for (size_t j=0; j<selected_all.size1(); ++j)
369  {
370  double sum = 0;
371  for (size_t i=0; i<selected_all.size2(); ++i)
372  sum += selected_all[j][i][p];
373  size_t i=0
374  for (double so_far = 0; i<selected_all.size2(); ++i) {
375  so_far += selected_all[j][i][p];
376  if (so_far > prob[pp]*sum)
377  break;
378  }
379  std::cerr << (boost::format("%+4d, ") % static_cast<int>(i)*25-1000);
380  }
381  std::cerr << "\n";
382  }
383  }
384  }
385  } _reporter;
386  }
387 }
388 #endif
389 
390 void osl::rating::
391 FeatureSet::generateLogProb(const NumEffectState& state, const RatingEnv& env,
392  int limit, MoveLogProbVector& out, bool in_pv_or_all) const
393 {
394  RatedMoveVector score;
395  generateRating(state, env, limit, score, in_pv_or_all);
396  if (score.empty())
397  return;
398 
399  const int highest = score[0].rating();
400  const int progress8 = env.progress.value()/2;
401  for (size_t i=0; i<score.size(); ++i) {
402  const int log_prob = make_prob(score[i].rating(), i, limit, highest, progress8, in_pv_or_all);
403 #ifdef RATING_STAT2
404  add_stat(limit, score[i].rating(), log_prob <= limit, progress8);
405 #endif
406  out.push_back(MoveLogProb(score[i].move(), log_prob));
407  }
408 }
409 
410 const int max_score = 999, min_score = 0;
411 static const osl::CArray<int, 10> score_to_depth_takeback = {{
412  223, 204, 208, 190, 159, 137, 124, 110, 100, 89
413 }};
414 static const osl::CArray<int, 10> score_to_depth_seeplus = {{
415  356, 337, 296, 262, 230, 200, 171, 148, 132, 120,
416 }};
417 static const osl::CArray<int, 10> score_to_depth_kingescape = {{
418  203, 201, 199, 188, 181, 169, 159, 147, 136, 122,
419 }};
420 
421 int osl::rating::
422 FeatureSet::logProbTakeBack(const NumEffectState& state, const RatingEnv& env, Move move) const
423 {
424  const bool in_check = state.inCheck();
425  const int score = makeRate(state, in_check, env, move).rating();
426  if (score >= 1000) {
427  const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
428  return score_to_depth[env.progress.value()/2][score_index];
429  }
430  return score_to_depth_takeback[std::max(min_score, std::min(max_score, score))/100];
431 }
432 int osl::rating::
433 FeatureSet::logProbSeePlus(const NumEffectState& state, const RatingEnv& env,
434  Move move) const
435 {
436  const bool in_check = state.inCheck();
437  const int score = makeRate(state, in_check, env, move).rating();
438  if (score >= 1000) {
439  const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
440  return score_to_depth[env.progress.value()/2][score_index];
441  }
442  return score_to_depth_seeplus[std::max(min_score, std::min(max_score, score))/100];
443 }
444 int osl::rating::
445 FeatureSet::logProbKingEscape(const NumEffectState& state, const RatingEnv& env,
446  Move move) const
447 {
448  const bool in_check = state.inCheck();
449  const int score = makeRate(state, in_check, env, move).rating();
450  if (score >= 1000) {
451  const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
452  return score_to_depth[env.progress.value()/2][score_index];
453  }
454  const int prob = score_to_depth_kingescape[std::max(min_score, std::min(max_score, score))/100];
455  assert(prob > 0);
456  return prob;
457 }
458 
459 int osl::rating::
460 FeatureSet::rating(const NumEffectState& state,
461  const RatingEnv& env, Move move, size_t group_id) const
462 {
463  int found = groups[group_id].findMatch(state, move, env);
464  if (found < 0) {
465 #ifdef RATING_STAT
466  const int progress8 = env.progress.value()/2;
467  frequency[group_id][progress8].add(0);
468  variance_all[group_id].add(0);
469 #endif
470  return 0;
471  }
472  found += ranges[group_id].first;
473 #ifdef RATING_STAT
474  const int progress8 = env.progress.value()/2;
475  frequency[group_id][progress8].add(1);
476  variance_match[group_id][progress8].add(weightslog10[found]);
477  variance_all[group_id].add(weightslog10[found]);
478 #endif
479  return weightslog10[found];
480 }
481 
483 FeatureSet::makeRate(const NumEffectState& state, bool in_check,
484  const RatingEnv& env, Move move) const
485 {
486  int sum = 0;
487  for (size_t j=0; j<groups.size(); ++j) {
488  if (! normal_groups[j])
489  continue;
490  if (in_check && ! effectiveInCheck(j))
491  continue;
492  sum += rating(state, env, move, j);
493  }
494  int capture = 0;
495  if (capture_group >= 0)
496  capture = rating(state, env, move, capture_group);
497  int checkmate_if_capture = 0;
498  if (checkmate_if_capture_group >= 0)
499  checkmate_if_capture = rating(state, env, move, checkmate_if_capture_group);
500  sum += checkmate_if_capture;
501  int sendoff = 0;
502  if (sendoff_group >= 0)
503  sendoff = rating(state, env, move, sendoff_group);
504  sum += sendoff;
505 
506  if (checkmate_if_capture > 0)
507  capture = std::max(0, capture);
508  else if (sendoff > 0 && capture < 0)
509  capture /= 2;
510  const int optimistic = sum + std::max(0, capture);
511  sum += capture;
512 
513  return RatedMove(move, sum, optimistic);
514 }
515 
516 
517 // limit [0-800)
518 #if 1
519 // 1%
520 static const osl::CArray2d<int,8,16> threshold = {{
521  {
522  0, 0, 0, 0, 0, 0,
523  100, 100, 50, 0, 0, -75,-100,-150,-200,-200,
524  },
525  {
526  0, 0, 0, 0, 0, 0,
527  125, 125, 125, 25, 25, -50, -50,-100,-125,-225,
528  },
529  {
530  0, 0, 0, 0, 0, 0,
531  100, 75, 100, 25, 0, -25, -50,-100,-125,-175,
532  },
533  {
534  0, 0, 0, 0, 0, 0,
535  75, 50, 75, 0, -25, -25, -75,-100,-125,-200,
536  },
537  {
538  0, 0, 0, 0, 0, 0,
539  125, 125, 150, 50, 50, 50, -25, 0, -50,-200,
540  },
541  {
542  0, 0, 0, 0, 0, 0,
543  175, 200, 200, 75, 75, 75, 0, 0,-175,-300,
544  },
545  {
546  0, 0, 0, 0, 0, 0,
547  175, 175, 200, 50, 75, 75, 25, 0,-100,-250,
548  },
549  {
550  0, 0, 0, 0, 0, 0,
551  225, 200, 225, 75, 100, 75, 50, 0, 0,-250,
552  },
553 }};
554 #endif
555 #if 0
556 static const osl::CArray2d<int,8,16> threshold = {{
557  // 0, 50, 100, 150, 200, ...
558  {
559  0, 0, 0, 0, 0, 0,
560  100,100,100,0,0,-100,-100,-200,-200,-200,
561  },
562  {
563  0, 0, 0, 0, 0, 0,
564  100,100,100,0,0,-100,-100,-100,-100,-200,
565  },
566  {
567  0, 0, 0, 0, 0, 0,
568  100,100,100,0,0,0,-100,-100,-100,-200
569  },
570  {
571  0, 0, 0, 0, 0, 0,
572  100,100,100,0,0,0,-100,-100,-100,-200
573  },
574  {
575  0, 0, 0, 0, 0, 0,
576  200,200,200,100,100,100,0,0,0,-100
577  },
578  {
579  0, 0, 0, 0, 0, 0,
580  300,300,300,100,100,100,100,0,-200,-300
581  },
582  {
583  0, 0, 0, 0, 0, 0,
584  300,300,300,100,100,100,100,0,0,-200
585  },
586  {
587  0, 0, 0, 0, 0, 0,
588  300,300,300,100,200,200,100,0,0,-200
589  },
590 }};
591 #endif
593 FeatureSet::makeRateWithCut(const NumEffectState& state,
594  bool in_check,
595  const RatingEnv& env,
596  int limit, Move move) const
597 {
598  if (limit >= 800)
599  return makeRate(state, in_check, env, move);
600 
601  limit /= 50;
602  int sum = 0;
603  int capture = 0;
604  int checkmate_if_capture = 0;
605  const int progress8 = env.progress.value()/2;
606  for (size_t j=0; j<groups.size(); ++j) {
607  if (in_check && ! effectiveInCheck(j))
608  continue;
609  const int r = rating(state, env, move, j);
610  sum += r;
611  if ((int)j == capture_group) {
612  capture = r;
613  }
614  else if ((int)j == checkmate_if_capture_group) {
615  checkmate_if_capture = r;
616  if (checkmate_if_capture > 0 && capture < 0) {
617  sum -= capture;
618  capture = 0;
619  }
620  }
621  // cut?
622  if (j % 8 == 7) {
623  int sigma = statistics[j].sigma_after;
624  if (sum + statistics[j].average_after + sigma < threshold[progress8][limit]) {
625  return RatedMove(move, MinRating, MinRating);
626  }
627  }
628  }
629 
630  const int optimistic = sum + std::max(0, capture);
631  return RatedMove(move, sum, optimistic);
632 }
633 
634 const std::string osl::rating::
635 FeatureSet::annotate(const NumEffectState& state,
636  const RatingEnv& env, Move move) const
637 {
638  const bool in_check = state.inCheck();
639  vector<std::pair<int, std::string> > values;
640  for (size_t j=0; j<groups.size(); ++j) {
641  if (in_check && ! effectiveInCheck(j))
642  continue;
643  int found = groups[j].findMatch(state, move, env);
644  if (found < 0)
645  continue;
646  found += ranges[j].first;
647  values.push_back(std::make_pair(weightslog10[found], groups[j].group_name));
648  }
649  std::sort(values.begin(), values.end());
650  std::reverse(values.begin(), values.end());
651  std::ostringstream ss;
652  for (size_t i=0; i<values.size(); ++i) {
653  if (i)
654  ss << " ";
655  ss << values[i].second << " " << values[i].first;
656  }
657  return ss.str();
658 }
659 
660 #ifndef MINIMAL
661 void osl::rating::
662 FeatureSet::showGroup(std::ostream& os, size_t group_id) const
663 {
664  os << std::setprecision(3);
665  group(group_id).show(os, 12, range(group_id), weights);
666 }
667 
668 void osl::rating::
669 FeatureSet::save(const std::string& output_directory, size_t group_id) const
670 {
671  group(group_id).saveResult(output_directory, range(group_id), weights);
672 }
673 
674 void osl::rating::
675 FeatureSet::showStatistics(std::ostream& os) const
676 {
677  os << std::setprecision(3);
678  for (size_t i=0; i<groups.size(); ++i) {
679  os << groups[i].group_name << "\t";
680  for (int p=0; p<8; ++p) {
681  os << " " << variance_match[i][p].getAverage()
682  << " " << sqrt(variance_match[i][p].variance())
683  << " " << frequency[i][p].getAverage() << " ";
684  }
685  os << "\t" << variance_all[i].getAverage()
686  << "\t" << sqrt(variance_all[i].variance())
687  << "\n";
688  }
689 }
690 #endif
691 
693 {
694  return OslConfig::home()+"/data/rating";
695 }
696 
697 /* ------------------------------------------------------------------------- */
698 
701 {
702  add(new CaptureGroup());
703  add(new SquareYGroup());
704  add(new RelativeKingXGroup(true));
705  add(new SquareXGroup());
706  add(new TakeBackGroup());
707  add(new RelativeKingYGroup(true));
708  add(new FromEffectGroup());
709  add(new PatternGroup(U));
710  add(new RelativeKingXGroup(false));
711  add(new PatternGroup(D));
712 
713  add(new PatternLongGroup(0));
714  add(new CheckGroup());
715  add(new BlockGroup());
716  add(new PtypeAttackedGroup());
717 
718  add(new PatternGroup(U,U));
719  add(new ImmediateAddSupportGroup()); // 300 cycles
720  add(new PatternGroup(DR));
721  add(new RelativeKingYGroup(false));
722  add(new DefenseKing8Group());
723  add(new PatternGroup(L));
724  add(new PatternGroup(UL));
725 
726  add(new ToSupportedGroup());
727 
728  add(new PatternGroup(UR));
729  add(new PatternBlockGroup(ROOK));
730  add(new AttackKing8Group());
731  add(new PatternGroup(R));
732  add(new PatternGroup(DL));
733 
734  add(new PatternGroup(R,R));
735  add(new PatternLongGroup(3));
736  add(new PatternGroup(UUL));
737  add(new PatternGroup(UUR));
738  add(new PatternGroup(L,L));
739 
740  add(new PatternLongGroup(2));
741  add(new OpenGroup());
742  add(new PatternBlockGroup(LANCE));
743  add(new ChaseGroup());
744  add(new PatternLongGroup(1));
745  add(new PatternLongGroup2(1));
746  add(new PatternBlockGroup(BISHOP));
747  add(new PatternGroup(UR,R));
748  add(new PatternLongGroup2(0));
749  add(new PatternGroup(UL,L));
750 
751  add(new ImmediateEscapeGroup());
752  add(new PatternLongGroup2(3));
753  add(new PatternLongGroup2(2));
754  add(new KaranariGroup());
755 
756  add(new BigramAttackGroup(true, true));
757  add(new BigramAttackGroup(false, true));
758  add(new BigramAttackGroup(true, false));
759  add(new BigramAttackGroup(false, false));
760 
761  add(new DropCapturedGroup());
762  add(new ContinueCaptureGroup());
763  add(new PawnAttackGroup());
764  add(new ThreatmateGroup());
765 
766  add(new BadLanceGroup());
767  add(new CheckmateIfCaptureGroup());
768  add(new RookDefense());
769  add(new SendOffGroup());
770 
771  add(new PinGroup());
772  add(new KingEscapeGroup());
773  add(new EscapePinGroup());
774 
775  addFinished();
776  bool success = tryLoad(defaultDirectory());
777  if (! allow_load_failure && ! success) {
778  std::cerr << "error: unable to load rating from " << defaultDirectory();
779  throw std::runtime_error("load failed " + OslConfig::home()+defaultDirectory());
780  }
781 }
782 
783 
786 {
787  static osl::rating::StandardFeatureSet common_instance;
788  return common_instance;
789 }
790 
792 {
793  std::cerr << "loading " << defaultDirectory() << ' ';
794  try {
795  instance();
796  std::cerr << "success\n";
797  }
798  catch (std::exception& e)
799  {
800  std::cerr << e.what() << "\n";
801  return false;
802  }
803  catch (...) {
804  std::cerr << "unknown exception\n";
805  return false;
806  }
807  return true;
808 }
809 
811 CaptureSet::CaptureSet(bool allow_load_failure)
812 {
813  add(new CaptureGroup());
814  add(new ShadowEffectGroup());
815 
816  addFinished();
817  bool success = tryLoad(defaultDirectory());
818  if (! allow_load_failure && ! success) {
819  std::cerr << "error: unable to load rating from " << defaultDirectory();
820  throw std::runtime_error("load failed " + defaultDirectory());
821  }
822 }
823 
824 /* ------------------------------------------------------------------------- */
825 // ;;; Local Variables:
826 // ;;; mode:c++
827 // ;;; c-basic-offset:2
828 // ;;; coding:utf-8
829 // ;;; End: