This repository has been archived by the owner on Dec 25, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
simulated_annealing.py
103 lines (82 loc) · 4.9 KB
/
simulated_annealing.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# -*- coding: utf-8 -*-
import random
import math
from metaheuristic import MetaHeuristic
# Конечная температура
COOL = 0.001
# Начальная температура какая-нибудь огромная
START_TEMPERATURE = 200
# Значение декремента убывающей функции
DECREMENT = 1.0001
MAGIC_CONSTANT = 0.01
"""
1) сравниваем текущее значение F с наилучшим найденным;
если текущее значение лучше — меняем глобальное наилучшее
2) случайным образом генерируем новое состояние;
распределение вероятности для него должно зависеть от текущего состояния и текущей температуры
3) вычисляем значение функции для сгенерированной точки
4) принимаем или не принимаем сгенерированное состояние в качестве текущего;
вероятность этого решения должна зависеть от разности функций сгенерированного и текущего состояний
и, конечно, от температуры (чем выше температура, тем больше вероятность принять
состояние хуже текущего)
если новое состояние не принято, генерируем другое и повторяем действия с третьего пункта,
если принято — переходим к следующей итерации, понизив температуру
(но чаще переход к следующему шагу производят в любом случае, чтобы избежать долгого зацикливания)
"""
class SimulatedAnnealing(MetaHeuristic):
"""
Алгоритм, схожий с имитацией отжига
"""
def __init__(self, n, m, k, funcName):
super(SimulatedAnnealing, self).__init__(n, m, k, funcName)
def run(self):
# Возьмем случайное расписание
schedule = MetaHeuristic.generateRandomSchedule(self._n, self._m, self._k, self._totalGroups)
# Обзовем его текущим лучшим
best_schedule = schedule
# Зададим начальную температуру
temperature = START_TEMPERATURE
# введем распределение вероятности принятия нового состояния
h = lambda T, delE: 1 / (1 + math.exp(-delE / T));
# введем функцию понижения температуры
decrease_temperature = lambda T, iteration: T*math.exp(-DECREMENT * math.pow(iteration, 1/(self._m*self._k)))
# Зададим нашу функцию, которую мы хотим оптимизировать
optimization_func = getattr(self, self._funcName)
best_function_result = 0
# Пока температура не опустилась, выполняем алгоритм
iteration = 0
while temperature > COOL:
self.__move_to_new_tours(schedule, temperature)
if optimization_func(schedule) < best_function_result:
best_schedule = schedule
else:
if random.random() > h(temperature, optimization_func(schedule) - best_function_result):
schedule = best_schedule
else:
best_schedule = schedule
best_function_result = optimization_func(schedule)
print "best_function_result: %s"%best_function_result
temperature = decrease_temperature(temperature, iteration)
print "temperature: %s"%temperature
iteration += 1
self.function_result = best_function_result
return best_schedule
def __move_to_new_tours(self, schedule, temperature):
"""
Функция случайного выбора следующего тура
на основе текущей вероятности
TODO: add serious implementation
"""
alpha = random.random()
# на самом деле, поскольку пример алгоритма был для коэффициента движения
# по доске координаты, то тут он особо не имеет смысла. Поэтому мы на основе
# коэффициента, раз он зависит от температуры, будем просто принимать решение
# о генерации нового тура. Конечно, эффективность будет очевидно снижена.
z = (math.pow((1 + 1/temperature), (2 * alpha - 1)) - 1) * temperature;
print "ZZZZ: %s\n\n"%z
tour = random.choice(range(self._m))
group = random.choice(range(self._totalGroups))
if z > MAGIC_CONSTANT:
random.shuffle(schedule[tour][group])
else:
schedule = MetaHeuristic.generateRandomSchedule(self._n, self._m, self._k, self._totalGroups)