-
Notifications
You must be signed in to change notification settings - Fork 4
/
ex6-simulated-annealing
104 lines (87 loc) · 3.94 KB
/
ex6-simulated-annealing
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
104
#!/usr/bin/env python
# --------------------------------------------------------------------------------------------------------- Intermediate
import math, random # just for generating random mountains
import numpy as np
n = 10000 # size of the problem: number of possible solutions x = 0, ..., n-1
# generate random mountains
def mountains(n):
h = [0]*n
for i in range(50):
c = random.randint(20, n-20)
w = random.randint(3, int(math.sqrt(n/5)))**2
s = random.random()
h[max(0, c-w):min(n, c+w)] = [h[i] + s*(w-abs(c-i)) for i in range(max(0, c-w), min(n, c+w))]
# scale the height so that the lowest point is 0.0 and the highest peak is 1.0
low = min(h)
high = max(h)
h = [y - low for y in h]
h = [y / (high-low) for y in h]
return h
h = mountains(n)
# start at a random place
x0 = random.randint(1, n-1)
x = x0
# keep climbing for 5000 steps
steps = 5000
def main(h, x):
n = len(h)
# the climbing starts here
for step in range(steps):
# this is our temperature to to be used for simulated annealing
# it starts large and decreases with each step. you don't have to change this
T = 2*max(0, ((steps-step*1.2)/steps))**3
x_new = random.randint(max(0, x-1000), min(n-1, x+1000))
S_old = h[x]
S_new = h[x_new]
if h[x_new] > h[x]:
x = x_new # the new position is higher, go there
else:
if T > 0:
prob = np.exp(-(S_old - S_new)/T)
if random.random() < prob:
x = x_new
pass # add simulated annealing here. remember to handle T=0
# correctly!
return x
x = main(h, x0)
print("ended up at %d, highest point is %d" % (x, np.argmax(h)))
# --------------------------------------------------------------------------------------------------------- Advanced
import numpy as np
import random
N = 100 # size of the problem is N x N
steps = 3000 # total number of iterations
tracks = 50
# generate a landscape with multiple local optima
def generator(x, y, x0=0.0, y0=0.0):
return np.sin((x/N-x0)*np.pi)+np.sin((y/N-y0)*np.pi)+\
.07*np.cos(12*(x/N-x0)*np.pi)+.07*np.cos(12*(y/N-y0)*np.pi)
x0 = np.random.random() - 0.5
y0 = np.random.random() - 0.5
h = np.fromfunction(np.vectorize(generator), (N, N), x0=x0, y0=y0, dtype=int)
peak_x, peak_y = np.unravel_index(np.argmax(h), h.shape)
# starting points
x = np.random.randint(0, N, tracks)
y = np.random.randint(0, N, tracks)
def main():
global x
global y
for step in range(steps):
# add a temperature schedule here
T = max(0, ((steps - step)/steps)**3-.005)
# update solutions on each search track
for i in range(tracks):
# try a new solution near the current one
x_new = np.random.randint(max(0, x[i]-2), min(N, x[i]+2+1))
y_new = np.random.randint(max(0, y[i]-2), min(N, y[i]+2+1))
S_old = h[x[i], y[i]]
S_new = h[x_new, y_new]
# change this to use simulated annealing
if S_new > S_old:
x[i], y[i] = x_new, y_new # new solution is better, go there
else:
if random.random() < (np.exp(-(S_old - S_new) / T)): # if the new solution is worse, do nothing
x[i], y[i] = x_new, y_new
pass # if the new solution is worse, do nothing
# Number of tracks found the peak
print(sum([x[j] == peak_x and y[j] == peak_y for j in range(tracks)]))
main()