焼きなまし法ライブラリ2
以前公開していた焼きなましライブラリが古くなったので、新しく公開します。
そして、以前の記事を編集しようとしたところ、誤って削除してしまいました。もとには戻せないようです・・・。
typedef long long ll; #define REP(i,n) for(int i=0;i<(int)n;++i) #define ALL(c) (c).begin(), (c).end() #ifdef _MSC_VER #include <Windows.h> ll getTime() { return GetTickCount(); } #else #include <sys/time.h> ll getTime() { struct timeval tv; gettimeofday(&tv, NULL); ll result = tv.tv_sec * 1000LL + tv.tv_usec / 1000LL; //cerr << result << endl; return result; } #endif // http://www.jstatsoft.org/v08/i14/xorshift.pdf unsigned int xor128() { // 周期は 2^128-1 static unsigned int x=123456789,y=362436069,z=521288629,w=88675123; unsigned long t; t=(x^(x<<11));x=y;y=z;z=w; return( w=(w^(w>>19))^(t^(t>>8)) ); } //TODO:状態を表す型/構造体を作成する class STATE { public: //TODO:コンストラクタに必要な引数を追加する explicit STATE(); void next(); void prev(); double energy(); private: }; class SimulatedAnnealing { public: //TODO:コンストラクタに必要な引数を追加する SimulatedAnnealing(); STATE run(); private: static const int TIME_LIMIT; double calculateProbability(double score, double scoreNeighbor, double temperature); }; //TODO:コンストラクタに必要な引数を追加する SimulatedAnnealing::SimulatedAnnealing() { } //TODO:計算時間をミリ秒単位で設定する const int SimulatedAnnealing::TIME_LIMIT = 9900; STATE SimulatedAnnealing::run() { const ll timeStart = getTime(); const ll timeEnd = timeStart + TIME_LIMIT; STATE state; double energy = state.energy(); STATE result = state; double minEnergy = energy; int counter = 0; ll timeCurrent; while ((timeCurrent = getTime()) < timeEnd){ REP(loop, 100) { state.next(); const double energyNeighbor = state.energy(); const double random = xor128() * 0.00000000023283064365386962890625; const double probability = calculateProbability(energy, energyNeighbor, (double)(timeEnd - timeCurrent) / (double)(timeEnd - timeStart) + 1e-8); if (random < probability){ //Accept if (minEnergy > energyNeighbor) { #ifdef _MSC_VER fprintf(stderr, "minEnergy updated! %.5lf -> %.5lf\n", minEnergy, energyNeighbor); #endif minEnergy = energyNeighbor; result = state; } //fprintf(stderr, "Accepted %.5lf -> %.5lf : minEnergy=%.5lf\n", energy, energyNeighbor, minEnergy); energy = energyNeighbor; } else { //Decline state.prev(); //fprintf(stderr, "Declined\n"); } ++counter; } } fprintf(stderr, "counter:%d minEnergy:%.5lf\n", counter, minEnergy); return result; } double SimulatedAnnealing::calculateProbability(double energy, double energyNeighbor, double temperature) { if (energyNeighbor < energy) { return 1; } else { const double result = exp((energy - energyNeighbor) * 0.5) * temperature; //fprintf(stderr, "%lf -> %lf * %lf = %lf\n", energy, energyNeighbor, temperature, result); return result; } } //TODO:初期状態を作る関数を記述する STATE::STATE() { } //TODO:遷移後の状態を作る関数を記述する void STATE::next() { } //TODO:遷移前の状態を作る関数を記述する // 高々一つ前の状態までに戻れれば良い void STATE::prev() { } //TODO:状態のエネルギーを計算する関数を記述する // 状態はエネルギーの低い所に遷移する点に注意する double STATE::energy() { }