diff -r f588efc6d607 -r 68beae6758a7 src/work/akos/simann.h --- a/src/work/akos/simann.h Mon Nov 22 09:12:33 2004 +0000 +++ b/src/work/akos/simann.h Mon Nov 22 14:39:40 2004 +0000 @@ -3,7 +3,7 @@ #include #include -#include +#include namespace lemon { @@ -30,12 +30,12 @@ controller = &_controller; controller->setBase(this); } - double getCurrCost() { return curr_cost; } - double getPrevCost() { return prev_cost; } - double getBestCost() { return best_cost; } + double getCurrCost() const { return curr_cost; } + double getPrevCost() const { return prev_cost; } + double getBestCost() const { return best_cost; } void run() { controller->init(); - while (controller->next()) { + do { mutate(); if (controller->accept()) { controller->acceptEvent(); @@ -48,7 +48,7 @@ revert(); controller->rejectEvent(); } - } + } while (controller->next()); } /*! \brief A base class for controllers. */ @@ -72,6 +72,7 @@ }; }; + /*! \todo atgondolni mi is ez a prev_cost */ template class SimAnn : public SimAnnBase { private: @@ -85,10 +86,12 @@ } E getBestEntity() { return *best_ent; } void mutate() { - curr_ent->mutate(); + prev_cost = curr_cost; + curr_cost = curr_ent->mutate(); } void revert() { curr_ent->revert(); + curr_cost = prev_cost; } void saveAsBest() { *best_ent = *curr_ent; @@ -140,8 +143,13 @@ return !quit; } bool accept() { - return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() / - temp)); + double cost_diff = base->getPrevCost() - base->getCurrCost(); + if (cost_diff < 0.0) { + return (drand48() <= exp(cost_diff / temp)); + } + else { + return true; + } } }; @@ -151,51 +159,90 @@ */ class AdvancedController : public SimAnnBase::Controller { private: + Timer timer; /*! \param time the elapsed time in seconds */ - double threshold(double time) { return 0.0; } + virtual double threshold(double time) { + // this is the function 1 / log(x) scaled and offset + static double xm = 5.0 / end_time; + static double ym = start_threshold / (1 / log(1.2) - 1 / log(5.0 + 1.2)); + return ym * (1 / log(xm * time + 1.2) - 1 / log(5.0 + 1.2)); + } public: double alpha, beta, gamma; double end_time, start_time; + double start_threshold; double avg_cost; double temp, ann_fact; - /*! \param _end_time running_time + bool warmup; + long iter; + /*! \param _end_time running time in seconds * \param _alpha parameter used to calculate the running average * \param _beta parameter used to decrease the annealing factor * \param _gamma parameter used to increase the temperature */ AdvancedController(double _end_time, double _alpha = 0.2, double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta), - gamma(_gamma), end_time(_end_time) {} + gamma(_gamma), end_time(_end_time), ann_fact(0.9999), warmup(true), + iter(0) {} void init() { - timeval tv; - gettimeofday(&tv, 0); - start_time = tv.tv_sec + double(tv.tv_usec) / 1e6; + avg_cost = base->getCurrCost(); } void acceptEvent() { avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost; + iter++; } void improveEvent() { } void rejectEvent() { + iter++; } bool next() { - timeval tv; - gettimeofday(&tv, 0); - double elapsed_time = tv.tv_sec + double(tv.tv_usec) / 1e6 - start_time; - if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) { - // decrease the annealing factor - ann_fact *= beta; + if (warmup) { + static double max_cost_diff = 0.0; + double cost_diff = base->getCurrCost() - base->getPrevCost(); + // jo ez igy egyaltalan? -> prev_cost + if ((cost_diff > 0.0) && (cost_diff > max_cost_diff)) { + max_cost_diff = cost_diff; + } + // How to set the starting temperature when all the 100 first + // iterations improve the solution? + if (iter > 100) { + // calculate starting threshold and starting temperature + start_threshold = fabs(base->getBestCost() - avg_cost); + temp = exp(max_cost_diff) / 0.5; + warmup = false; + timer.reset(); + } + return true; } else { - // increase the temperature - temp *= gamma; + double elapsed_time = timer.getRealTime(); + if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) { + // decrease the annealing factor + ann_fact *= beta; + } + else { + // increase the temperature + temp *= gamma; + } + temp *= ann_fact; + return elapsed_time < end_time; } - temp *= ann_fact; - return elapsed_time < end_time; } bool accept() { - return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() / - temp)); + if (warmup) { + // we accept eveything during the "warm up" phase + return true; + } + else { + double cost_diff = base->getPrevCost() - base->getCurrCost(); + if (cost_diff < 0.0) { + return (drand48() <= exp(cost_diff / temp)); + } + else { + return true; + } + } } };