TheAlgorithms-Python
137 строк · 5.1 Кб
1# https://en.wikipedia.org/wiki/Simulated_annealing
2import math3import random4from typing import Any5
6from .hill_climbing import SearchProblem7
8
9def simulated_annealing(10search_prob,11find_max: bool = True,12max_x: float = math.inf,13min_x: float = -math.inf,14max_y: float = math.inf,15min_y: float = -math.inf,16visualization: bool = False,17start_temperate: float = 100,18rate_of_decrease: float = 0.01,19threshold_temp: float = 1,20) -> Any:21"""22Implementation of the simulated annealing algorithm. We start with a given state,
23find all its neighbors. Pick a random neighbor, if that neighbor improves the
24solution, we move in that direction, if that neighbor does not improve the solution,
25we generate a random real number between 0 and 1, if the number is within a certain
26range (calculated using temperature) we move in that direction, else we pick
27another neighbor randomly and repeat the process.
28
29Args:
30search_prob: The search state at the start.
31find_max: If True, the algorithm should find the minimum else the minimum.
32max_x, min_x, max_y, min_y: the maximum and minimum bounds of x and y.
33visualization: If True, a matplotlib graph is displayed.
34start_temperate: the initial temperate of the system when the program starts.
35rate_of_decrease: the rate at which the temperate decreases in each iteration.
36threshold_temp: the threshold temperature below which we end the search
37Returns a search state having the maximum (or minimum) score.
38"""
39search_end = False40current_state = search_prob41current_temp = start_temperate42scores = []43iterations = 044best_state = None45
46while not search_end:47current_score = current_state.score()48if best_state is None or current_score > best_state.score():49best_state = current_state50scores.append(current_score)51iterations += 152next_state = None53neighbors = current_state.get_neighbors()54while (55next_state is None and neighbors56): # till we do not find a neighbor that we can move to57index = random.randint(0, len(neighbors) - 1) # picking a random neighbor58picked_neighbor = neighbors.pop(index)59change = picked_neighbor.score() - current_score60
61if (62picked_neighbor.x > max_x63or picked_neighbor.x < min_x64or picked_neighbor.y > max_y65or picked_neighbor.y < min_y66):67continue # neighbor outside our bounds68
69if not find_max:70change = change * -1 # in case we are finding minimum71if change > 0: # improves the solution72next_state = picked_neighbor73else:74probability = (math.e) ** (75change / current_temp76) # probability generation function77if random.random() < probability: # random number within probability78next_state = picked_neighbor79current_temp = current_temp - (current_temp * rate_of_decrease)80
81if current_temp < threshold_temp or next_state is None:82# temperature below threshold, or could not find a suitable neighbor83search_end = True84else:85current_state = next_state86
87if visualization:88from matplotlib import pyplot as plt89
90plt.plot(range(iterations), scores)91plt.xlabel("Iterations")92plt.ylabel("Function values")93plt.show()94return best_state95
96
97if __name__ == "__main__":98
99def test_f1(x, y):100return (x**2) + (y**2)101
102# starting the problem with initial coordinates (12, 47)103prob = SearchProblem(x=12, y=47, step_size=1, function_to_optimize=test_f1)104local_min = simulated_annealing(105prob, find_max=False, max_x=100, min_x=5, max_y=50, min_y=-5, visualization=True106)107print(108"The minimum score for f(x, y) = x^2 + y^2 with the domain 100 > x > 5 "109f"and 50 > y > - 5 found via hill climbing: {local_min.score()}"110)111
112# starting the problem with initial coordinates (12, 47)113prob = SearchProblem(x=12, y=47, step_size=1, function_to_optimize=test_f1)114local_min = simulated_annealing(115prob, find_max=True, max_x=100, min_x=5, max_y=50, min_y=-5, visualization=True116)117print(118"The maximum score for f(x, y) = x^2 + y^2 with the domain 100 > x > 5 "119f"and 50 > y > - 5 found via hill climbing: {local_min.score()}"120)121
122def test_f2(x, y):123return (3 * x**2) - (6 * y)124
125prob = SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_f1)126local_min = simulated_annealing(prob, find_max=False, visualization=True)127print(128"The minimum score for f(x, y) = 3*x^2 - 6*y found via hill climbing: "129f"{local_min.score()}"130)131
132prob = SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_f1)133local_min = simulated_annealing(prob, find_max=True, visualization=True)134print(135"The maximum score for f(x, y) = 3*x^2 - 6*y found via hill climbing: "136f"{local_min.score()}"137)138