-
Notifications
You must be signed in to change notification settings - Fork 0
/
anneal.jl
143 lines (122 loc) · 4.29 KB
/
anneal.jl
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using Gadfly
using Cairo
using Fontconfig
type Coordinate
x :: Float64
y :: Float64
end
function input_coordinates(filename::String)
coords = Array(Coordinate, 0)
open(filename, "r") do file
for line in eachline(file)
coord_ary = split(strip(line, ['\n', ',']), ' ')
coord = Coordinate(float(coord_ary[1]), float(coord_ary[2]))
push!(coords, coord)
end
end
return coords
end
function calc_distance{N <: Integer}(path::Array{N}, coords::Array{Coordinate})
distance = 0
for i in 1:(length(coords) - 1)
present_idx, next_idx = path[i], path[i + 1]
distance += sqrt((coords[next_idx].x - coords[present_idx].x)^2
+ (coords[next_idx].y - coords[present_idx].y)^2)
end
return distance
end
function random_path{N <: Integer}(n::N)
path = collect(1:(n - 1))
path = shuffle(path)
push!(path, path[1])
return path
end
function random_path(coords::Array{Coordinate})
n = length(coords)
random_path(n)
end
function metropolis{N <: Integer, R <: Real}(current_path::Array{N},
coords::Array{Coordinate},
temp::R)
current_distance = calc_distance(current_path, coords)
candidate_path = copy(current_path)
n = length(current_path)
swap_cities_indices = Array(Any, 2)
while true
swap_cities_indices = rand(2:(length(current_path) - 1), 2)
if swap_cities_indices[1] != swap_cities_indices[2]
break
end
end
candidate_path[swap_cities_indices[1]], candidate_path[swap_cities_indices[2]] =
candidate_path[swap_cities_indices[2]], candidate_path[swap_cities_indices[1]]
candidate_distance = calc_distance(candidate_path, coords)
Δd = candidate_distance - current_distance
if Δd < 0
return candidate_path, candidate_distance
end
prob = exp(-Δd / temp)
if rand() <= prob
return candidate_path, candidate_distance
else
return current_path, current_distance
end
end
function anneal{N <: Integer}(path::Array{N}, coords::Array{Coordinate}; n_iter::N=100000,
pmelt=0.7, tgt=0.1, stagfactor=0.05, procplt::Bool=false)
n_cities = length(path)
initial_distance = calc_distance(path, coords)
min_distance, max_distance = initial_distance, initial_distance
optimized_distances = Array(Float64, 0)
distances = Array(Float64, 0)
push!(optimized_distances, initial_distance)
push!(distances, initial_distance)
for i in 1:(max(0.01 * n_cities, 2))
path_, disntance = metropolis(path, coords, typemax(Int64))
if disntance < min_distance
min_distance = disntance
end
if max_distance < disntance
max_distance = disntance
end
end
range = (max_distance - min_distance) * pmelt
temp = tgt ^ (1 / n_iter)
optimized_distance = initial_distance
optimized_step = 1
optimized_path = copy(path)
path_ = copy(path)
for i in 1:n_iter
print("$(i) / $(n_iter) processing...\r")
flush(STDOUT)
dtemp = range * (temp ^ i)
path_, distance = metropolis(path_, coords, dtemp)
if distance < optimized_distance
optimized_distance = distance
optimized_path = copy(path_)
optimized_step = i
end
push!(optimized_distances, optimized_distance)
push!(distances, distance)
# Reheat
if i - optimized_step == stagfactor * n_iter
temp = temp ^ (0.05 * i / n_iter)
end
end
print("\n")
if procplt
white_panel = Theme(background_color="white")
p = plot(layer(x=1:length(distances), y=distances, Geom.line,
Theme(default_color="gray")),
layer(x=1:length(distances), y=optimized_distances, Geom.line,
Theme(default_color="orange", line_width=2px)),
white_panel,
Coord.Cartesian(xmin=0, xmax=length(distances)))
img = PNG("result.png", 1280px, 720px)
draw(img, p)
end
return optimized_path
end
coords = input_coordinates("prefs.in")
init_path = random_path(coords)
path = anneal(init_path, coords, n_iter=100000, procplt=true)