#ifndef LEMON_SIMANN_H #define LEMON_SIMANN_H #include #include #include namespace lemon { const double INFTY = 1e24; class SimAnnBase { public: class Controller; private: Controller *controller; protected: double curr_cost; double prev_cost; double best_cost; virtual void mutate() = 0; virtual void revert() = 0; virtual void saveAsBest() = 0; public: SimAnnBase() { curr_cost = prev_cost = best_cost = INFTY; } void setController(Controller &_controller) { controller = &_controller; controller->setBase(this); } double getCurrCost() { return curr_cost; } double getPrevCost() { return prev_cost; } double getBestCost() { return best_cost; } void run() { controller->init(); while (controller->next()) { mutate(); if (controller->accept()) { controller->acceptEvent(); if (curr_cost < best_cost) { saveAsBest(); controller->improveEvent(); } } else { revert(); controller->rejectEvent(); } } } class Controller { public: SimAnnBase *base; virtual void init() {} virtual void acceptEvent() {} virtual void improveEvent() {} virtual void rejectEvent() {} virtual void setBase(SimAnnBase *_base) { base = _base; } virtual bool next() = 0; virtual bool accept() = 0; }; }; template class SimAnn : public SimAnnBase { private: E *curr_ent; E *best_ent; public: SimAnn() : SimAnnBase() {} void setEntity(E &ent) { curr_ent = new E(ent); best_ent = new E(ent); } E getBestEntity() { return *best_ent; } void mutate() { curr_ent->mutate(); } void revert() { curr_ent->revert(); } void saveAsBest() { *best_ent = *curr_ent; best_cost = curr_cost; } }; class EntitySkeleton { public: /*! \brief Makes a minor change to the entity. * \return the new cost */ double mutate() { return 0.0; } /*! \brief Restores the entity to its previous state i.e. reverts the * effects of the last mutate. */ void revert() {} }; /*! \brief A simple controller for the simulated annealing class. * \todo Find a way to set the various parameters. */ class SimpleController : public SimAnnBase::Controller { public: long iter, last_impr, max_iter, max_no_impr; double temp, annealing_factor; SimpleController() { iter = last_impr = 0; max_iter = 500000; max_no_impr = 20000; annealing_factor = 0.9999; temp = 1000; } void acceptEvent() { iter++; } void improveEvent() { last_impr = iter; } void rejectEvent() { iter++; } bool next() { temp *= annealing_factor; bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr); return !quit; } bool accept() { return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() / temp)); } }; /*! \brief A controller with preset running time for the simulated annealing * class. * \todo Find a better name. */ class AdvancedController : public SimAnnBase::Controller { private: double threshold() { return 0.0; } public: double alpha; double temp; double avg_cost; double start_time, end_time; void init() { timeval tv; gettimeofday(&tv, 0); start_time = tv.tv_sec + double(tv.tv_usec) / 1e6; } void acceptEvent() { avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost; } void improveEvent() { } void rejectEvent() { } bool next() { // abs(avg_cost - base->getBestCost()) // ha nagy: cooling factor novelese // ha kicsi: homerseklet novelese // de mennyivel? timeval tv; gettimeofday(&tv, 0); double elapsed_time = tv.tv_sec + double(tv.tv_usec) / 1e6 - start_time; return elapsed_time < end_time; } bool accept() { return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() / temp)); } }; } #endif