|
23 | 23 | """
|
24 | 24 |
|
25 | 25 | 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)) |
27 | 27 |
|
28 | 28 | 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 |
41 | 41 |
|
42 | 42 | 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 |
50 | 50 |
|
51 | 51 | 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 |
78 | 78 |
|
79 | 79 | #FIXME modifying and returning an argument?
|
80 | 80 | 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 |
97 | 97 |
|
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 |
105 | 105 |
|
106 | 106 | 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 |
111 | 111 |
|
112 | 112 | 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 |
128 | 128 |
|
129 | 129 | 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"])) |
0 commit comments