Skip to content

Commit 16a65d2

Browse files
committed
Some refactoring.
1 parent a8a19b4 commit 16a65d2

File tree

1 file changed

+143
-153
lines changed

1 file changed

+143
-153
lines changed

python/stochastic/guided_local_search.py

Lines changed: 143 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -23,172 +23,162 @@
2323
"""
2424

2525
def random_permutation(cities):
26-
"""
27-
Same as the one in 2.5
28-
"""
29-
perm = [i for i in range(len(cities))]
30-
31-
for i in perm:
32-
r = random.randint(0, len(perm) - 1 - i) + i
33-
perm[r], perm[i] = perm[i], perm[r]
34-
35-
return perm
26+
"""
27+
Same as the one in 2.5
28+
"""
29+
perm = [i for i in range(len(cities))]
30+
31+
for i in perm:
32+
r = random.randint(0, len(perm) - 1 - i) + i
33+
perm[r], perm[i] = perm[i], perm[r]
34+
35+
return perm
3636

3737
def stochastic_two_opt(permutation):
38-
"""
39-
Same as the one in 2.5
40-
"""
41-
perm = [permutation[i] for i in range(len(permutation))]
42-
upper_bound = len(perm) - 1
43-
c1, c2 = random.randint(0, upper_bound), random.randint(0, upper_bound)
44-
exclude = [c1]
45-
46-
if c1 == 0:
47-
exclude.append(upper_bound)
48-
else:
49-
exclude.append(c1 - 1)
50-
51-
if c1 == upper_bound:
52-
exclude.append(0)
53-
else:
54-
exclude.append(c1 + 1)
55-
56-
while c2 in exclude:
57-
c2 = random.randint(0, upper_bound)
58-
59-
if c2 < c1:
60-
c1, c2 = c2, c1
61-
62-
perm_range = perm[c1:c2]
63-
perm_range.reverse()
64-
perm[c1:c2] = perm_range
65-
66-
return perm
38+
"""
39+
Same as the one in 2.5
40+
"""
41+
perm = [permutation[i] for i in range(len(permutation))]
42+
upper_bound = len(perm) - 1
43+
c1, c2 = random.randint(0, upper_bound), random.randint(0, upper_bound)
44+
exclude = [c1]
45+
46+
if c1 == 0:
47+
exclude.append(upper_bound)
48+
else:
49+
exclude.append(c1 - 1)
50+
51+
if c1 == upper_bound:
52+
exclude.append(0)
53+
else:
54+
exclude.append(c1 + 1)
55+
56+
while c2 in exclude:
57+
c2 = random.randint(0, upper_bound)
58+
59+
if c2 < c1:
60+
c1, c2 = c2, c1
61+
62+
perm_range = perm[c1:c2]
63+
perm_range.reverse()
64+
perm[c1:c2] = perm_range
65+
66+
return perm
6767

6868
def augmented_cost(permutation, penalties, cities, l):
69-
distance, augmented = 0, 0
70-
limit = len(permutation)
71-
72-
for i in range(limit):
73-
c1 = permutation[i]
74-
75-
if i == (limit - 1):
76-
c2 = permutation[0]
77-
else:
78-
c2 = permutation[i + 1]
79-
80-
if c2 < c1:
81-
c1, c2 = c2, c1
82-
83-
d = euc_2d(cities[c1], cities[c2])
84-
distance += d
85-
augmented += d + (l * penalties[c1][c2])
86-
87-
return [distance, augmented]
69+
distance, augmented = 0, 0
70+
limit = len(permutation)
71+
72+
for i in range(limit):
73+
c1 = permutation[i]
74+
75+
if i == (limit - 1):
76+
c2 = permutation[0]
77+
else:
78+
c2 = permutation[i + 1]
79+
80+
if c2 < c1:
81+
c1, c2 = c2, c1
82+
83+
d = euc_2d(cities[c1], cities[c2])
84+
distance += d
85+
augmented += d + (l * penalties[c1][c2])
86+
87+
return [distance, augmented]
8888

8989
def cost(cand, penalties, cities, l):
90-
cost, acost = augmented_cost(cand["vector"], penalties, cities, l)
91-
cand["cost"], cand["aug_cost"] = cost, acost
90+
cost, acost = augmented_cost(cand["vector"], penalties, cities, l)
91+
cand["cost"], cand["aug_cost"] = cost, acost
9292

9393
def local_search(current, cities, penalties, max_no_improv, l):
94-
cost(current, penalties, cities, l)
95-
count = 0
96-
97-
# begin-until hack
98-
while True:
99-
candidate = {}
100-
candidate["vector"] = stochastic_two_opt(current["vector"])
101-
cost(candidate, penalties, cities, l)
102-
103-
if candidate["aug_cost"] < current["aug_cost"]:
104-
count = 0
105-
else:
106-
count += 1
107-
108-
if candidate["aug_cost"] < current["aug_cost"]:
109-
current = candidate
110-
111-
if count >= max_no_improv:
112-
return current
94+
cost(current, penalties, cities, l)
95+
count = 0
96+
97+
# begin-until hack
98+
while True:
99+
candidate = {}
100+
candidate["vector"] = stochastic_two_opt(current["vector"])
101+
cost(candidate, penalties, cities, l)
102+
103+
if candidate["aug_cost"] < current["aug_cost"]:
104+
count = 0
105+
else:
106+
count += 1
107+
108+
if candidate["aug_cost"] < current["aug_cost"]:
109+
current = candidate
110+
111+
if count >= max_no_improv:
112+
return current
113113

114114
def calculate_feature_utilities(penal, cities, permutation):
115-
limit = len(permutation)
116-
limit_list = range(limit)
117-
utilities = [0 for i in limit_list]
118-
119-
for i in limit_list:
120-
c1 = permutation[i]
121-
122-
if i == (limit - 1):
123-
c2 = permutation[0]
124-
else:
125-
c2 = permutation[i + 1]
126-
127-
if c2 < c1:
128-
c1, c2 = c2, c1
129-
130-
utilities[i] = euc_2d(cities[c1], cities[c2]) / (1 + penal[c1][c2])
131-
132-
return utilities
115+
limit = len(permutation)
116+
limit_list = range(limit)
117+
utilities = [0 for i in limit_list]
118+
119+
for i in limit_list:
120+
c1 = permutation[i]
121+
122+
if i == (limit - 1):
123+
c2 = permutation[0]
124+
else:
125+
c2 = permutation[i + 1]
126+
127+
if c2 < c1:
128+
c1, c2 = c2, c1
129+
130+
utilities[i] = euc_2d(cities[c1], cities[c2]) / (1 + penal[c1][c2])
131+
132+
return utilities
133133

134134
def update_penalties(penalties, cities, permutation, utilities):
135-
max_util = max(utilities)
136-
limit = len(permutation)
137-
138-
for i in range(limit):
139-
c1 = permutation[i]
140-
141-
if i == (limit - 1):
142-
c2 = permutation[0]
143-
else:
144-
c2 = permutation[i + 1]
145-
146-
if c2 < c1:
147-
c1, c2 = c2, c1
148-
149-
if utilities[i] == max_util:
150-
penalties[c1][c2] += 1
151-
152-
return penalties
135+
max_util = max(utilities)
136+
limit = len(permutation)
137+
138+
for i in range(limit):
139+
c1 = permutation[i]
140+
141+
if i == (limit - 1):
142+
c2 = permutation[0]
143+
else:
144+
c2 = permutation[i + 1]
145+
146+
if c2 < c1:
147+
c1, c2 = c2, c1
148+
149+
if utilities[i] == max_util:
150+
penalties[c1][c2] += 1
151+
152+
return penalties
153153

154154
def search(max_iterations, cities, max_no_improv, l):
155-
current = {}
156-
current["vector"] = random_permutation(cities)
157-
best = None
158-
cities_count_list = range(len(cities))
159-
penalties = [[0 for i in cities_count_list] for j in cities_count_list]
160-
161-
for i in range(max_iterations):
162-
current = local_search(current, cities, penalties, max_no_improv, l)
163-
utilities = calculate_feature_utilities(penalties, cities, current["vector"])
164-
update_penalties(penalties, cities, current["vector"], utilities)
165-
166-
if best is None or current["cost"] < best["cost"]:
167-
best = current
168-
169-
print("Iteration #" + str(i + 1) + ", best = " + str(best["cost"]) + ", aug = " + str(best["aug_cost"]))
170-
171-
return best
155+
current = {}
156+
current["vector"] = random_permutation(cities)
157+
best = None
158+
cities_count_list = range(len(cities))
159+
penalties = [[0 for i in cities_count_list] for j in cities_count_list]
160+
161+
for i in range(max_iterations):
162+
current = local_search(current, cities, penalties, max_no_improv, l)
163+
utilities = calculate_feature_utilities(penalties, cities, current["vector"])
164+
update_penalties(penalties, cities, current["vector"], utilities)
165+
166+
if best is None or current["cost"] < best["cost"]:
167+
best = current
168+
169+
print("Iteration #" + str(i + 1) + ", best = " + str(best["cost"]) + ", aug = " + str(best["aug_cost"]))
170+
171+
return best
172172

173173
if __name__ == "__main__":
174-
# Problem configuration
175-
berlin52 = [[565,575],[25,185],[345,750],[945,685],[845,655],
176-
[880,660],[25,230],[525,1000],[580,1175],[650,1130],[1605,620],
177-
[1220,580],[1465,200],[1530,5],[845,680],[725,370],[145,665],
178-
[415,635],[510,875],[560,365],[300,465],[520,585],[480,415],
179-
[835,625],[975,580],[1215,245],[1320,315],[1250,400],[660,180],
180-
[410,250],[420,555],[575,665],[1150,1160],[700,580],[685,595],
181-
[685,610],[770,610],[795,645],[720,635],[760,650],[475,960],
182-
[95,260],[875,920],[700,500],[555,815],[830,485],[1170,65],
183-
[830,610],[605,625],[595,360],[1340,725],[1740,245]]
184-
185-
# Algorithm configuration
186-
max_iterations = 150
187-
max_no_improv = 20
188-
alpha = 0.3
189-
local_search_optima = 12000
190-
l = alpha * (local_search_optima / len(berlin52))
191-
192-
# Execute the algorithm
193-
best = search(max_iterations, berlin52, max_no_improv, l)
194-
print("Done. Best solution: c = " + str(best["cost"]) + ", v = " + str(best["vector"]))
174+
from .common import berlin52
175+
176+
max_iterations = 150
177+
max_no_improv = 20
178+
alpha = 0.3
179+
local_search_optima = 12000
180+
l = alpha * (local_search_optima / len(berlin52))
181+
182+
# Execute the algorithm
183+
best = search(max_iterations, berlin52, max_no_improv, l)
184+
print("Done. Best solution: c = " + str(best["cost"]) + ", v = " + str(best["vector"]))

0 commit comments

Comments
 (0)