featureSet.cc
Go to the documentation of this file.
00001 /* featureSet.cc
00002  */
00003 #include "osl/move_probability/featureSet.h"
00004 #include "osl/move_probability/feature.h"
00005 #include "osl/move_generator/legalMoves.h"
00006 #include "osl/container/moveVector.h"
00007 #include "osl/record/csa.h"
00008 #include "osl/misc/binaryIO.h"
00009 #include "osl/oslConfig.h"
00010 #include <boost/accumulators/accumulators.hpp>
00011 #include <boost/accumulators/statistics/stats.hpp>
00012 #include <boost/accumulators/statistics/mean.hpp>
00013 #include <boost/accumulators/statistics/min.hpp>
00014 #include <boost/accumulators/statistics/max.hpp>
00015 #include <boost/foreach.hpp>
00016 #include <boost/format.hpp>
00017 #include <fstream>
00018 #include <iomanip>
00019 #include <iostream>
00020 #include <cstdio>
00021 
00022 osl::move_probability::
00023 FeatureSet::FeatureSet()
00024 {
00025 }
00026 
00027 osl::move_probability::
00028 FeatureSet::~FeatureSet()
00029 {
00030 }
00031 
00032 void osl::move_probability::
00033 FeatureSet::pushBack(Feature *f, bool light)
00034 {
00035   features.push_back(f);
00036   if (light)
00037     light_features.push_back(features.size()-1);
00038 }
00039 
00040 void osl::move_probability::
00041 FeatureSet::addFinished()
00042 {
00043   offsets.resize(features.size()+1);
00044   offsets[0] = 0;
00045   for (size_t i=0; i<features.size(); ++i)
00046     offsets[i+1] = offsets[i] + features[i].dimension();
00047 }
00048 
00049 double osl::move_probability::FeatureSet::
00050 matchExp(const StateInfo& state, Move move, const double * weights) const
00051 {
00052   MoveInfo info(state, move);
00053   assert(offsets.size() == features.size()+1);
00054   double sum = 0.0;
00055   for (size_t i=0; i<features.size(); ++i) {
00056     sum += features[i].match(state, info, offsets[i], weights);
00057   }
00058   return exp(sum);
00059 }
00060 
00061 double osl::move_probability::FeatureSet::
00062 matchLight(const StateInfo& state, Move move, const double * weights) const
00063 {
00064   MoveInfo info(state, move);
00065   assert(offsets.size() == features.size()+1);
00066   double sum = 0.0;
00067   BOOST_FOREACH(size_t i, light_features) {
00068     sum += features[i].match(state, info, offsets[i], weights);
00069   }
00070   return sum;
00071 }
00072 
00073 
00074 void osl::move_probability::FeatureSet::
00075 analyze(const StateInfo& state, Move move, const double * weights) const
00076 {
00077   MoveInfo info(state, move);
00078   std::cerr << record::csa::show(move) << "\n";
00079   vector<std::pair<double, std::string> > out;
00080   for (size_t i=0; i<features.size(); ++i) {
00081     double s = features[i].match(state, info, offsets[i], weights);
00082     if (s)
00083       out.push_back(make_pair(s, features[i].name()));
00084   }
00085   std::sort(out.begin(), out.end());
00086   std::reverse(out.begin(), out.end());
00087   for (size_t i=0; i<out.size(); ++i) {
00088     std::cerr << boost::format("%16s %6.2f ") % out[i].second % out[i].first;
00089     if (i % 3 == 2)
00090       std::cerr << "\n";
00091   }
00092   if (out.size() % 3 != 0)
00093     std::cerr << "\n";
00094 }
00095 
00096 double osl::move_probability::FeatureSet::
00097 generateRating(const StateInfo& state, WeightedMoveVector& out,
00098                const double * weights) const
00099 {
00100   assert(! state.dirty);
00101   MoveVector moves;
00102   LegalMoves::generate(*state.state, moves);
00103   double sum = 0.0;
00104   FixedCapacityVector<Move,128> unpromote_moves;
00105   BOOST_FOREACH(Move move, moves) {
00106     double score = matchExp(state, move, weights);
00107     out.push_back(WeightedMove(score, move));
00108     sum += score;
00109   }
00110   return sum;
00111 }
00112 
00113 void osl::move_probability::FeatureSet::
00114 ratingToLogProb(const WeightedMoveVector& rating,
00115                 double sum, MoveLogProbVector& out)
00116 {
00117   static const double scale = 100.0 / log(0.5);
00118   BOOST_FOREACH(WeightedMove move, rating) {
00119     double p = move.first/sum;
00120     if (std::isnan(p) || p <= 1.0/(1<<12)) 
00121       p = 1.0/(1<<12);
00122     const int logp = std::max(50, static_cast<int>(log(p)*scale));
00123     out.push_back(MoveLogProb(move.second, logp));
00124   }
00125   out.sortByProbability();
00126 }
00127 
00128 void osl::move_probability::FeatureSet::
00129 generateLogProb(const StateInfo& state, MoveLogProbVector& out,
00130                 const double * weights) const
00131 {
00132   WeightedMoveVector moves;
00133   double sum = generateRating(state, moves, weights);
00134   ratingToLogProb(moves, sum, out);
00135 }
00136 
00137 bool osl::move_probability::FeatureSet::
00138 load(const char *base_filename, double * weights) const
00139 {
00140   std::string filename = std::string(base_filename) + ".txt";
00141   std::fill(weights, weights+dimension(), 0.0);
00142   std::ifstream is(filename.c_str());
00143   for (int i=0; i<dimension(); ++i) {
00144     is >> weights[i];
00145     if (! is) {
00146       std::cerr << "load failed at " << i << " in " << dimension() << "\n";
00147       break;
00148     }
00149   }
00150   return is;
00151 }
00152 
00153 bool osl::move_probability::FeatureSet::
00154 load_binary(const char *base_filename, double * weights) const
00155 {
00156   std::string filename = std::string(base_filename) + ".bin";
00157   std::fill(weights, weights+dimension(), 0.0);
00158   std::ifstream is(filename.c_str());
00159   misc::BinaryElementReader<double> reader(is);
00160   for (int i=0; i<dimension(); ++i) {
00161     if (! reader.hasNext()) {
00162       std::cerr << "load failed at " << i << " in " << dimension() << "\n";
00163       return false;
00164     }
00165     double value = reader.read();
00166     weights[i] = value;
00167   }
00168   return true;
00169 }
00170 
00171 void osl::move_probability::FeatureSet::
00172 showSummary(const double * weights) const
00173 {
00174   for (size_t i=0; i<features.size(); ++i) {
00175     const Feature& f = features[i];
00176 #if (__GNUC_MINOR__ < 5)
00177     using namespace boost::accumulators;
00178     accumulator_set<double, stats<tag::mean, tag::min, tag::max> > acc;
00179 #endif
00180     int zero = 0;
00181     for (int j=offsets[i]; j<offsets[i+1]; ++j)
00182       if (weights[j]) {
00183 #if (__GNUC_MINOR__ < 5)
00184         acc(weights[j]);
00185 #endif
00186       }
00187       else 
00188         ++zero;
00189     std::cerr << std::setw(16) << f.name() 
00190               << " dim " << std::setw(5) << f.dimension() - zero
00191               << "/" << std::setw(5) << f.dimension()
00192 #if (__GNUC_MINOR__ < 5)
00193               << " min " << std::setw(6) << min(acc)
00194               << " max " << std::setw(6) << max(acc)
00195               << " mean " << std::setw(6) << mean(acc)
00196 #endif
00197               << "\n";
00198   }
00199 }
00200 
00201 
00202 
00203 boost::scoped_array<double> osl::move_probability::
00204 StandardFeatureSet::weights;
00205 boost::scoped_array<double> osl::move_probability::
00206 StandardFeatureSet::tactical_weights;
00207 
00208 osl::move_probability::StandardFeatureSet::
00209 StandardFeatureSet()
00210 {
00211   pushBack(new TakeBackFeature, 1);
00212   pushBack(new CheckFeature, 1);
00213   pushBack(new SeeFeature, 1);
00214   pushBack(new ContinueCapture, 1);
00215   pushBack(new DropCaptured);
00216   pushBack(new SquareY, 1);
00217   pushBack(new SquareX, 1);
00218   pushBack(new KingRelativeY, 1);
00219   pushBack(new KingRelativeX, 1);
00220   pushBack(new FromEffect, 1);
00221   pushBack(new ToEffect, 1);
00222   pushBack(new FromEffectLong, 1);
00223   pushBack(new ToEffectLong, 1);
00224   pushBack(new Pattern(0,-1));  // U
00225   pushBack(new Pattern(1,-1));  // UL
00226   pushBack(new Pattern(1,0));   // L
00227   pushBack(new Pattern(0,1));   // D
00228   pushBack(new Pattern(1,1));   // DL
00229   pushBack(new Pattern(1,-2));  // UUL
00230   pushBack(new Pattern(0,-2));  // UU
00231   pushBack(new Pattern(0,2));   // DD
00232   pushBack(new Pattern(2,0));   // LL
00233   pushBack(new Pattern(1,2));   // DDL
00234   pushBack(new MoveFromOpposingSliders);
00235   pushBack(new AttackToOpposingSliders);
00236   pushBack(new PawnAttack);
00237   pushBack(new CapturePtype, 1);
00238   pushBack(new BlockLong);
00239   pushBack(new BlockLongFrom);
00240   pushBack(new LanceAttack);
00241   pushBack(new BishopAttack);
00242   pushBack(new RookAttack);
00243   pushBack(new BreakThreatmate);
00244   pushBack(new SendOff);
00245   pushBack(new CheckmateIfCapture);
00246   pushBack(new OpposingPawn);
00247   pushBack(new DropAfterOpposingPawn);
00248   pushBack(new LongRecapture);
00249   pushBack(new SacrificeAttack);
00250   pushBack(new AddEffectLong);
00251   pushBack(new King5x5Ptype);
00252   pushBack(new KingBlockade);
00253   pushBack(new CoverFork);
00254   pushBack(new ThreatmateByCapture);
00255   pushBack(new LureDefender);
00256   pushBack(new CoverPawn);
00257   pushBack(new PromotionBySacrifice);
00258   pushBack(new EscapeThreatened);
00259   pushBack(new BookMove);
00260   addFinished();
00261 }
00262 
00263 osl::move_probability::StandardFeatureSet::
00264 ~StandardFeatureSet()
00265 {
00266 }
00267 
00268 const osl::move_probability::StandardFeatureSet& 
00269 osl::move_probability::StandardFeatureSet::
00270 instance()
00271 {
00272   static StandardFeatureSet the_instance;
00273   the_instance.setUp();
00274   return the_instance;
00275 }
00276 
00277 bool osl::move_probability::StandardFeatureSet::
00278 setUp()
00279 {
00280   static bool initialized = false;
00281   if (initialized)
00282     return true;
00283   initialized = true;
00284   weights.reset(new double[dimension()]);
00285   std::string filename = OslConfig::home();
00286   filename += "/data/move-order";
00287   const bool success = load_binary(filename.c_str(), &weights[0]);
00288 
00289   filename = OslConfig::home();
00290   filename += "/data/move-tactical.txt";
00291   const int tactical_dimension = 8*4;
00292   tactical_weights.reset(new double[tactical_dimension]);
00293   std::ifstream is(filename.c_str());
00294   for (int i=0; i<tactical_dimension; ++i)
00295     is >> tactical_weights[i];
00296   return success && is;
00297 }
00298 
00299 void osl::move_probability::StandardFeatureSet::
00300 generateLogProb(const StateInfo& state, MoveLogProbVector& out) const
00301 {
00302   FeatureSet::generateLogProb(state, out, &weights[0]);
00303 }
00304 
00305 void osl::move_probability::StandardFeatureSet::
00306 generateLogProb2(const StateInfo& state, MoveLogProbVector& out) const
00307 {
00308   WeightedMoveVector moves;
00309   double sum = FeatureSet::generateRating(state, moves, &weights[0]);
00310   double elapsed = 0.0, welapsed = 0.0, last_p = 1.0;
00311   std::sort(moves.begin(), moves.end());
00312   for (int i=moves.size()-1; i>=0; --i) {
00313     WeightedMove move = moves[i];
00314     static const double scale = 100.0 / log(0.5);
00315     if (i+1<(int)moves.size())
00316       welapsed = std::max(welapsed, std::min(moves[i+1].first,move.first*4));
00317     double p = move.first/(sum-elapsed+welapsed);
00318     if (std::isnan(p) || p <= 1.0/(1<<12)) 
00319       p = 1.0/(1<<12);
00320     else
00321       p = std::min(last_p, p);
00322     int logp = std::max(50, static_cast<int>(log(p)*scale));
00323     if (moves.size() - i <= 8)
00324       logp = std::min(logp, 300);
00325     else if (moves.size() - i <= 16)
00326       logp = std::min(logp, 500);
00327     out.push_back(MoveLogProb(move.second, logp));
00328     elapsed += move.first;
00329     welapsed = (welapsed+move.first)*(moves.size()-i)/moves.size();
00330   }
00331 }
00332 
00333 void osl::move_probability::StandardFeatureSet::
00334 generateLogProb(const StateInfo& state, int /*limit*/, MoveLogProbVector& out, bool /*in_pv*/) const
00335 {
00336   generateLogProb2(state, out);
00337 }
00338 
00339 double osl::move_probability::StandardFeatureSet::
00340 matchLight(const StateInfo& state, Move move) const
00341 {
00342   return FeatureSet::matchLight(state, move, &weights[0]);
00343 }
00344 
00345 int osl::move_probability::StandardFeatureSet::
00346 logProbTakeBack(const StateInfo& state, Move target) const
00347 {
00348   const int progress8 = state.progress8();
00349   const double sum = matchLight(state, target);
00350   return tacticalLogProb(progress8*4 + 0, sum);
00351 }
00352 
00353 int osl::move_probability::StandardFeatureSet::
00354 logProbSeePlus(const StateInfo& state, Move target) const
00355 {
00356   const int progress8 = state.progress8();
00357   const double sum = matchLight(state, target);
00358   return tacticalLogProb(progress8*4 + 2, sum);
00359 }
00360 
00361 int osl::move_probability::StandardFeatureSet::
00362 tacticalLogProb(int offset, double sum) const
00363 {
00364   static const double scale = 100.0 / log(0.5);
00365   double x = tactical_weights[offset] * sum + tactical_weights[offset+1];
00366   double p = 1/(1.0+exp(-x));
00367   return std::max(50, static_cast<int>(log(p)*scale));
00368 }
00369 
00370 
00371 
00372 
00373 // ;;; Local Variables:
00374 // ;;; mode:c++
00375 // ;;; c-basic-offset:2
00376 // ;;; End:
00377 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines