|
23 | 23 | """
|
24 | 24 |
|
25 | 25 | 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 |
36 | 36 |
|
37 | 37 | 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 |
67 | 67 |
|
68 | 68 | 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] |
88 | 88 |
|
89 | 89 | 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 |
92 | 92 |
|
93 | 93 | 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 |
113 | 113 |
|
114 | 114 | 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 |
133 | 133 |
|
134 | 134 | 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 |
153 | 153 |
|
154 | 154 | 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 |
172 | 172 |
|
173 | 173 | 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