featureSet.cc
Go to the documentation of this file.
00001 /* featureSet.cc
00002  */
00003 #include "osl/rating/featureSet.h"
00004 #include "osl/config.h"
00005 #include "osl/rating/group.h"
00006 #include "osl/rating/group/captureGroup.h"
00007 #include "osl/rating/group/escape.h"
00008 #include "osl/rating/group/squareGroup.h"
00009 #include "osl/rating/group/patternGroup.h"
00010 #include "osl/rating/group/bigramGroup.h"
00011 #include "osl/rating/group/king8Group.h"
00012 #include "osl/rating/group/checkmateGroup.h"
00013 #include "osl/rating/group/pinGroup.h"
00014 #include "osl/move_generator/allMoves.h"
00015 #include "osl/move_generator/escape_.h"
00016 #include "osl/move_classifier/moveAdaptor.h"
00017 #include "osl/move_classifier/safeMove.h"
00018 #include "osl/container/moveVector.h"
00019 #include "osl/stat/variance.h"
00020 #include "osl/oslConfig.h"
00021 #include <boost/format.hpp>
00022 #include <boost/foreach.hpp>
00023 #include <map>
00024 #include <iostream>
00025 #include <fstream>
00026 #include <sstream>
00027 #include <iomanip>
00028 #include <stdexcept>
00029 #include <cmath>
00030 
00031 // statistics for each feature
00032 // #define RATING_STAT
00033 // show statistics loaded for each feature
00034 // #define VERBOSE_RATING
00035 // statistics between rating and limit
00036 // #define RATING_STAT2
00037 
00038 const int MinRating = -4000;
00039 
00040 struct osl::rating::FeatureSet::Statistics
00041 {
00043   int average_after, sigma_after;
00045   double average, variance, probability;
00046   Statistics() : average_after(0), sigma_after(0), 
00047                  average(0), variance(0), probability(0)
00048   {
00049   }  
00050 };
00051 
00052 
00053 osl::rating::
00054 FeatureSet::FeatureSet()
00055   : capture_group(-1), checkmate_if_capture_group(-1), sendoff_group(-1)
00056 {
00057 }
00058 
00059 osl::rating::
00060 FeatureSet::~FeatureSet()
00061 {
00062 #ifdef RATING_STAT
00063   showStatistics(std::cerr);
00064 #endif
00065 }
00066 
00067 const osl::rating::range_t osl::rating::
00068 FeatureSet::makeRange(size_t group) const
00069 {
00070   int first = 0;
00071   for (size_t i=0; i<groups.size(); ++i) {
00072     if (i == group)
00073       return std::make_pair(first, first+groups[i].size());
00074     first += groups[i].size();
00075   }
00076   assert(0);
00077   abort();
00078 }
00079 
00080 void osl::rating::
00081 FeatureSet::addFinished()
00082 {
00083   assert(normal_groups.size() == groups.size());
00084   weights.resize(features.size(), 1.0);
00085   weightslog10.resize(features.size(), 1);
00086   assert(weights.size() == features.size());
00087   ranges.resize(groups.size());
00088   for (size_t i=0; i<groups.size(); ++i)
00089     ranges[i] = makeRange(i);
00090   variance_match.resize(groups.size());
00091   variance_all.resize(groups.size());
00092   frequency.resize(groups.size());
00093   statistics.resize(groups.size());
00094 }
00095 
00096 void osl::rating::
00097 FeatureSet::add(Feature *f)
00098 {
00099   add(new Group(f));
00100 }
00101 
00102 void osl::rating::
00103 FeatureSet::addCommon(Group *g)
00104 {
00105   features.reserve(features.size()+g->size());
00106   for (size_t i=0; i<g->size(); ++i) {
00107     features.push_back(&(*g)[i]);
00108   }
00109   groups.push_back(g);
00110   effective_in_check.push_back(g->effectiveInCheck());
00111 }
00112 
00113 void osl::rating::
00114 FeatureSet::add(Group *g)
00115 {
00116   normal_groups.push_back(true);
00117   addCommon(g);
00118 }
00119 
00120 void osl::rating::
00121 FeatureSet::add(CaptureGroup *g)
00122 {
00123   capture_group = normal_groups.size();
00124   normal_groups.push_back(false);
00125   addCommon(g);
00126 }
00127 
00128 void osl::rating::
00129 FeatureSet::add(SendOffGroup *g)
00130 {
00131   sendoff_group = normal_groups.size();
00132   normal_groups.push_back(false);
00133   addCommon(g);
00134 }
00135 
00136 void osl::rating::
00137 FeatureSet::add(CheckmateIfCaptureGroup *g)
00138 {
00139   checkmate_if_capture_group = normal_groups.size();
00140   normal_groups.push_back(false);  
00141   addCommon(g);
00142 }
00143 
00144 bool osl::rating::
00145 FeatureSet::tryLoad(const std::string& input_directory) 
00146 {
00147   bool result = true;
00148   for (size_t i=0; i<groups.size(); ++i) {
00149     const bool success = groups[i].load(input_directory, ranges[i], weights);
00150     if (! success && result)
00151       std::cerr << "warning: rating load failed " << groups[i].group_name << " " << i 
00152                 << " in " << input_directory << "\n";
00153     result &= success;
00154   }
00155   for (size_t i=0; i<features.size(); ++i)
00156     weightslog10[i] = static_cast<int>(400*log10(weights[i]));
00157 #ifndef RATING_STAT
00158   std::string filename = input_directory + "/statistics.txt";
00159   std::ifstream is(filename.c_str());
00160   typedef std::map<std::string,Statistics> map_t;
00161   map_t table;
00162   std::string name;
00163   double a, s, p, dummy;
00164   while (is >> name >> a >> s >> dummy >> dummy >> p) {
00165     Statistics& stat = table[name];
00166     stat.average = a;
00167     stat.variance = s*s;
00168     stat.probability = p;
00169   }
00170   for (size_t i=0; i<groups.size(); ++i) {
00171     double a = 0.0, v = 0.0;
00172     for (size_t j=i+1; j<groups.size(); ++j) {
00173       map_t::iterator q = table.find(groups[j].group_name);
00174       if (q == table.end()) {
00175         result = false;
00176         break;
00177       }
00178       a += q->second.probability * q->second.average;
00179       v += q->second.probability * q->second.variance;
00180     }
00181     statistics[i] = table[groups[i].group_name];
00182     statistics[i].average_after = static_cast<int>(a);
00183     statistics[i].sigma_after = static_cast<int>(sqrt(v)*3);
00184 #  ifdef VERBOSE_RATING
00185     std::cerr << groups[i].group_name
00186               << " " << statistics[i].average_after
00187               << " " << statistics[i].sigma_after << "\n";
00188 #  endif
00189   }
00190 #endif
00191   return result;
00192 }
00193 
00194 void osl::rating::
00195 FeatureSet::setWeight(size_t feature_id, const double& value)
00196 {
00197   weights[feature_id] = value; 
00198   weightslog10[feature_id] = static_cast<int>(400*log10(value));
00199 }
00200 
00201 void osl::rating::
00202 FeatureSet::generateRating(const NumEffectState& state, const RatingEnv& env,
00203                            int limit, RatedMoveVector& out, bool in_pv_or_all) const
00204 {
00205 #if (defined RATING_STAT) || (defined RATING_STAT2)
00206   in_pv_or_all = true;
00207 #endif
00208   MoveVector moves;
00209   const bool in_check = state.inCheck();
00210   // generate legal moves except for pawn drop checkmate
00211   if (in_check)
00212     GenerateEscapeKing::generate(state, moves);
00213   else
00214     GenerateAllMoves::generate(state.turn(), state, moves);
00215 
00216   for (size_t i=0; i<moves.size(); ++i) {
00217     if (moves[i].ptype() == KING) {
00218       if (state.hasEffectAt(alt(state.turn()), moves[i].to()))
00219         continue;
00220     } else {
00221       if (! in_check && env.my_pin.any() && ! moves[i].isDrop()
00222           && move_classifier::PlayerMoveAdaptor<move_classifier::KingOpenMove>::isMember(state, moves[i]))
00223         continue;
00224     }
00225 
00226     if (in_pv_or_all)
00227       out.push_back(makeRate(state, in_check, env, moves[i]));
00228     else {
00229       RatedMove r = makeRateWithCut(state, in_check, env, limit, moves[i]);
00230       if (r.rating() > MinRating)
00231         out.push_back(r);
00232     }
00233   }
00234   out.sort();
00235 }
00236 
00237 // width 4, [0,80]
00238 static const osl::CArray2d<int, 8, 20> order_to_depth = {{
00239  {  186, 213, 243, 247, 249,  255, 252, 258, 263, 269,  267, 279, 295, 295, 295,  295, 295, 295, 295, 295, },
00240  {  191, 245, 283, 300, 313,  315, 319, 323, 326, 339,  321, 347, 334, 346, 328,  368, 328, 328, 328, 328, },
00241  {  183, 250, 304, 328, 346,  352, 373, 366, 365, 379,  396, 379, 392, 416, 420,  374, 423, 378, 395, 399, },
00242  {  184, 253, 312, 346, 358,  378, 389, 407, 409, 403,  404, 421, 432, 395, 421,  444, 444, 461, 411, 408, },
00243  {  190, 256, 319, 350, 373,  397, 397, 403, 420, 431,  415, 450, 424, 416, 436,  447, 456, 439, 429, 428, },
00244  {  197, 262, 324, 357, 374,  390, 407, 423, 415, 425,  436, 444, 458, 455, 439,  474, 451, 466, 464, 457, },
00245  {  202, 268, 332, 360, 381,  386, 416, 416, 418, 433,  447, 446, 452, 462, 479,  468, 467, 486, 483, 459, },
00246  {  205, 270, 330, 361, 383,  394, 410, 418, 427, 438,  438, 452, 446, 445, 447,  463, 475, 472, 483, 485, },
00247 }};
00248 static const osl::CArray2d<int, 8, 20> order_to_width = {{
00249  {  262, 445, 584, 685, 788,  890, 982,1067,1120,1148, 1137,1156,1182,1231,1259, 1343,1352,1359,1359,1359, },
00250  {  265, 456, 577, 665, 745,  809, 874, 938, 997,1061, 1088,1154,1179,1231,1259, 1343,1352,1359,1359,1359, },
00251  {  260, 467, 596, 680, 751,  807, 872, 908, 951,1003, 1054,1072,1117,1168,1198, 1188,1267,1259,1311,1344, },
00252  {  261, 467, 599, 688, 747,  810, 861, 914, 948, 975, 1008,1055,1092,1084,1142, 1189,1214,1254,1231,1258, },
00253  {  264, 463, 595, 679, 746,  808, 844, 885, 933, 973,  987,1049,1048,1068,1115, 1151,1184,1191,1209,1233, },
00254  {  268, 459, 588, 673, 732,  788, 840, 887, 910, 950,  989,1022,1059,1078,1088, 1144,1144,1180,1201,1216, },
00255  {  271, 459, 587, 664, 727,  771, 835, 866, 899, 942,  984,1006,1037,1069,1105, 1114,1134,1173,1188,1186, },
00256  {  272, 458, 581, 661, 725,  773, 824, 863, 902, 940,  966,1005,1023,1047,1074, 1113,1145,1163,1193,1214, },
00257 }};
00258 
00259 const int sc_width = 100, sc_length = 18, sc_start = -400;
00260 static const osl::CArray2d<int, 8, sc_length> score_to_depth = {{
00261  {  263, 271,  274, 270, 278, 253, 235,  201, 171, 151, 111,  95,   83,  76,  78,  65,  71,   61,},
00262  {  330, 334,  328, 316, 312, 304, 284,  256, 218, 188, 159, 136,  113, 103,  92,  87,  82,   71,},
00263  {  377, 374,  376, 368, 356, 337, 311,  278, 246, 203, 175, 146,  131, 118, 107,  96,  81,   65,},
00264  {  415, 424,  406, 396, 376, 345, 315,  276, 243, 211, 179, 155,  138, 121, 110,  91,  80,   62,},
00265  {  423, 422,  433, 423, 405, 381, 341,  313, 276, 243, 210, 182,  158, 142, 123, 104,  85,   73,},
00266  {  442, 451,  448, 437, 417, 395, 364,  333, 297, 267, 234, 202,  178, 158, 133, 107,  91,   76,},
00267  {  446, 447,  455, 439, 427, 402, 373,  339, 307, 274, 242, 212,  188, 162, 133, 111,  92,   75,},
00268  {  467, 468,  469, 453, 433, 412, 389,  365, 334, 301, 268, 236,  205, 177, 153, 131, 116,  101,},
00269 }};
00270 static const osl::CArray2d<int, 8, sc_length> score_to_width = {{
00271  {  978, 880,  786, 676, 586, 475, 383,  302, 239, 208, 167, 153,  134, 127, 126, 100, 100,   82,},
00272  { 1020, 935,  836, 730, 634, 549, 472,  412, 351, 312, 269, 232,  190, 167, 143, 127, 112,   95,},
00273  { 1095, 998,  910, 810, 715, 623, 543,  471, 407, 338, 291, 246,  216, 189, 160, 140, 115,   90,},
00274  { 1106,1031,  929, 829, 730, 635, 551,  469, 402, 341, 290, 249,  217, 186, 159, 127, 108,   85,},
00275  { 1185,1092, 1011, 913, 811, 717, 617,  538, 459, 391, 331, 285,  242, 210, 176, 143, 114,   96,},
00276  { 1224,1150, 1058, 957, 853, 755, 658,  573, 493, 424, 363, 308,  262, 223, 181, 142, 116,   96,},
00277  { 1224,1134, 1057, 953, 857, 759, 666,  579, 501, 432, 373, 315,  267, 220, 178, 141, 115,   93,},
00278  { 1296,1201, 1115,1009, 904, 807, 717,  638, 563, 492, 425, 363,  305, 254, 210, 172, 145,  123,},
00279 }};
00280 
00281 const int rsc_length = 15;
00282 static const osl::CArray2d<int, 8, rsc_length> relative_score_to_depth = {{
00283  {  193, 220, 235, 249, 256,  263, 268, 274, 279, 284,  283, 279, 292, 267, 272, },
00284  {  220, 243, 263, 273, 287,  300, 306, 308, 317, 325,  328, 339, 319, 336, 323, },
00285  {  215, 242, 267, 287, 302,  314, 329, 340, 347, 360,  367, 364, 349, 387, 374, },
00286  {  209, 243, 267, 293, 317,  332, 347, 360, 372, 383,  387, 387, 395, 398, 405, },
00287  {  216, 244, 276, 303, 322,  344, 360, 374, 378, 397,  405, 414, 408, 400, 424, },
00288  {  220, 251, 278, 307, 331,  355, 365, 381, 398, 406,  418, 423, 414, 433, 403, },
00289  {  226, 254, 284, 311, 336,  354, 378, 390, 408, 418,  420, 448, 414, 446, 408, },
00290  {  219, 250, 283, 310, 333,  356, 377, 391, 403, 417,  426, 426, 440, 445, 452, },
00291 }};
00292 static const osl::CArray2d<int, 8, rsc_length> relative_score_to_width = {{
00293  {  214, 285, 357, 442, 520,  596, 669, 742, 816, 881,  928, 972,1045,1079,1143, },
00294  {  237, 302, 374, 442, 519,  595, 662, 731, 799, 870,  925, 994,1031,1112,1159, },
00295  {  230, 294, 367, 442, 517,  595, 675, 746, 815, 884,  951,1012,1060,1149,1185, },
00296  {  224, 292, 361, 441, 524,  602, 682, 758, 833, 904,  964,1028,1105,1164,1223, },
00297  {  231, 295, 369, 449, 525,  611, 692, 771, 839, 922,  985,1041,1094,1150,1239, },
00298  {  235, 301, 370, 450, 532,  616, 690, 769, 851, 920,  991,1054,1100,1194,1217, },
00299  {  240, 300, 373, 448, 527,  607, 693, 768, 845, 919,  981,1066,1094,1191,1218, },
00300  {  233, 294, 364, 435, 511,  591, 674, 753, 832, 917,  993,1065,1157,1224,1300, },
00301 }};
00302 
00303 inline int make_prob(int score, int order, int limit, int highest, int progress8, bool in_pv_or_all) 
00304 {
00305   const int order_index = std::min((int)order/4, 19);
00306   int result = limit+1;
00307   if (order_to_width[progress8][order_index] <= limit) {
00308     result = (order == 0) ? 100 : order_to_depth[progress8][order_index];
00309   }  
00310   score = std::max(sc_start, score);
00311   highest = std::max(sc_start, highest);
00312   const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
00313   if (limit > 600 && score_to_width[progress8][score_index] <= limit) {
00314     result = std::min(result, score_to_depth[progress8][score_index]);
00315   }
00316   if (limit > 700 && order > 0 && in_pv_or_all) {
00317     const int rscore_index = std::min((highest - score)/100, rsc_length-1);
00318     assert(rscore_index >= 0);
00319     if (relative_score_to_width[progress8][rscore_index] <= limit)
00320       result = std::min(result, relative_score_to_depth[progress8][rscore_index]);
00321   }
00322   return result;
00323 }
00324 
00325 #ifdef RATING_STAT2
00326 namespace osl
00327 {
00328   namespace 
00329   {
00330     CArray2d<CArray<stat::Average,8>,14,40> data; // selected/generated for each range
00331     CArray2d<CArray<double,8>,14,80> selected_all;
00332     void add_stat(int limit, int rating, bool added, int progress8) 
00333     {
00334       limit = std::min(limit, 999);
00335       limit -= 300;
00336       limit = std::max(limit, 0);
00337       rating = std::max(-999,rating);
00338       rating = std::min(999,rating);
00339       data[limit/50][(rating+1000)/50][progress8].add(added);
00340       if (added)
00341         selected_all[limit/50][(rating+1000)/25][progress8] += 1.0;
00342     }
00343     struct Reporter
00344     {
00345       ~Reporter()
00346       {
00347         std::cerr << "limit " << 0*50+300 << " - " << (data.size1()-1)*50+300 << "\n";
00348         for (int p=0; p<8; ++p) 
00349         {
00350           std::cerr << "progress8 " << p << "\n  ";
00351           for (size_t j=0; j<data.size1(); ++j) 
00352           {
00353             size_t i=0;
00354             for (; i<data.size2(); ++i)
00355               if (data[j][i][p].getAverage() > 0.05)
00356                 break;
00357             std::cerr << (boost::format("%+4d, ") % static_cast<int>(i)*50-1000);
00358           }
00359           std::cerr << "\n";
00360         }
00361         std::cerr << "limit " << 0*50+300 << " - " << (selected_all.size1()-1)*50+300 << "\n";
00362         CArray<double, 3> prob = {{ 0.01, 0.03, 0.05 }};
00363         for (size_t pp=0; pp<prob.size(); ++pp) {
00364           std::cerr << "prob " << prob[pp] << "\n";
00365           for (int p=0; p<8; ++p) 
00366           {
00367             std::cerr << "progress8 " << p << "\n  ";
00368             for (size_t j=0; j<selected_all.size1(); ++j) 
00369             {
00370               double sum = 0;
00371               for (size_t i=0; i<selected_all.size2(); ++i)
00372                 sum += selected_all[j][i][p];
00373               size_t i=0
00374               for (double so_far = 0; i<selected_all.size2(); ++i) {
00375                 so_far += selected_all[j][i][p];
00376                 if (so_far > prob[pp]*sum) 
00377                   break;
00378               }
00379               std::cerr << (boost::format("%+4d, ") % static_cast<int>(i)*25-1000);
00380             }
00381             std::cerr << "\n";
00382           }
00383         }
00384       }
00385     } _reporter;
00386   }
00387 }
00388 #endif
00389 
00390 void osl::rating::
00391 FeatureSet::generateLogProb(const NumEffectState& state, const RatingEnv& env,
00392                             int limit, MoveLogProbVector& out, bool in_pv_or_all) const
00393 {
00394   RatedMoveVector score;
00395   generateRating(state, env, limit, score, in_pv_or_all);
00396   if (score.empty())
00397     return;
00398 
00399   const int highest = score[0].rating();
00400   const int progress8 = env.progress.value()/2;
00401   for (size_t i=0; i<score.size(); ++i) {
00402     const int log_prob = make_prob(score[i].rating(), i, limit, highest, progress8, in_pv_or_all);
00403 #ifdef RATING_STAT2
00404     add_stat(limit, score[i].rating(), log_prob <= limit, progress8);
00405 #endif
00406     out.push_back(MoveLogProb(score[i].move(), log_prob));
00407   }
00408 }
00409 
00410 const int max_score = 999, min_score = 0;
00411 static const osl::CArray<int, 10> score_to_depth_takeback = {{
00412   223, 204, 208, 190, 159, 137, 124, 110, 100, 89
00413 }};
00414 static const osl::CArray<int, 10> score_to_depth_seeplus = {{
00415   356, 337, 296, 262, 230, 200, 171, 148, 132, 120,
00416 }};
00417 static const osl::CArray<int, 10> score_to_depth_kingescape = {{
00418   203, 201, 199, 188, 181, 169, 159, 147, 136, 122,
00419 }};
00420 
00421 int osl::rating::
00422 FeatureSet::logProbTakeBack(const NumEffectState& state, const RatingEnv& env, Move move) const
00423 {
00424   const bool in_check = state.inCheck();
00425   const int score = makeRate(state, in_check, env, move).rating();
00426   if (score >= 1000) {
00427     const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
00428     return score_to_depth[env.progress.value()/2][score_index];
00429   }
00430   return score_to_depth_takeback[std::max(min_score, std::min(max_score, score))/100];
00431 }
00432 int osl::rating::
00433 FeatureSet::logProbSeePlus(const NumEffectState& state, const RatingEnv& env,
00434                            Move move) const
00435 {
00436   const bool in_check = state.inCheck();
00437   const int score = makeRate(state, in_check, env, move).rating();
00438   if (score >= 1000) {
00439     const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
00440     return score_to_depth[env.progress.value()/2][score_index];
00441   }
00442   return score_to_depth_seeplus[std::max(min_score, std::min(max_score, score))/100];
00443 }
00444 int osl::rating::
00445 FeatureSet::logProbKingEscape(const NumEffectState& state, const RatingEnv& env,
00446                               Move move) const
00447 {
00448   const bool in_check = state.inCheck();
00449   const int score = makeRate(state, in_check, env, move).rating();
00450   if (score >= 1000) {
00451     const int score_index = std::min((score - sc_start)/sc_width, sc_length-1);
00452     return score_to_depth[env.progress.value()/2][score_index];
00453   }
00454   const int prob = score_to_depth_kingescape[std::max(min_score, std::min(max_score, score))/100];
00455   assert(prob > 0);
00456   return prob;
00457 }
00458 
00459 int osl::rating::
00460 FeatureSet::rating(const NumEffectState& state, 
00461                    const RatingEnv& env, Move move, size_t group_id) const
00462 {
00463   int found = groups[group_id].findMatch(state, move, env);
00464   if (found < 0) {
00465 #ifdef RATING_STAT
00466     const int progress8 = env.progress.value()/2;
00467     frequency[group_id][progress8].add(0);
00468     variance_all[group_id].add(0);
00469 #endif
00470     return 0;
00471   }
00472   found += ranges[group_id].first;
00473 #ifdef RATING_STAT
00474   const int progress8 = env.progress.value()/2;
00475   frequency[group_id][progress8].add(1);
00476   variance_match[group_id][progress8].add(weightslog10[found]);
00477   variance_all[group_id].add(weightslog10[found]);
00478 #endif
00479   return weightslog10[found];
00480 }
00481 
00482 const osl::rating::RatedMove osl::rating::
00483 FeatureSet::makeRate(const NumEffectState& state, bool in_check,
00484                      const RatingEnv& env, Move move) const
00485 {
00486   int sum = 0;
00487   for (size_t j=0; j<groups.size(); ++j) {
00488     if (! normal_groups[j])
00489       continue;
00490     if (in_check && ! effectiveInCheck(j))
00491       continue;
00492     sum += rating(state, env, move, j);
00493   }
00494   int capture = 0;
00495   if (capture_group >= 0)
00496     capture = rating(state, env, move, capture_group);
00497   int checkmate_if_capture = 0;
00498   if (checkmate_if_capture_group >= 0)
00499     checkmate_if_capture = rating(state, env, move, checkmate_if_capture_group);
00500   sum += checkmate_if_capture;
00501   int sendoff = 0;
00502   if (sendoff_group >= 0)
00503     sendoff = rating(state, env, move, sendoff_group);
00504   sum += sendoff;
00505 
00506   if (checkmate_if_capture > 0)
00507     capture = std::max(0, capture);
00508   else if (sendoff > 0 && capture < 0)
00509     capture /= 2;
00510   const int optimistic = sum + std::max(0, capture);
00511   sum += capture;
00512   
00513   return RatedMove(move, sum, optimistic);
00514 }
00515 
00516 
00517 // limit [0-800)
00518 #if 1
00519 // 1%
00520 static const osl::CArray2d<int,8,16> threshold = {{
00521   {
00522     0, 0, 0, 0, 0, 0,
00523     100, 100,  50,   0,   0, -75,-100,-150,-200,-200,
00524   },
00525   {
00526     0, 0, 0, 0, 0, 0,
00527     125, 125, 125,  25,  25, -50, -50,-100,-125,-225,
00528   },
00529   {
00530     0, 0, 0, 0, 0, 0,
00531     100,  75, 100,  25,   0, -25, -50,-100,-125,-175,
00532   },
00533   {
00534     0, 0, 0, 0, 0, 0,
00535      75,  50,  75,   0, -25, -25, -75,-100,-125,-200,
00536   },
00537   {
00538     0, 0, 0, 0, 0, 0,
00539     125, 125, 150,  50,  50,  50, -25,   0, -50,-200,
00540   },
00541   {
00542     0, 0, 0, 0, 0, 0,
00543     175, 200, 200,  75,  75,  75,   0,   0,-175,-300,
00544   },
00545   {
00546     0, 0, 0, 0, 0, 0,
00547     175, 175, 200,  50,  75,  75,  25,   0,-100,-250,
00548   },
00549   {
00550     0, 0, 0, 0, 0, 0,
00551     225, 200, 225,  75, 100,  75,  50,   0,   0,-250,
00552   },
00553 }};
00554 #endif
00555 #if 0
00556 static const osl::CArray2d<int,8,16> threshold = {{
00557   // 0, 50, 100, 150, 200, ...
00558   {
00559     0, 0, 0, 0, 0, 0,
00560     100,100,100,0,0,-100,-100,-200,-200,-200,
00561   },
00562   {
00563     0, 0, 0, 0, 0, 0,
00564     100,100,100,0,0,-100,-100,-100,-100,-200,
00565   },
00566   {
00567     0, 0, 0, 0, 0, 0,
00568     100,100,100,0,0,0,-100,-100,-100,-200
00569   },
00570   {
00571     0, 0, 0, 0, 0, 0,
00572     100,100,100,0,0,0,-100,-100,-100,-200
00573   },
00574   {
00575     0, 0, 0, 0, 0, 0,
00576     200,200,200,100,100,100,0,0,0,-100
00577   },
00578   {
00579     0, 0, 0, 0, 0, 0,
00580     300,300,300,100,100,100,100,0,-200,-300
00581   },
00582   {
00583     0, 0, 0, 0, 0, 0,
00584     300,300,300,100,100,100,100,0,0,-200
00585   },
00586   {
00587     0, 0, 0, 0, 0, 0,
00588     300,300,300,100,200,200,100,0,0,-200
00589   },
00590 }};
00591 #endif
00592 const osl::rating::RatedMove osl::rating::
00593 FeatureSet::makeRateWithCut(const NumEffectState& state, 
00594                             bool in_check,
00595                             const RatingEnv& env, 
00596                             int limit, Move move) const
00597 {
00598   if (limit >= 800)
00599     return makeRate(state, in_check, env, move);
00600 
00601   limit /= 50;
00602   int sum = 0;
00603   int capture = 0;
00604   int checkmate_if_capture = 0;
00605   const int progress8 = env.progress.value()/2;
00606   for (size_t j=0; j<groups.size(); ++j) {
00607     if (in_check && ! effectiveInCheck(j))
00608       continue;
00609     const int r = rating(state, env, move, j);
00610     sum += r;
00611     if ((int)j == capture_group) {
00612       capture = r;
00613     }
00614     else if ((int)j == checkmate_if_capture_group) {
00615       checkmate_if_capture = r;
00616       if (checkmate_if_capture > 0 && capture < 0) {
00617         sum -= capture;
00618         capture = 0;
00619       }
00620     }
00621     // cut?
00622     if (j % 8 == 7) {
00623       int sigma = statistics[j].sigma_after;
00624       if (sum + statistics[j].average_after + sigma < threshold[progress8][limit]) {
00625         return RatedMove(move, MinRating, MinRating);
00626       }
00627     }
00628   }
00629 
00630   const int optimistic = sum + std::max(0, capture);  
00631   return RatedMove(move, sum, optimistic);
00632 }
00633 
00634 const std::string osl::rating::
00635 FeatureSet::annotate(const NumEffectState& state, 
00636                      const RatingEnv& env, Move move) const
00637 {
00638   const bool in_check = state.inCheck();
00639   vector<std::pair<int, std::string> > values;
00640   for (size_t j=0; j<groups.size(); ++j) {
00641     if (in_check && ! effectiveInCheck(j))
00642       continue;
00643     int found = groups[j].findMatch(state, move, env);
00644     if (found < 0)
00645       continue;
00646     found += ranges[j].first;
00647     values.push_back(std::make_pair(weightslog10[found], groups[j].group_name));
00648   }
00649   std::sort(values.begin(), values.end());
00650   std::reverse(values.begin(), values.end());
00651   std::ostringstream ss;
00652   for (size_t i=0; i<values.size(); ++i) {
00653     if (i)
00654       ss << "  ";
00655     ss << values[i].second << " " << values[i].first;
00656   }
00657   return ss.str();
00658 }
00659 
00660 #ifndef MINIMAL
00661 void osl::rating::
00662 FeatureSet::showGroup(std::ostream& os, size_t group_id) const
00663 {
00664   os << std::setprecision(3);
00665   group(group_id).show(os, 12, range(group_id), weights);
00666 }
00667 
00668 void osl::rating::
00669 FeatureSet::save(const std::string& output_directory, size_t group_id) const
00670 {
00671   group(group_id).saveResult(output_directory, range(group_id), weights);
00672 }
00673 
00674 void osl::rating::
00675 FeatureSet::showStatistics(std::ostream& os) const
00676 {
00677   os << std::setprecision(3);
00678   for (size_t i=0; i<groups.size(); ++i) {
00679     os << groups[i].group_name << "\t";
00680     for (int p=0; p<8; ++p) {
00681       os << "  " << variance_match[i][p].getAverage() 
00682          << "  " << sqrt(variance_match[i][p].variance())
00683          << "  " << frequency[i][p].getAverage() << "  ";
00684     }
00685     os << "\t" << variance_all[i].getAverage() 
00686        << "\t" << sqrt(variance_all[i].variance())
00687        << "\n";
00688   }
00689 }
00690 #endif
00691 
00692 std::string osl::rating::FeatureSet::defaultDirectory()
00693 {
00694   return OslConfig::home()+"/data/rating";
00695 }
00696 
00697 /* ------------------------------------------------------------------------- */
00698 
00699 osl::rating::
00700 StandardFeatureSet::StandardFeatureSet(bool allow_load_failure)
00701 {
00702   add(new CaptureGroup());
00703   add(new SquareYGroup());
00704   add(new RelativeKingXGroup(true));
00705   add(new SquareXGroup());
00706   add(new TakeBackGroup());
00707   add(new RelativeKingYGroup(true));
00708   add(new FromEffectGroup());
00709   add(new PatternGroup(U));
00710   add(new RelativeKingXGroup(false));
00711   add(new PatternGroup(D));
00712 
00713   add(new PatternLongGroup(0));
00714   add(new CheckGroup());
00715   add(new BlockGroup()); 
00716   add(new PtypeAttackedGroup());
00717 
00718   add(new PatternGroup(U,U));
00719   add(new ImmediateAddSupportGroup()); // 300 cycles
00720   add(new PatternGroup(DR));
00721   add(new RelativeKingYGroup(false));
00722   add(new DefenseKing8Group());
00723   add(new PatternGroup(L));
00724   add(new PatternGroup(UL));
00725 
00726   add(new ToSupportedGroup());
00727 
00728   add(new PatternGroup(UR));
00729   add(new PatternBlockGroup(ROOK));
00730   add(new AttackKing8Group());
00731   add(new PatternGroup(R));
00732   add(new PatternGroup(DL));
00733 
00734   add(new PatternGroup(R,R));
00735   add(new PatternLongGroup(3));
00736   add(new PatternGroup(UUL));
00737   add(new PatternGroup(UUR));
00738   add(new PatternGroup(L,L));
00739 
00740   add(new PatternLongGroup(2));
00741   add(new OpenGroup());
00742   add(new PatternBlockGroup(LANCE));
00743   add(new ChaseGroup());
00744   add(new PatternLongGroup(1));
00745   add(new PatternLongGroup2(1));
00746   add(new PatternBlockGroup(BISHOP));
00747   add(new PatternGroup(UR,R));
00748   add(new PatternLongGroup2(0));
00749   add(new PatternGroup(UL,L));
00750 
00751   add(new ImmediateEscapeGroup());
00752   add(new PatternLongGroup2(3));
00753   add(new PatternLongGroup2(2));
00754   add(new KaranariGroup());
00755 
00756   add(new BigramAttackGroup(true, true));
00757   add(new BigramAttackGroup(false, true));
00758   add(new BigramAttackGroup(true, false));
00759   add(new BigramAttackGroup(false, false));
00760 
00761   add(new DropCapturedGroup());
00762   add(new ContinueCaptureGroup());
00763   add(new PawnAttackGroup());
00764   add(new ThreatmateGroup());
00765 
00766   add(new BadLanceGroup());
00767   add(new CheckmateIfCaptureGroup());
00768   add(new RookDefense());
00769   add(new SendOffGroup());
00770 
00771   add(new PinGroup());
00772   add(new KingEscapeGroup());
00773   add(new EscapePinGroup());
00774 
00775   addFinished();
00776   bool success = tryLoad(defaultDirectory());
00777   if (! allow_load_failure && ! success) {
00778     std::cerr << "error: unable to load rating from " << defaultDirectory();
00779     throw std::runtime_error("load failed " + OslConfig::home()+defaultDirectory());
00780   }
00781 }
00782 
00783 
00784 const osl::rating::StandardFeatureSet& osl::rating::
00785 StandardFeatureSet::instance()
00786 {
00787   static osl::rating::StandardFeatureSet common_instance;
00788   return common_instance;
00789 }
00790 
00791 bool osl::rating::StandardFeatureSet::healthCheck()
00792 {
00793   std::cerr << "loading " << defaultDirectory() << ' ';
00794   try {
00795     instance();
00796     std::cerr << "success\n";
00797   }
00798   catch (std::exception& e)
00799   {
00800     std::cerr << e.what() << "\n";
00801     return false;
00802   }
00803   catch (...) {
00804     std::cerr << "unknown exception\n";
00805     return false;
00806   }
00807   return true;
00808 }
00809 
00810 osl::rating::
00811 CaptureSet::CaptureSet(bool allow_load_failure)
00812 {
00813   add(new CaptureGroup());
00814   add(new ShadowEffectGroup());
00815 
00816   addFinished();
00817   bool success = tryLoad(defaultDirectory());
00818   if (! allow_load_failure && ! success) {
00819     std::cerr << "error: unable to load rating from " << defaultDirectory();
00820     throw std::runtime_error("load failed " + defaultDirectory());
00821   }
00822 }
00823 
00824 /* ------------------------------------------------------------------------- */
00825 // ;;; Local Variables:
00826 // ;;; mode:c++
00827 // ;;; c-basic-offset:2
00828 // ;;; coding:utf-8
00829 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines