15 #ifndef PAAL_SIMULATED_ANNEALING_HPP
16 #define PAAL_SIMULATED_ANNEALING_HPP
40 template <
typename Duration = std::chrono::seconds,
41 typename Clock = std::chrono::system_clock>
52 double startTemperature,
53 double endTemperature)
54 : m_duration(duration), m_start(Clock::now()),
55 m_multiplier(startTemperature),
56 m_base(std::pow(endTemperature / startTemperature,
57 1. / duration.count())) {}
62 void restart() { m_start = Clock::now(); }
71 std::pow(m_base, std::chrono::duration_cast<Duration>(
72 Clock::now() - m_start).count());
77 typename Clock::time_point m_start;
93 template <
typename Clock = std::chrono::system_clock,
typename Duration>
95 double startTemperature,
96 double endTemperature) {
98 duration, startTemperature, endTemperature);
117 double startTemperature,
double multiplier,
118 double numberOFRoundsWithSameTemperature = 1)
119 : m_temperature(startTemperature), m_multiplier(multiplier),
120 m_number_of_rounds_with_same_temperature(
121 numberOFRoundsWithSameTemperature) {}
129 if (++m_cnt_from_last_multiply ==
130 m_number_of_rounds_with_same_temperature) {
131 m_temperature *= m_multiplier;
132 m_cnt_from_last_multiply = 0;
134 return m_temperature;
138 double m_temperature;
140 int m_number_of_rounds_with_same_temperature;
141 int m_cnt_from_last_multiply = 0;
169 template <
typename Solution,
typename ProbabilisticGain,
typename GetMoves,
170 typename SetTemperature>
172 GetMoves
get_moves, SetTemperature set_temperature,
173 double acceptance_rate = 0.4,
174 int repeats_number = 1e3,
double epsilon = 1e-4) {
175 assert(acceptance_rate >= 0. && acceptance_rate <= 1.);
177 auto get_success_rate = [&](
int t) {
179 int number_of_success = 0;
181 for (
int i = 0; i < repeats_number; ++i) {
182 for (
auto && move : get_moves(solution)) {
184 if (detail::positive_delta(gain(solution, move))) {
189 return double(number_of_success) / total;
194 double success_rate = get_success_rate(t);
195 double t_lower_bound{ t }, t_upper_bound{ t };
196 if (success_rate > acceptance_rate) {
199 success_rate = get_success_rate(t);
203 }
while (success_rate > acceptance_rate);
205 t_upper_bound = 2 * t;
206 }
else if (success_rate < acceptance_rate) {
209 success_rate = get_success_rate(t);
210 }
while (success_rate < acceptance_rate);
211 t_lower_bound = t / 2;
218 while (t_upper_bound - t_lower_bound > epsilon) {
219 t = (t_upper_bound + t_lower_bound) / 2;
220 success_rate = get_success_rate(t);
221 if (success_rate > acceptance_rate) {
223 }
else if (success_rate < acceptance_rate) {
230 return (t_upper_bound + t_lower_bound) / 2;
244 template <
typename Gain,
typename GetTemperature,
245 typename random_generator = std::default_random_engine>
257 random_generator rand = random_generator())
258 : m_gain(gain), m_get_temperature(getTemperature), m_rand(rand),
259 m_distribution(0.0, 1.0) {}
290 : m_is_chosen(false), m_delta(std::numeric_limits<Delta>::max()) {}
300 if (m_is_chosen != other.m_is_chosen) {
301 return m_is_chosen < other.m_is_chosen;
303 return m_delta < other.m_delta;
315 if (m_is_chosen != other.m_is_chosen) {
316 return m_is_chosen > other.m_is_chosen;
318 return m_delta > other.m_delta;
339 is_chosen(
bool isChosen, Delta d) : m_is_chosen(isChosen), m_delta(d) {}
353 template <
typename... Args>
355 ->is_chosen<
typename std::result_of<Gain(Args...)>::type> {
356 auto delta = m_gain(std::forward<Args>(args)...);
357 using Delta = decltype(delta);
358 if (detail::positive_delta(delta)) {
361 if (m_distribution(m_rand) <
362 fast_exp(
double(delta) / m_get_temperature())) {
372 GetTemperature m_get_temperature;
373 random_generator m_rand;
374 std::uniform_real_distribution<double> m_distribution;
389 template <
typename Gain,
typename GetTemperature,
390 typename random_generator = std::default_random_engine>
392 random_generator rand =
393 random_generator()) {
396 std::move(gain), std::move(getTemperature), std::move(rand));
412 template <
typename Commit,
typename Gain,
typename GetTemperature,
413 typename random_generator = std::default_random_engine>
418 GetTemperature get_temperature,
419 random_generator rand =
423 std::move(gain), std::move(get_temperature), std::move(rand))) {}
433 template <
typename... Args>
bool operator()(Args &&... args) {
434 if (detail::positive_delta(m_gain(args...))) {
435 return m_commit(std::forward<Args>(args)...);
455 template <
typename Commit,
typename Gain,
typename GetTemperature,
456 typename random_generator = std::default_random_engine>
458 GetTemperature getTemperature,
459 random_generator rand =
460 random_generator{}) {
461 return simulated_annealing_commit_adaptor<Commit, Gain, GetTemperature,
463 std::move(commit), std::move(gain), std::move(getTemperature),
470 #endif // PAAL_SIMULATED_ANNEALING_HPP
auto operator()(Args &&...args) -> is_chosen< typename std::result_of< Gain(Args...)>::type >
operator(), returns original gain with information indicating if the move is chosen ...
bool chosen() const
chosen
This functors returns potential (temperature) using the following schema. The start potential equals ...
simulated_annealing_commit_adaptor(Commit commit, Gain gain, GetTemperature get_temperature, random_generator rand=random_generator())
contructor
simulated_annealing_gain_adaptor(Gain gain, GetTemperature getTemperature, random_generator rand=random_generator())
constructor
bool operator()(Args &&...args)
operator()
exponential_cooling_schema_dependant_on_iteration(double startTemperature, double multiplier, double numberOFRoundsWithSameTemperature=1)
Constructor.
This object represents Delta computed by gain and the decision if the object is taken or not...
exponential_cooling_schema_dependant_on_time(Duration duration, double startTemperature, double endTemperature)
Constructor.
This functors returns potential (temperature) using the following schema. The start potential equals ...
static is_chosen make_chosen(Delta d)
creates is_chosen for Move object
double operator()()
operator(), return Temperature at given time point point
idea is NOT mine, found in the web
This adaptor takes Gain functor and adopts it to simulated annealing. For each move, if it has positive gain it is chosen otherwise the move is chosen wit probability e^(movesGain/Temperature). Temperature is given by getTemperature functor.
void restart()
resets the start point
auto make_simulated_annealing_gain_adaptor(Gain gain, GetTemperature getTemperature, random_generator rand=random_generator())
make function for simulated_annealing_gain_adaptor
double operator()() const
operator(), return Temperature at given time point point
auto make_simulated_annealing_commit_adaptor(Commit commit, Gain gain, GetTemperature getTemperature, random_generator rand=random_generator{})
make for simulated_annealing_commit_adaptor
float fast_exp(float p)
fast power of e.
bool operator>(is_chosen other) const
operator>
bool local_search(Solution &solution, SearchStrategy searchStrategy, ContinueOnSuccess succ, ContinueOnFail fail, components...comps)
detail
bool operator<(is_chosen other) const
operator<. Chosen move is always bigger then unchosen
This adaptor takes Cammit functor and adopts it to simulated annealing. If the input move has positiv...
static is_chosen make_unchosen(Delta d)
creates is_chosen for Move which is not chosen
double start_temperature(Solution &solution, ProbabilisticGain gain, GetMoves get_moves, SetTemperature set_temperature, double acceptance_rate=0.4, int repeats_number=1e3, double epsilon=1e-4)
This function takes gain functor which is assumed to be probabilistic and dependent on one nonnegativ...
is_chosen()
constructor (from 0) represents the largest possible value of unchosen element If some element is big...
auto make_exponential_cooling_schema_dependant_on_time(Duration duration, double startTemperature, double endTemperature)
make function for exponential_cooling_schema_dependant_on_time