My Project
featureSet_.cc
Go to the documentation of this file.
1/* featureSet.cc
2 */
5#include "osl/container.h"
6#include "osl/csa.h"
7#include "osl/bits/binaryIO.h"
8#include "osl/oslConfig.h"
9#include <boost/accumulators/accumulators.hpp>
10#include <boost/accumulators/statistics/stats.hpp>
11#include <boost/accumulators/statistics/mean.hpp>
12#include <boost/accumulators/statistics/min.hpp>
13#include <boost/accumulators/statistics/max.hpp>
14#include <boost/format.hpp>
15#include <mutex>
16#include <fstream>
17#include <iomanip>
18#include <iostream>
19#include <cstdio>
20#include <cmath>
21
26
31
33FeatureSet::pushBack(Feature *f, bool light)
34{
35 features.push_back(f);
36 if (light)
37 light_features.push_back(features.size()-1);
38}
39
42{
43 offsets.resize(features.size()+1);
44 offsets[0] = 0;
45 for (size_t i=0; i<features.size(); ++i)
46 offsets[i+1] = offsets[i] + features[i].dimension();
47}
48
50matchNoExp(const StateInfo& state, Move move, const double * weights) const
51{
52 MoveInfo info(state, move);
53 assert(offsets.size() == features.size()+1);
54 double sum = 0.0;
55 for (size_t i=0; i<features.size(); ++i) {
56 sum += features[i].match(state, info, offsets[i], weights);
57 }
58 return sum;
59}
60
62matchExp(const StateInfo& state, Move move, const double * weights) const
63{
64 return exp(matchNoExp(state, move, weights));
65}
66
68matchLight(const StateInfo& state, Move move, const double * weights) const
69{
70 MoveInfo info(state, move);
71 assert(offsets.size() == features.size()+1);
72 double sum = 0.0;
73 for (size_t i: light_features) {
74 sum += features[i].match(state, info, offsets[i], weights);
75 }
76 return sum;
77}
78
79
81analyze(const StateInfo& state, Move move, const double * weights) const
82{
83 MoveInfo info(state, move);
84 std::cerr << csa::show(move) << "\n";
85 std::vector<std::pair<double, std::string> > out;
86 for (size_t i=0; i<features.size(); ++i) {
87 double s = features[i].match(state, info, offsets[i], weights);
88 if (s)
89 out.push_back(make_pair(s, features[i].name()));
90 }
91 std::sort(out.begin(), out.end());
92 std::reverse(out.begin(), out.end());
93 for (size_t i=0; i<out.size(); ++i) {
94 std::cerr << boost::format("%16s %6.2f ") % out[i].second % out[i].first;
95 if (i % 3 == 2)
96 std::cerr << "\n";
97 }
98 if (out.size() % 3 != 0)
99 std::cerr << "\n";
100}
101
104 const double * weights) const
105{
106 assert(! state.dirty);
107 MoveVector moves;
108 state.state->generateLegal(moves);
109 double sum = 0.0;
110 FixedCapacityVector<Move,128> unpromote_moves;
111 for (Move move: moves) {
112 double score = matchExp(state, move, weights);
113 out.push_back(WeightedMove(score, move));
114 sum += score;
115 }
116 return sum;
117}
118
121 double sum, MoveLogProbVector& out)
122{
123 static const double scale = 100.0 / log(0.5);
124 for (WeightedMove move: rating) {
125 double p = move.first/sum;
126 if (std::isnan(p) || p <= 1.0/(1<<12))
127 p = 1.0/(1<<12);
128 const int logp = std::max(50, static_cast<int>(log(p)*scale));
129 out.push_back(MoveLogProb(move.second, logp));
130 }
131 out.sortByProbability();
132}
133
136 const double * weights) const
137{
138 WeightedMoveVector moves;
139 double sum = generateRating(state, moves, weights);
140 ratingToLogProb(moves, sum, out);
141}
142
144load(const char *base_filename, double * weights) const
145{
146 std::string filename = std::string(base_filename) + ".txt";
147 std::fill(weights, weights+dimension(), 0.0);
148 std::ifstream is(filename.c_str());
149 for (int i=0; i<dimension(); ++i) {
150 is >> weights[i];
151 if (! is) {
152 std::cerr << "load failed at " << i << " in " << dimension()
153 << " file " << filename << "\n";
154 break;
155 }
156 }
157 return static_cast<bool>(is);
158}
159
161load_binary(const char *base_filename, double * weights) const
162{
163 std::string filename = std::string(base_filename) + ".bin";
164 std::fill(weights, weights+dimension(), 0.0);
165 std::ifstream is(filename.c_str(), std::ios_base::binary);
167 for (int i=0; i<dimension(); ++i) {
168 if (! reader.hasNext()) {
169 std::cerr << "load failed at " << i << " in " << dimension()
170 << " file " << filename << "\n";
171 return false;
172 }
173 double value = reader.read();
174 weights[i] = value;
175 }
176 return true;
177}
178
180showSummary(const double * weights) const
181{
182 for (size_t i=0; i<features.size(); ++i) {
183 const Feature& f = features[i];
184#if (__GNUC_MINOR__ < 5)
185 using namespace boost::accumulators;
186 accumulator_set<double, stats<tag::mean, tag::min, tag::max> > acc;
187#endif
188 int zero = 0;
189 for (int j=offsets[i]; j<offsets[i+1]; ++j)
190 if (weights[j]) {
191#if (__GNUC_MINOR__ < 5)
192 acc(weights[j]);
193#endif
194 }
195 else
196 ++zero;
197 std::cerr << std::setw(16) << f.name()
198 << " dim " << std::setw(5) << f.dimension() - zero
199 << "/" << std::setw(5) << f.dimension()
200#if (__GNUC_MINOR__ < 5)
201 << " min " << std::setw(6) << min(acc)
202 << " max " << std::setw(6) << max(acc)
203 << " mean " << std::setw(6) << mean(acc)
204#endif
205 << "\n";
206 }
207}
208
209
210
211boost::scoped_array<double> osl::move_probability::
213boost::scoped_array<double> osl::move_probability::
215
217StandardFeatureSet() : initialized(false)
218{
220 pushBack(new CheckFeature, 1);
221 pushBack(new SeeFeature, 1);
224 pushBack(new SquareY, 1);
225 pushBack(new SquareX, 1);
226 pushBack(new KingRelativeY, 1);
227 pushBack(new KingRelativeX, 1);
228 pushBack(new FromEffect, 1);
229 pushBack(new ToEffect, 1);
230 pushBack(new FromEffectLong, 1);
231 pushBack(new ToEffectLong, 1);
232 pushBack(new Pattern(0,-1)); // U
233 pushBack(new Pattern(1,-1)); // UL
234 pushBack(new Pattern(1,0)); // L
235 pushBack(new Pattern(0,1)); // D
236 pushBack(new Pattern(1,1)); // DL
237 pushBack(new Pattern(1,-2)); // UUL
238 pushBack(new Pattern(0,-2)); // UU
239 pushBack(new Pattern(0,2)); // DD
240 pushBack(new Pattern(2,0)); // LL
241 pushBack(new Pattern(1,2)); // DDL
244 pushBack(new PawnAttack);
245 pushBack(new CapturePtype, 1);
246 pushBack(new BlockLong);
250 pushBack(new RookAttack);
252 pushBack(new SendOff);
261 pushBack(new CoverFork);
264 pushBack(new CoverPawn);
267 pushBack(new BookMove);
268 addFinished();
269}
270
275
278instance(bool verbose)
279{
280 static StandardFeatureSet the_instance;
281 the_instance.setUp(verbose);
282 return the_instance;
283}
284
287{
288 return instance(true).ok();
289}
290
291namespace osl
292{
293 namespace move_probability
294 {
296 }
297}
299setUp(bool verbose)
300{
301 std::lock_guard<std::mutex> lk(standardfeatureset_lock);
302 static bool initialized = false;
303 if (initialized)
304 return true;
305 initialized = true;
306 weights.reset(new double[dimension()]);
307 std::string filename = OslConfig::home();
308 filename += "/data/move-order";
309 if (verbose)
310 std::cerr << "loading " << filename << ".bin ";
311 const bool success = load_binary(filename.c_str(), &weights[0]);
312 if (verbose)
313 std::cerr << (success ? "success" : "failed\a") << "\n";
314
315 filename = OslConfig::home();
316 filename += "/data/move-tactical.txt";
317 const int tactical_dimension = 8*4;
318 tactical_weights.reset(new double[tactical_dimension]);
319 if (verbose)
320 std::cerr << "loading " << filename << " ";
321 std::ifstream is(filename.c_str());
322 for (int i=0; i<tactical_dimension; ++i)
323 is >> tactical_weights[i];
324 if (verbose)
325 std::cerr << (is ? "success" : "failed\a") << "\n";
326 this->initialized = success && is;
327 return this->initialized;
328}
329
331generateLogProb(const StateInfo& state, MoveLogProbVector& out) const
332{
333 FeatureSet::generateLogProb(state, out, &weights[0]);
334}
335
337generateLogProb2(const StateInfo& state, MoveLogProbVector& out) const
338{
339 WeightedMoveVector moves;
340 double sum = FeatureSet::generateRating(state, moves, &weights[0]);
341 double elapsed = 0.0, welapsed = 0.0, last_p = 1.0;
342 std::sort(moves.begin(), moves.end());
343 for (int i=moves.size()-1; i>=0; --i) {
344 WeightedMove move = moves[i];
345 static const double scale = 100.0 / log(0.5);
346 if (i+1<(int)moves.size())
347 welapsed = std::max(welapsed, std::min(moves[i+1].first,move.first*4));
348 double p = move.first/(sum-elapsed+welapsed);
349 if (std::isnan(p) || p <= 1.0/(1<<12))
350 p = 1.0/(1<<12);
351 else
352 p = std::min(last_p, p);
353 int logp = std::max(50, static_cast<int>(log(p)*scale));
354 if (moves.size() - i <= 8)
355 logp = std::min(logp, 300);
356 else if (moves.size() - i <= 16)
357 logp = std::min(logp, 500);
358 out.push_back(MoveLogProb(move.second, logp));
359 elapsed += move.first;
360 welapsed = (welapsed+move.first)*(moves.size()-i)/moves.size();
361 }
362}
363
365generateLogProb(const StateInfo& state, int /*limit*/, MoveLogProbVector& out, bool /*in_pv*/) const
366{
367 generateLogProb2(state, out);
368}
369
371matchLight(const StateInfo& state, Move move) const
372{
373 return FeatureSet::matchLight(state, move, &weights[0]);
374}
375
377matchExp(const StateInfo& state, Move move) const
378{
379 return FeatureSet::matchExp(state, move, &weights[0]);
380}
381
383matchNoExp(const StateInfo& state, Move move) const
384{
385 return FeatureSet::matchNoExp(state, move, &weights[0]);
386}
387
389logProbTakeBack(const StateInfo& state, Move target) const
390{
391 const int progress8 = state.progress8();
392 const double sum = matchLight(state, target);
393 return tacticalLogProb(progress8*4 + 0, sum);
394}
395
397logProbSeePlus(const StateInfo& state, Move target) const
398{
399 const int progress8 = state.progress8();
400 const double sum = matchLight(state, target);
401 return tacticalLogProb(progress8*4 + 2, sum);
402}
403
405tacticalLogProb(int offset, double sum) const
406{
407 static const double scale = 100.0 / log(0.5);
408 double x = tactical_weights[offset] * sum + tactical_weights[offset+1];
409 double p = 1/(1.0+exp(-x));
410 return std::max(50, static_cast<int>(log(p)*scale));
411}
412
413
414
415
416// ;;; Local Variables:
417// ;;; mode:c++
418// ;;; c-basic-offset:2
419// ;;; End:
420
size_t size() const
Definition container.h:243
void push_back(const T &e)
Definition container.h:204
圧縮していない moveの表現 .
void generateLegal(MoveVector &) const
全ての合法手を生成する.
void push_back(Move move, int prob)
void sortByProbability()
確率が高い順にsort
double generateRating(const StateInfo &state, WeightedMoveVector &out, const double *weights) const
double matchExp(const StateInfo &, Move, const double *weights) const
double matchNoExp(const StateInfo &, Move, const double *weights) const
void generateLogProb(const StateInfo &state, MoveLogProbVector &out, const double *weights) const
bool load_binary(const char *base_filename, double *weights) const
double matchLight(const StateInfo &, Move, const double *weights) const
void analyze(const StateInfo &state, Move move, const double *weights) const
bool load(const char *base_filename, double *weights) const
void showSummary(const double *weights) const
static void ratingToLogProb(const WeightedMoveVector &rating, double sum, MoveLogProbVector &out)
void pushBack(Feature *, bool light=false)
static boost::scoped_array< double > tactical_weights
void generateLogProb(const StateInfo &state, MoveLogProbVector &out) const
static boost::scoped_array< double > weights
int logProbTakeBack(const StateInfo &state, Move target) const
void generateLogProb2(const StateInfo &state, MoveLogProbVector &out) const
int logProbSeePlus(const StateInfo &state, Move target) const
static const StandardFeatureSet & instance(bool verbose=false)
double matchLight(const StateInfo &, Move) const
double matchExp(const StateInfo &, Move) const
int tacticalLogProb(int offset, double sum) const
double matchNoExp(const StateInfo &, Move) const
const std::string show(Move)
Definition csa.cc:133
std::mutex standardfeatureset_lock
std::pair< double, Move > WeightedMove
static const std::string & home(const std::string &initialize_if_first_invocation="")
compile時に指定されたディレクトリを返す.
Definition oslConfig.cc:239
const NumEffectState * state
Definition stateInfo.h:22