#ifndef LEMON_SIMANN_H #define LEMON_SIMANN_H 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; } double getBestCost() { return best_cost; } void run() { while (controller->next()) { mutate(); if (controller->accept(prev_cost - curr_cost)) { controller->acceptEvent(); if (curr_cost < best_cost) { saveAsBest(); controller->improveEvent(); } } else { revert(); controller->rejectEvent(); } } } class Controller { public: virtual void acceptEvent() {} virtual void improveEvent() {} virtual void rejectEvent() {} virtual bool next() = 0; virtual bool accept(double cost_diff) = 0; }; }; template class SimAnn : public SimAnnBase { private: E *curr_ent; E *best_ent; public: SimAnn2() : 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: // returns the new cost double mutate() { return 0.0; } // restores the entity to its previous state i.e. reverts the effects of // the last mutate() void revert() {} }; class SimpleController : public SimAnnBase::Controller { public: long iter, last_impr, max_iter, max_no_impr; double temp, annealing_factor; MyController() { 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(double cost_diff) { return (drand48() <= exp(cost_diff / temp)); } }; } #endif