-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathts.py
executable file
·328 lines (265 loc) · 13 KB
/
ts.py
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
'''
Tabu Search Module
------------------
This file implements the Tabu Search to the modeled problem in the
research.
@author: Italo Campos
Functions
---------
- run : The function that runs the Tabu Search.
'''
from util import tools, models, TabuList
import time, color, pandapower as pp
def run(loops = 10):
''' Runs the Tabu Search
Parameters
----------
loops : int, optional
The number of loops that the Tabu Search should execute. Default is 10.
Returns
-------
list
A list with dicts containing the results and the parameters for each
step of the loop. The dicts has the following form:
{'time': float, # The time elapsed
'best': list, # The best solution found
'total_i': int, # The total iterations
'i_best': int, # The iteration of the best solution
'fault': list, # The list with the fault points
'i_local': int, # The amout of loops of the local search
'itm': int, # The loops for reset the search with ITM
'max_i': # The max loops for stop the search
}
'''
results = list()
for step in range(loops):
print(color.yellow('\n\nLOOP #%d ---------------------------------------------' % (step + 1), 'bold'))
# Extra variables
elapsed_time = 0
# DEFINING GLOBAL VARIABLES AND PARAMETERS --------------
# For single-sourced models, use the lines of code below:
# -------------------------------------------------------
# Getting the test model
#net = models.network33bus()
# Getting the power source name (it works only for one-sourced nets)
#source = net.bus['name'][int(net.ext_grid['bus'])]
# Getting the initial topology
#top = tools.create_topology(net)
# Getting the indexes of the bridge lines between the source (bus0) and
# the first fork
#bridges = tools.bridge_lines(top, source)
# For multiple-sourced models, use the lines of code below:
# ---------------------------------------------------------
net = models.network10bus()
# Defines the power source name
source = 'bus1'
# Creating a multi-sourced topology
top = tools.create_multisourced_topology(net)
# Adding the abstract edges to the topology
top.add_abstract_edge('bus0', 'bus1')
#top.add_abstract_edge('bus1', 'bus2')
# Defining manually the bridge lines according to the model
bridges = [0, 1]
# ---------------------------------------------------------
# The variable that controls the loop
stop = False
# Creating the tabu-list
tabu = TabuList(max_length = int(0.2 * len(net.line))) #int(20% of the number of lines)
# Getting the probability vector for the initial state of the net
prob_vector = tools.get_lines_probability(top, source)
# Defining the fault points
fault = [3]
# Applying the fault points
tools.set_faults(top, fault)
# Limit for voltage variation
#v_variation = 0.18
v_variation = 0.05
# Limit for current variation
i_variation = 0.0
# Best solution (starting with the initial solution)
best = top.get_edge_states()
# Number of solutions generated per iteration
n_solutions = int(0.2 * len(net.line))
# Iteration number (starting with 0)
iteration = 1
# The IT memory
memory = [0 for _ in range(len(net.line))]
# Stores the last iteration that improve the best solution
improved = iteration
# Limiar of frequence that determines if a component will stay in the
# solution after the reset of the search by the ITM
frequence = 0.6
# A flag that indicates if the search was restarted once
reset = False
# The number of max iterations before reset the search with IT memory
max_reset = 25
# Maximum limit of iterations without improvement of the best solution
# found (termination criteria)
max_i = 50
# Maximum iterations to local search
max_local = 10
# -------------------------------------------------------
# MAIN LOOP ---------------------------------------------
print('Starting loop...')
print('Initial solution:', top.get_edge_states())
# Stores the initial time
begin = time.time()
while not stop:
# List of generated neighbors (solutions)
neighbors = list()
# The iteration-selected solution
selected = top.get_edge_states()
# Neighborhood generation ---------------------------
print(color.blue('Iteration #%d' % iteration))
print('Generating neighbors...')
# Making `n_solutions` neihgbors
for k in range(n_solutions):
print(' Generating neighbor %d/%d' % (k+1, n_solutions))
# Generating the neighbor components
sol = list()
for i in range(len(net.line)):
c = selected[i]
if c == 1:
if tools.draw(prob_vector[i]):
c = 0
else:
if tools.draw(0.5):
c = 1
# Making solution
sol.append(c)
# Local search
#print(' Performing local search...')
local_search = [sol] + [tools.swap_1_0(sol.copy()) for _ in range(max_local)]
# Activating the bridge lines and removing fault points
for i in range(len(local_search)):
local_search[i] = tools.set_value(local_search[i], bridges, 1)
local_search[i] = tools.set_value(local_search[i], fault, 0)
#print(' Removing cycles...')
# Removing cycles
for i in range(len(local_search)):
top.set_edge_states(local_search[i])
for cycle in top.cycles(source, search = 'bfs'):
#print(color.magenta(' The topology has cycles. Fixing it...'))
top.deactivate_edge(top.get_edge_index(cycle[0], cycle[1]))
# Update the solution removing its cycles
local_search[i] = top.get_edge_states()
#print(' Running the power flow...')
valid_solutions = list()
for solution in local_search:
# Setting the solution in the network switching
top.set_edge_states(solution)
tools.make_switch_operations(top.get_edge_states(), net)
try:
# Running powerflow
pp.runpp(net)
# Checking voltage constraints
for index, voltage in enumerate(net.res_bus['vm_pu'], start=0):
if abs(1 - voltage) > v_variation: # out of the voltage constraints
#print(color.magenta(' Bus out of voltage contraints. Fixing it...'))
bus = top.get_vertex_name(index)
for adjacent in top.get_adjacent(bus):
top.deactivate_edge(top.get_edge_index(bus, adjacent))
# Passing the topology alterations to the network
tools.make_switch_operations(top.get_edge_states(), net)
# Running the power flow again
pp.runpp(net)
# Checking current constraints
for index, current in enumerate(net.res_line['loading_percent'], start=0):
if current > 100 * (1 + i_variation): # out of the current constraints
#print(color.magenta(' Line out of current limits. Fixing it...'))
top.deactivate_edge(index)
# Saving the generated solution in the valid solution list
valid_solutions.append(top.get_edge_states())
except(pp.powerflow.LoadflowNotConverged):
print(color.red(' ### Power flow not converged. Ignoring the solution.'))
continue
# Getting the best of local search
if valid_solutions != []:
neighbors.append(tools.best_of(valid_solutions, top, source))
# ---------------------------------------------------
# Neighbor selection --------------------------------
print('Selecting the neighbor...')
if neighbors != []:
best_of_iteration = tools.best_of(neighbors, top, source)
while len(neighbors) != 0:
selected = tools.best_of(neighbors, top, source)
neighbors.remove(selected)
if tabu.is_tabu(selected):
print(' TABU: This solution is in tabu list. Applying aspiration criteria...')
# Aspiration criteria
if not tools.draw(0.3):
print(' Result: REFUSED')
continue
print(' Result: ACCEPTED')
if len(neighbors) == 0:
print(' All solutions is in tabu list. Selecting the best found.')
selected = best_of_iteration.copy()
tabu.add(best_of_iteration)
top.set_edge_states(best_of_iteration)
break
tabu.add(selected.copy())
top.set_edge_states(selected)
print(' Solution selected.')
break
else:
# Case no valid solutions were generated, select the same
# previous iteration solution
top.set_edge_states(selected)
# Comparing the selected solution with the best solution found
#print(' Comparing the selected solution with the best solution found...')
if best != []:
sel = tools.best_of([selected, best], top, source)
if sel != best and tools.value_of_solution(selected, net) > tools.value_of_solution(best, net):
print(color.green('IMPROVEMENT: Improving solution at iteration %d.' % iteration, 'bold'))
best = sel.copy()
improved = iteration
else:
best = selected.copy()
# ---------------------------------------------------
# Intermediate-term memory --------------------------
print('Saving the solution in the intermediate-term memory...')
for i in range(len(selected)):
memory[i] += selected[i]
if not reset and iteration - improved >= max_reset:
print(color.yellow('RESETING SEARCH -------------------'))
print('Reseting the search with intermediate-term memory.')
reset = True
mcc = list()
for value in memory:
if value/iteration > frequence:
mcc.append(1)
else:
mcc.append(0)
# Activating the bridge lines and removing fault points
mcc = tools.set_value(mcc, bridges, 1)
mcc = tools.set_value(mcc, fault, 0)
print('Most common components:', mcc)
selected = mcc.copy()
top.set_edge_states(selected)
# ---------------------------------------------------
# Checking termination criteria ---------------------
#print('Selected:', selected)
#print('Best:', best)
iteration += 1
# The TS stops whether it reaches the max iterarion or find a
# optimal solution
if iteration - improved > max_i or tools.value_of_solution(best, net) == len(net.bus.values):
stop = True
elapsed_time = time.time() - begin
print(color.yellow('Elapsed time: %f s' % elapsed_time))
print(color.yellow('Best solution found: %s' % best, 'bold'))
# ---------------------------------------------------
# -------------------------------------------------------
results.append({
'time': elapsed_time,
'best': best,
'total_i': iteration,
'i_best': improved,
'fault': fault,
'i_local': max_local,
'itm': max_reset,
'max_i': max_i,
})
return results
if __name__ == '__main__':
print(run())