Skip to content

Commit 4f32123

Browse files
committed
Some code clean-up.
1 parent 9a651b6 commit 4f32123

File tree

4 files changed

+166
-134
lines changed

4 files changed

+166
-134
lines changed

python/2_Stochastic_Algorithms/iterated_local_search.py

Lines changed: 106 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -23,125 +23,125 @@
2323
"""
2424

2525
def euc_2d(c1, c2):
26-
return math.sqrt(((c1[0] - c2[0]) ** 2) + ((c1[1] - c2[1]) ** 2))
26+
return math.sqrt(((c1[0] - c2[0]) ** 2) + ((c1[1] - c2[1]) ** 2))
2727

2828
def cost(permutation, cities):
29-
distance = 0
30-
limit = len(permutation)
31-
32-
for i in range(limit):
33-
if i == (limit - 1):
34-
c2 = permutation[0]
35-
else:
36-
c2 = permutation[i + 1]
37-
38-
distance += euc_2d(cities[permutation[i]], cities[c2])
39-
40-
return distance
29+
distance = 0
30+
limit = len(permutation)
31+
32+
for i in range(limit):
33+
if i == (limit - 1):
34+
c2 = permutation[0]
35+
else:
36+
c2 = permutation[i + 1]
37+
38+
distance += euc_2d(cities[permutation[i]], cities[c2])
39+
40+
return distance
4141

4242
def random_permutation(cities):
43-
perm = [i for i in range(len(cities))]
44-
45-
for i in perm:
46-
r = random.randint(0, len(perm) - 1 - i) + i
47-
perm[r], perm[i] = perm[i], perm[r]
48-
49-
return perm
43+
perm = [i for i in range(len(cities))]
44+
45+
for i in perm:
46+
r = random.randint(0, len(perm) - 1 - i) + i
47+
perm[r], perm[i] = perm[i], perm[r]
48+
49+
return perm
5050

5151
def stochastic_two_opt(permutation):
52-
perm = [permutation[i] for i in range(len(permutation))]
53-
upper_bound = len(perm) - 1
54-
c1, c2 = random.randint(0, upper_bound), random.randint(0, upper_bound)
55-
exclude = [c1]
56-
57-
if c1 == 0:
58-
exclude.append(upper_bound)
59-
else:
60-
exclude.append(c1 - 1)
61-
62-
if c1 == upper_bound:
63-
exclude.append(0)
64-
else:
65-
exclude.append(c1 + 1)
66-
67-
while c2 in exclude:
68-
c2 = random.randint(0, upper_bound)
69-
70-
if c2 < c1:
71-
c1, c2 = c2, c1
72-
73-
perm_range = perm[c1:c2]
74-
perm_range.reverse()
75-
perm[c1:c2] = perm_range
76-
77-
return perm
52+
perm = [permutation[i] for i in range(len(permutation))]
53+
upper_bound = len(perm) - 1
54+
c1, c2 = random.randint(0, upper_bound), random.randint(0, upper_bound)
55+
exclude = [c1]
56+
57+
if c1 == 0:
58+
exclude.append(upper_bound)
59+
else:
60+
exclude.append(c1 - 1)
61+
62+
if c1 == upper_bound:
63+
exclude.append(0)
64+
else:
65+
exclude.append(c1 + 1)
66+
67+
while c2 in exclude:
68+
c2 = random.randint(0, upper_bound)
69+
70+
if c2 < c1:
71+
c1, c2 = c2, c1
72+
73+
perm_range = perm[c1:c2]
74+
perm_range.reverse()
75+
perm[c1:c2] = perm_range
76+
77+
return perm
7878

7979
#FIXME modifying and returning an argument?
8080
def local_search(best, cities, max_no_improv):
81-
count = 0
82-
83-
while count < max_no_improv:
84-
candidate = {}
85-
candidate["vector"] = stochastic_two_opt(best["vector"])
86-
candidate["cost"] = cost(candidate["vector"], cities)
87-
88-
if candidate["cost"] < best["cost"]:
89-
count = 0
90-
else:
91-
count += 1
92-
93-
if candidate["cost"] < best["cost"]:
94-
best = candidate
95-
96-
return best
81+
count = 0
82+
83+
while count < max_no_improv:
84+
candidate = {}
85+
candidate["vector"] = stochastic_two_opt(best["vector"])
86+
candidate["cost"] = cost(candidate["vector"], cities)
87+
88+
if candidate["cost"] < best["cost"]:
89+
count = 0
90+
else:
91+
count += 1
92+
93+
if candidate["cost"] < best["cost"]:
94+
best = candidate
95+
96+
return best
9797

98-
def double_bridge_move(perm):
99-
pos1 = 1 + random.randint(0, math.floor(len(perm) / 4))
100-
pos2 = pos1 + 1 + random.randint(0, math.floor(len(perm) / 4))
101-
pos3 = pos2 + 1 + random.randint(0, math.floor(len(perm) / 4))
102-
p1 = perm[0:pos1] + perm[pos3:len(perm)]
103-
p2 = perm[pos2:pos3] + perm[pos1:pos2]
104-
return p1 + p2
98+
def double_bridge_move(perm):
99+
pos1 = 1 + random.randint(0, math.floor(len(perm) / 4))
100+
pos2 = pos1 + 1 + random.randint(0, math.floor(len(perm) / 4))
101+
pos3 = pos2 + 1 + random.randint(0, math.floor(len(perm) / 4))
102+
p1 = perm[0:pos1] + perm[pos3:len(perm)]
103+
p2 = perm[pos2:pos3] + perm[pos1:pos2]
104+
return p1 + p2
105105

106106
def perturbation(cities, best):
107-
candidate = {}
108-
candidate["vector"] = double_bridge_move(best["vector"])
109-
candidate["cost"] = cost(candidate["vector"], cities)
110-
return candidate
107+
candidate = {}
108+
candidate["vector"] = double_bridge_move(best["vector"])
109+
candidate["cost"] = cost(candidate["vector"], cities)
110+
return candidate
111111

112112
def search(cities, max_iterations, max_no_improv):
113-
best = {}
114-
best["vector"] = random_permutation(cities)
115-
best["cost"] = cost(best["vector"], cities)
116-
best = local_search(best, cities, max_no_improv)
117-
118-
for i in range(max_iterations):
119-
candidate = perturbation(cities, best)
120-
candidate = local_search(candidate, cities, max_no_improv)
121-
122-
if candidate["cost"] < best["cost"]:
123-
best = candidate
124-
125-
print("Iteration #" + str(i) + " best = " + str(best["cost"]))
126-
127-
return best
113+
best = {}
114+
best["vector"] = random_permutation(cities)
115+
best["cost"] = cost(best["vector"], cities)
116+
best = local_search(best, cities, max_no_improv)
117+
118+
for i in range(max_iterations):
119+
candidate = perturbation(cities, best)
120+
candidate = local_search(candidate, cities, max_no_improv)
121+
122+
if candidate["cost"] < best["cost"]:
123+
best = candidate
124+
125+
print("Iteration #" + str(i) + " best = " + str(best["cost"]))
126+
127+
return best
128128

129129
if __name__ == "__main__":
130-
# Problem configuration
131-
berlin52 = [[565,575],[25,185],[345,750],[945,685],[845,655],
132-
[880,660],[25,230],[525,1000],[580,1175],[650,1130],[1605,620],
133-
[1220,580],[1465,200],[1530,5],[845,680],[725,370],[145,665],
134-
[415,635],[510,875],[560,365],[300,465],[520,585],[480,415],
135-
[835,625],[975,580],[1215,245],[1320,315],[1250,400],[660,180],
136-
[410,250],[420,555],[575,665],[1150,1160],[700,580],[685,595],
137-
[685,610],[770,610],[795,645],[720,635],[760,650],[475,960],
138-
[95,260],[875,920],[700,500],[555,815],[830,485],[1170,65],
139-
[830,610],[605,625],[595,360],[1340,725],[1740,245]]
140-
141-
# Algorithm configuration
142-
max_iterations = 100
143-
max_no_improv = 50
144-
145-
# Execute the algorithm
146-
best = search(berlin52, max_iterations, max_no_improv)
147-
print("Done. Best solution: c = " + str(best["cost"]) +", v = " + str(best["vector"]))
130+
# Problem configuration
131+
berlin52 = [[565,575],[25,185],[345,750],[945,685],[845,655],
132+
[880,660],[25,230],[525,1000],[580,1175],[650,1130],[1605,620],
133+
[1220,580],[1465,200],[1530,5],[845,680],[725,370],[145,665],
134+
[415,635],[510,875],[560,365],[300,465],[520,585],[480,415],
135+
[835,625],[975,580],[1215,245],[1320,315],[1250,400],[660,180],
136+
[410,250],[420,555],[575,665],[1150,1160],[700,580],[685,595],
137+
[685,610],[770,610],[795,645],[720,635],[760,650],[475,960],
138+
[95,260],[875,920],[700,500],[555,815],[830,485],[1170,65],
139+
[830,610],[605,625],[595,360],[1340,725],[1740,245]]
140+
141+
# Algorithm configuration
142+
max_iterations = 100
143+
max_no_improv = 50
144+
145+
# Execute the algorithm
146+
best = search(berlin52, max_iterations, max_no_improv)
147+
print("Done. Best solution: c = " + str(best["cost"]) +", v = " + str(best["vector"]))

python/2_Stochastic_Algorithms/random_search_tests.py

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,33 @@
55
import unittest
66

77
class RandomSearchTests(unittest.TestCase):
8-
"""
9-
Unit tests for functions in random_search.py .
10-
"""
11-
12-
def test_objective_function(self):
13-
#integer
14-
self.assertEqual(99**2, rs.objective_function([99]))
15-
#float
16-
self.assertEqual(0.1**2.0, rs.objective_function([0.1]))
17-
#vector
18-
self.assertEqual((1**2) + (2**2) + (3**2), rs.objective_function([1,2,3]))
19-
20-
def test_random_vector(self):
21-
bounds, trials, size = [-3, 3], 300, 20
22-
minmax = [bounds for i in range(size)]
23-
24-
for i in range(trials):
25-
vector, total = rs.random_vector(minmax), 0.0
26-
self.assertEqual(size, len(vector))
27-
28-
for v in vector:
29-
self.assertTrue(v >= bounds[0])
30-
self.assertTrue(v < bounds[1])
31-
total += v
32-
33-
#TODO: test with total
8+
"""
9+
Unit tests for functions in random_search.py .
10+
"""
11+
12+
def test_objective_function(self):
13+
#integer
14+
self.assertEqual(99**2, rs.objective_function([99]))
15+
#float
16+
self.assertEqual(0.1**2.0, rs.objective_function([0.1]))
17+
#vector
18+
self.assertEqual((1**2) + (2**2) + (3**2), rs.objective_function([1,2,3]))
19+
20+
def test_random_vector(self):
21+
bounds, trials, size = [-3, 3], 300, 20
22+
minmax = [bounds for i in range(size)]
23+
24+
for i in range(trials):
25+
vector, total = rs.random_vector(minmax), 0.0
26+
self.assertEqual(size, len(vector))
27+
28+
for v in vector:
29+
self.assertTrue(v >= bounds[0])
30+
self.assertTrue(v < bounds[1])
31+
total += v
32+
33+
#TODO: test with total
3434

3535
if __name__ == "__main__":
36-
tests = unittest.TestLoader().loadTestsFromTestCase(RandomSearchTests)
37-
unittest.TextTestRunner(verbosity=2).run(tests)
36+
tests = unittest.TestLoader().loadTestsFromTestCase(RandomSearchTests)
37+
unittest.TextTestRunner(verbosity=2).run(tests)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#! /usr/bin/env python3
2+
3+
import math
4+
5+
"""
6+
Not in the original code listing. This factors out the common functions
7+
used in Chapter 2.
8+
"""
9+
10+
def euc_2d(p1, p2):
11+
dx = p1[0] - p2[0]
12+
dy = p1[1] - p2[1]
13+
return math.sqrt((dx ** 2) + (dy ** 2))
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#! /usr/bin/env python3
2+
3+
import stochastic
4+
import unittest
5+
6+
"""
7+
Tests for the base class of Chapter 2: Stochastic Algorithms
8+
"""
9+
10+
class StochasticTests(unittest.TestCase):
11+
12+
def test_euc_2d(self):
13+
self.assertEqual(0, stochastic.euc_2d([0, 0], [0, 0]))
14+
self.assertEqual(0, stochastic.euc_2d([1.1, 1.1], [1.1, 1.1]))
15+
self.assertEqual(1, stochastic.euc_2d([1, 1], [2, 2]))
16+
self.assertEqual(3, stochastic.euc_2d([-1, -1], [1, 1]))
17+
18+
if __name__ == "__main__":
19+
unittest.main()

0 commit comments

Comments
 (0)