00001 #include "osl/category/standardMoveGenerator.h"
00002 #include "osl/category/categoryListUtil.h"
00003 #include "osl/category/categoryUtil.h"
00004 #include "osl/search/simpleHashRecord.h"
00005 #include "osl/stat/histogram.h"
00006 #include "osl/stat/average.h"
00007 #include "osl/container/moveStack.h"
00008 #include "osl/container/moveLogProbSet.h"
00009 #include "osl/eval/progressEval.h"
00010 #include "osl/state/numEffectState.h"
00011 #include "osl/moveLogProb.h"
00012 #include "osl/record/csaRecord.h"
00013 #include "osl/record/csaIOError.h"
00014 #include "osl/record/kanjiPrint.h"
00015 #include "osl/apply_move/applyMove.h"
00016 #include "osl/misc/perfmon.h"
00017
00018 #include <vector>
00019 #include <map>
00020 #include <string>
00021 #include <boost/format.hpp>
00022 #include <iostream>
00023 #include <iomanip>
00024 using namespace osl;
00025 using namespace osl::category;
00026
00032 void usage(const char *prog)
00033 {
00034 using namespace std;
00035 cerr << "Usage: " << prog << " [-va] [-l limit] [-O order-limit] [-f skip] csafiles\n"
00036 << "-v verbose output\n"
00037 << "-V very verbose output\n"
00038 << "-a analyze all legal moves\n"
00039 << endl;
00040 exit(1);
00041 }
00042
00043 int limit = 1200;
00044 size_t first_skip = 0;
00045 bool verbose = false;
00046 bool very_verbose = false;
00047 bool all_moves = false;
00048
00049 stat::Average moves, cycles, cycles_per_move, probs;
00050 stat::Histogram moves_histogram(2, 10);
00051
00052 struct CategoryStat
00053 {
00054 stat::Average cycles_per_move;
00055 stat::Average moves;
00056 };
00057 typedef std::map<const char *,CategoryStat> map_t;
00058 map_t category_table;
00059
00060 void test_file(const char *filename);
00061 void show_table(const map_t&);
00062
00063 int main(int argc, char **argv)
00064 {
00065 const char *program_name = argv[0];
00066 bool error_flag = false;
00067 extern char *optarg;
00068 extern int optind;
00069
00070 char c;
00071 while ((c = getopt(argc, argv, "l:f:Vvh")) != EOF)
00072 {
00073 switch(c)
00074 {
00075 case 'l': limit = atoi(optarg);
00076 break;
00077 case 'f': first_skip = atoi(optarg);
00078 break;
00079 case 'V': very_verbose = true;
00080
00081 case 'v': verbose = true;
00082 break;
00083 default: error_flag = true;
00084 }
00085 }
00086 argc -= optind;
00087 argv += optind;
00088
00089 if (error_flag || (argc < 1))
00090 usage(program_name);
00091
00092 eval::ProgressEval::setUp();
00093
00094 for (int i=0; i<argc; ++i)
00095 {
00096 if (i % 128 == 0)
00097 std::cerr << '.';
00098 test_file(argv[i]);
00099 }
00100
00101 std::cout << "\n"
00102 << "average probability " << probs.getAverage() << "\n"
00103 << "average moves/position " << moves.getAverage() << "\n";
00104 if (verbose) {
00105 moves_histogram.show(std::cout);
00106 }
00107 std::cout << "average cycles/position " << cycles.getAverage() << "\n"
00108 << "average cycles/position/move " << cycles_per_move.getAverage()
00109 << "\n";
00110 show_table(category_table);
00111 }
00112
00113
00114
00115 struct CategoryCount
00116 {
00117 Move the_move;
00118 size_t& counter;
00119 int& prob;
00120 const char *& last_category;
00121 size_t& last_category_generated;
00122 template <bool is_king_escape>
00123 bool operator()(const char *category_name, MoveLogProbVector& moves)
00124 {
00125 last_category = category_name;
00126 last_category_generated = moves.size();
00127 for (size_t i=0; i<moves.size(); ++i,++counter) {
00128 if (moves[i].getMove() == the_move) {
00129 prob = moves[i].getLogProb();
00130 return false;
00131 }
00132 }
00133 return true;
00134 }
00135 };
00136
00137
00138 size_t num_positions = 0;
00139 void test_position(Move next_move,
00140 const NumEffectState& state, const MoveStack& history)
00141 {
00142 eval::ProgressEval eval(state);
00143 SimpleHashRecord record;
00144 const category::CategoryEnv env(&state, limit, &history,
00145 eval.progress32(), &record);
00146 size_t count=0;
00147 int prob = limit;
00148 const char *last_category = 0;
00149 size_t last_category_generated = 0;
00150 CategoryCount counter
00151 = { next_move, count, prob, last_category, last_category_generated };
00152 misc::PerfMon clock;
00153 CategoryListUtil::forEachCategory(StandardMoveGenerator(), env, counter);
00154 const size_t consumed = clock.stop();
00155 if (count) {
00156 moves.add(count);
00157 moves_histogram.add(count);
00158 cycles.add(consumed);
00159 cycles_per_move.add(consumed/count);
00160 probs.add(prob);
00161 assert(last_category);
00162 CategoryStat& stat = category_table[last_category];
00163 stat.cycles_per_move.add(consumed/count);
00164 stat.moves.add(last_category_generated);
00165 ++num_positions;
00166 }
00167 }
00168
00169 void test_file(const char *filename)
00170 {
00171 Record rec;
00172 try {
00173 rec = CsaFile(filename).getRecord();
00174 }
00175 catch (CsaIOError& e) {
00176 std::cerr << "skip " << filename <<"\n";
00177 std::cerr << e.what() << "\n";
00178 return;
00179 }
00180 catch (...) {
00181 throw;
00182 }
00183
00184 NumEffectState state(rec.getInitialState());
00185 const osl::stl::vector<osl::Move> moves=rec.getMoves();
00186
00187 MoveStack history;
00188
00189 for (size_t i=0; i<moves.size(); ++i) {
00190 const Move move = moves[i];
00191 assert(state.isValidMove(move));
00193 if (i >= first_skip) {
00194 test_position(moves[i], state, history);
00195 }
00196 ApplyMoveOfTurn::doMove(state, move);
00197 history.push(move);
00198 }
00199 }
00200
00201
00202
00203 struct Order
00204 {
00205 const std::string name;
00206 template <class Head, class Tail>
00207 int find(CategoryList<Head,Tail>, int cur)
00208 {
00209 if (Head::getName() == this->name)
00210 return cur;
00211 return find(Tail(), cur+1);
00212 }
00213 template <class Head>
00214 int find (CategoryList<Head,NullCategory>, int cur)
00215 {
00216 assert(Head::getName() == this->name);
00217 return cur;
00218 }
00219 static int order(const char *name)
00220 {
00221 Order work = { name };
00222 return work.find(StandardMoveGenerator(), 0);
00223 }
00224 };
00225
00226 void show_table(const map_t& table)
00227 {
00228 typedef std::map<int, std::pair<const char*, CategoryStat> > sorter_t;
00229 sorter_t sorter;
00230 for (map_t::const_iterator p=table.begin(); p != table.end(); ++p) {
00231 const size_t order = Order::order(p->first);
00232 sorter[order] = *p;
00233 }
00234 std::cout <<(boost::format("%22s %12s %9s %9s\n")
00235 % "category caused cut"
00236 % "cycles/move"
00237 % "position%" % "#moves");
00238 for (sorter_t::const_iterator p=sorter.begin(); p!=sorter.end(); ++p) {
00239 const CategoryStat& stat = p->second.second;
00240 std::cout << (boost::format("%22s % 12.2f % 9.2f % 9.2f\n")
00241 % p->second.first
00242 % stat.cycles_per_move.getAverage()
00243 % (stat.cycles_per_move.numElements()*100.0/num_positions)
00244 % stat.moves.getAverage());
00245 }
00246 }
00247
00248
00249
00250
00251
00252