bradleyTerry.cc
Go to the documentation of this file.
00001 /* bradleyTerry.cc
00002  */
00003 #include "osl/rating/bradleyTerry.h"
00004 #include "osl/rating/group.h"
00005 #include "osl/checkmate/immediateCheckmate.h"
00006 #include "osl/move_generator/legalMoves.h"
00007 #include "osl/record/kisen.h"
00008 #include "osl/container/moveVector.h"
00009 
00010 #include <boost/thread/thread.hpp>
00011 #include <iostream>
00012 #include <iomanip>
00013 
00014 #ifndef MINIMAL
00015 osl::rating::
00016 BradleyTerry::BradleyTerry(FeatureSet& f, const std::string& kisen_file, int kisen_start)
00017   : features(f), kisen_filename(kisen_file), kisen_start(kisen_start), num_cpus(1), num_records(200),
00018     verbose(1), fix_group(-1), min_rating(0)
00019 {
00020 }
00021 
00022 osl::rating::BradleyTerry::~BradleyTerry()
00023 {
00024 }
00025 
00026 bool osl::rating::
00027 BradleyTerry::addSquare(size_t g, const NumEffectState& state, 
00028                           const RatingEnv& env, Move selected,
00029                           valarray_t& wins, std::valarray<long double>& denominator) const
00030 {
00031   MoveVector moves;
00032   LegalMoves::generate(state, moves);
00033   if (! moves.isMember(selected))
00034     return false;                       // checkmate or illegal move  
00035   const range_t range = features.range(g);
00036 #ifdef SPEEDUP_TEST
00037   const bool in_check = EffectUtil::isKingInCheck(state.turn(), state);
00038   if (! in_check || features.effectiveInCheck(g))
00039 #endif
00040   {
00041     int found = features.group(g).findMatch(state, selected, env);
00042     if (found >= 0)
00043       ++wins[found+range.first];
00044   }
00045   valarray_t sum_c(0.0, range.second-range.first);
00046   long double sum_e = 0.0;
00047   for (size_t i=0; i<moves.size(); ++i) {
00048     Move m = moves[i];
00049     double product = 1.0;
00050     int count = 0;
00051     int match_id = -1;
00052     for (size_t j=0; j<features.groupSize(); ++j) {
00053 #ifdef SPEEDUP_TEST
00054       if (in_check && ! features.effectiveInCheck(j))
00055         continue;
00056 #endif
00057       int found = features.group(j).findMatch(state, m, env);
00058       if (found < 0)
00059         continue;
00060       found += features.range(j).first;
00061       product *= features.weight(found);
00062       ++count;
00063       if (j == g) {
00064         assert(range.first <= found && found < range.second);
00065         match_id = found;
00066       }
00067     }
00068     assert(count);
00069     sum_e += product;
00070     if (match_id >= 0)
00071       sum_c[match_id-range.first] += product / features.weight(match_id);
00072   }
00073   assert(sum_e > 0);
00074   for (int f=range.first; f<range.second; ++f)
00075     denominator[f] += sum_c[f-range.first]/sum_e;
00076   return true;
00077 }
00078 
00079 class osl::rating::
00080   BradleyTerry::Thread
00081 {
00082 public:
00083   const BradleyTerry *features;
00084   size_t target;
00085   size_t first, last;
00086   valarray_t *wins;
00087   std::valarray<long double> *denominator;
00088   size_t *skip;
00089   Thread(const BradleyTerry *a, size_t t, size_t f, size_t l, valarray_t *w, std::valarray<long double> *d,
00090          size_t *s)
00091     : features(a), target(t), first(f), last(l), wins(w), denominator(d), skip(s)
00092   {
00093   }
00094   void operator()()
00095   {
00096     *skip = features->accumulate(target, first, last, *wins, *denominator);
00097   }
00098 };
00099 
00100 size_t osl::rating::
00101 BradleyTerry::accumulate(size_t g, size_t first, size_t last, valarray_t& wins, std::valarray<long double>& denominator) const
00102 {
00103   assert(wins.size() == features.featureSize());
00104   KisenFile kisen_file(kisen_filename.c_str());
00105   KisenIpxFile ipx(KisenFile::ipxFileName(kisen_filename));
00106   size_t skip = 0;
00107   for (size_t i=first; i<last; i++) {
00108     if ((i % 4000) == 0)
00109       std::cerr << ".";
00110     if (ipx.getRating(i, BLACK) < min_rating 
00111         || ipx.getRating(i, WHITE) < min_rating) {
00112       ++skip;
00113       continue;
00114     }
00115     NumEffectState state(kisen_file.getInitialState());
00116     RatingEnv env;
00117     env.make(state);
00118     const vector<Move> moves=kisen_file.getMoves(i+kisen_start);
00119     for (size_t j=0; j<moves.size(); j++) {
00120       if (j<2)
00121         goto next;
00122       {
00123         const Player turn = state.turn();
00124         if (! state.inCheck()
00125             && ImmediateCheckmate::hasCheckmateMove(turn, state))
00126           break;
00127       }
00128       if (! addSquare(g, state, env, moves[j], wins, denominator))
00129         break;
00130     next:
00131       state.makeMove(moves[j]);
00132       env.update(state, moves[j]);
00133     }
00134   }
00135   return skip;
00136 }
00137 
00138 void osl::rating::
00139 BradleyTerry::update(size_t g)
00140 {
00141   std::valarray<valarray_t> wins(valarray_t(0.0, features.featureSize()), num_cpus);
00142   std::valarray<std::valarray<long double> > denominator(std::valarray<long double>(0.0, features.featureSize()), num_cpus);
00143   assert(wins.size() == num_cpus);
00144 
00145   KisenFile kisen_file(kisen_filename.c_str());
00146   if (num_records==0)
00147     num_records=kisen_file.size();
00148   if (num_cpus == 1) {
00149     accumulate(g, 0, num_records, wins[0], denominator[0]);
00150   }
00151   else {
00152     size_t cur = 0;
00153     size_t last = num_records, step = (last - cur)/num_cpus;
00154     boost::ptr_vector<boost::thread> threads;  
00155     std::valarray<size_t> skip((size_t)0, num_cpus);
00156     for (size_t i=0; i<num_cpus; ++i, cur += step) {
00157       size_t next = (i+1 == num_cpus) ? last : cur + step;
00158       threads.push_back(new boost::thread(Thread(this, g, cur, next, &wins[i], &denominator[i], &skip[i])));
00159     }
00160     for (size_t i=0; i<num_cpus; ++i) 
00161       threads[i].join();
00162     if (g == 0)
00163       std::cerr << "skip " << skip.sum() << " / " << num_records << "\n";
00164   }
00165   const range_t range = features.range(g);
00166   for (int f=range.first; f<range.second; ++f) {
00167     const int NPRIOR = 10; // assume NPRIOR wins, NPRIOR losses
00168     double sum_win = NPRIOR;
00169     long double sum_denom = (1.0 / (features.weight(f) + 1.0)) * 2 * NPRIOR;
00170     for (size_t i=0; i<num_cpus; ++i) {
00171       sum_win += wins[i][f];
00172       sum_denom += denominator[i][f];
00173     }
00174 #ifdef DEBUG
00175     std::cerr << "  " << std::setw(14) << features.feature(f).name() 
00176               << " " << features.weight(f) << " => " << sum_win/sum_denom
00177               << "  " << sum_win << " / " << sum_denom
00178               << "  " << 400*log10(sum_win/sum_denom) << "\n";
00179 #endif
00180     // update
00181     if (sum_denom)
00182       features.setWeight(f, sum_win/sum_denom);
00183     assert(! std::isinf(features.weight(f)));
00184     assert(! std::isnan(features.weight(f)));
00185   }
00186   
00187   features.showGroup(std::cerr, g);
00188 }
00189 
00190 void osl::rating::
00191 BradleyTerry::iterate()
00192 {
00193   for (int j=0; j<16; ++j) {
00194     std::cerr << "\nnew iteration " << j << "\n";
00195     for (size_t i=0; i<features.groupSize(); ++i) {
00196       update(i);
00197       features.save(output_directory, i); 
00198       if ((int)(i+1) == fix_group)
00199         break;
00200     }
00201   }
00202 }
00203 #endif
00204 /* ------------------------------------------------------------------------- */
00205 // ;;; Local Variables:
00206 // ;;; mode:c++
00207 // ;;; c-basic-offset:2
00208 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines