-
Notifications
You must be signed in to change notification settings - Fork 0
/
gbmv_ils.py
316 lines (273 loc) · 12.1 KB
/
gbmv_ils.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
import random
import time
import math
import sys
MAX_TENTATIVAS = 100
MAX_ITERACOES = 10000
INFERIOR = 0
SUPERIOR = 1
TAXA_PERTURBACAO = 0
class Grafo:
def __init__(self):
self.vertices = []
self.arestas = dict()
self.num_vertices = 0
def adiciona_vertice(self, vertice):
self.vertices.append(vertice)
self.num_vertices += 1
def adiciona_aresta(self, vert_origem, vert_destino, peso_aresta):
self.arestas[vert_origem, vert_destino] = peso_aresta
def valor_aresta(self, v_origem, v_destino):
return self.arestas[v_origem, v_destino]
def valor_vertice(self, indice):
return int(self.vertices[indice])
def get_num_vertices(self):
return int(self.num_vertices)
def get_arestas(self):
return self.arestas
def get_vertices(self):
return self.vertices
class Grupo:
def __init__(self, inferior, superior):
self.limites = [inferior, superior]
self.vertices = []
self.valor_total_arestas = 0
self.valor_total_vertices = 0
def adiciona_vertice(self, vertice, arestas, valor_grupo):
for vert in self.vertices:
vert_min = min(vert, vertice)
vert_max = max(vert, vertice)
if (vert_min, vert_max) in arestas:
self.valor_total_arestas += arestas[vert_min, vert_max]
self.valor_total_vertices = valor_grupo
self.vertices.append(vertice)
def remove_vertice(self, vertice, arestas, vertices):
for vert in self.vertices:
vert_min = min(vert, vertice)
vert_max = max(vert, vertice)
if (vert_min, vert_max) in arestas:
self.valor_total_arestas -= arestas[vert_min, vert_max]
self.valor_total_vertices -= vertices[vertice]
self.vertices.remove(vertice)
def get_valor_arestas(self):
return self.valor_total_arestas
def get_valor_vertices(self):
return self.valor_total_vertices
def get_vertices(self):
return self.vertices
def get_limites(self):
return self.limites
def criterio_de_parada(n):
return n <= MAX_ITERACOES
# def busca_completa(grupos, vertices, arestas):
# grupos_solucao = copia_grupos(grupos, vertices, arestas)
# for origem in grupos_solucao:
# for vertice in origem.get_vertices():
# for destino in grupos_solucao
def nova_busca_local(grupos, vertices_arestas):
def busca_local(grupos, vertices, arestas):
inicio_processo = time.time()
grupos_vizinhos = [None]*len(vertices)
pontuacao_maxima = calcula_pontuacao(grupos)
indice_melhor_vizinho = -1
estagnado = False
while not estagnado:
melhora = False
for i in range(len(vertices)):
grupos_vizinhos[i] = gera_nova_solucao(grupos, vertices, arestas)
pontuacao_vizinho = calcula_pontuacao(grupos_vizinhos[i])
if pontuacao_vizinho > pontuacao_maxima:
melhora = True
pontuacao_maxima = pontuacao_vizinho
indice_melhor_vizinho = i
estagnado = not melhora
#print("BUSCA LOCAL DEMOROU: " + str(time.time() - inicio_processo))
return grupos if indice_melhor_vizinho < 0 else grupos_vizinhos[indice_melhor_vizinho]
def gera_nova_solucao(grupos, vertices, arestas):
inicio_processo = time.time()
num_grupos = len(grupos)
num_vertices = len(vertices)
grupos_solucao = copia_grupos(grupos, vertices, arestas)
solucao_valida = False
while not solucao_valida:
grupo_antigo_index = random.randint(0,num_grupos-1)
grupo_antigo = grupos_solucao[grupo_antigo_index]
vertices_grupo_antigo = grupo_antigo.get_vertices()
vertice_random = random.randint(0,len(vertices_grupo_antigo)-1)
vertice_random = vertices_grupo_antigo[vertice_random]
grupo_novo_index = random.randint(0,num_grupos-1)
while grupo_novo_index == grupo_antigo_index:
grupo_novo_index = random.randint(0,num_grupos-1)
grupo_novo = grupos_solucao[grupo_novo_index]
if len(vertices_grupo_antigo) == 1:
break
valor_novo_grupo = grupo_novo.get_valor_vertices() + vertices[vertice_random]
valor_antigo_grupo = grupo_antigo.get_valor_vertices() - vertices[vertice_random]
if valor_antigo_grupo >= grupo_antigo.get_limites()[INFERIOR]:
if valor_novo_grupo <= grupo_novo.get_limites()[SUPERIOR]:
grupo_antigo.remove_vertice(vertice_random, arestas, vertices)
grupo_novo.adiciona_vertice(vertice_random, arestas, valor_novo_grupo)
grupos_solucao[grupo_antigo_index] = grupo_antigo
grupos_solucao[grupo_novo_index] = grupo_novo
solucao_valida = True
#print("GERA NOVA DEMOROU: " + str(time.time() - inicio_processo))
return grupos_solucao
def perturbacao(grupos, vertices, arestas):
num_grupos = len(grupos)
num_vertices = len(vertices)
for i in range(math.floor(TAXA_PERTURBACAO*num_vertices)):
grupos = gera_nova_solucao(grupos, vertices, arestas)
return grupos
def calcula_pontuacao(grupos):
pontuacao = 0
for grupo in grupos:
pontuacao += grupo.get_valor_arestas()
return pontuacao
def grupos_randomicos(vertices, grupos, arestas):
num_grupos = len(grupos)
num_vertices = len(vertices)
grupos_validos = False
tentativas = 0
while not grupos_validos:
tentativas += 1
contador = 0
grupos_auxiliar = copia_grupos(grupos, vertices, arestas)
vertices_usados = []
vertices_tentados = []
valores_grupos = [0]*num_grupos
distribuicao_valida = True
complete = False
for i in range(0, num_grupos):
valor_grupo = 0
while valor_grupo < grupos_auxiliar[i].get_limites()[INFERIOR]:
vertice_random = random.randint(0,num_vertices-1)
while vertice_random in vertices_tentados:
vertice_random = random.randint(0,num_vertices-1)
valor_grupo += vertices[vertice_random]
if valor_grupo <= grupos_auxiliar[i].get_limites()[SUPERIOR]:
grupos_auxiliar[i].adiciona_vertice(vertice_random, arestas, valor_grupo)
vertices_usados.append(vertice_random)
contador += 1
else:
valor_grupo -= vertices[vertice_random]
vertices_tentados.append(vertice_random)
if len(vertices_tentados) == len(vertices) and len(vertices_usados) != len(vertices):
distribuicao_valida = False
break
if len(vertices_usados) == len(vertices):
complete = True
valores_grupos[i] = valor_grupo
if not distribuicao_valida:
break
if distribuicao_valida and not complete:
while len(vertices_usados) < num_vertices:
grupo_random = random.randint(0, num_grupos-1)
while not valores_grupos[grupo_random] < grupos_auxiliar[grupo_random].get_limites()[SUPERIOR]:
grupo_random = random.randint(0, num_grupos-1)
vertice_random = random.randint(0,num_vertices-1)
while vertice_random in vertices_tentados:
vertice_random = random.randint(0,num_vertices-1)
novo_valor_grupo = valores_grupos[grupo_random] + vertices[vertice_random]
if novo_valor_grupo <= grupos_auxiliar[grupo_random].get_limites()[SUPERIOR]:
grupos_auxiliar[grupo_random].adiciona_vertice(vertice_random, arestas, novo_valor_grupo)
vertices_usados.append(vertice_random)
valores_grupos[grupo_random] += vertices[vertice_random]
contador += 1
vertices_tentados.append(vertice_random)
if len(vertices_tentados) == len(vertices) and len(vertices_usados) != len(vertices):
distribuicao_valida = False
break
grupos_validos = distribuicao_valida
if tentativas == MAX_TENTATIVAS:
exit("Arquivo inicial inválido")
return grupos_auxiliar
def formata_linha(linha):
return linha.replace(' \n','')
def processa_arquivo(arq_name):
grafo = Grafo()
with open(arq_name) as arq:
linhas = arq.readlines()
num_vertices, num_grupos = formata_linha(linhas[0]).split(' ')
num_vertices, num_grupos = int(num_vertices), int(num_grupos)
limites = formata_linha(linhas[1]).split(' ')
grupos = []
for i in range(num_grupos):
grupos.append(Grupo(int(limites[2*i]), int(limites[2*i+1])))
vertices = formata_linha(linhas[2]).split(' ')
for vertice in vertices:
if vertice.replace(' ','') != '':
grafo.adiciona_vertice(int(vertice))
for i in range(3, len(linhas)):
linha = linhas[i]
origem, destino, peso = formata_linha(linha).split(' ')
grafo.adiciona_aresta(int(origem), int(destino), float(peso))
return num_vertices, num_grupos, grupos, grafo
def mostra_grupo(grupo):
print("Limites grupo: " + str(grupo.get_limites()))
print("Valor vertices grupo: " + str(grupo.get_valor_vertices()))
print("Vertices: " + str(grupo.get_vertices()))
print("Valor arestas grupo: " + str(grupo.get_valor_arestas()) + str('\n'))
def copia_grupo(grupo, vertices, arestas):
valor_grupo = 0
limites = grupo.get_limites()[:]
vertices_grupo = grupo.get_vertices()[:]
novo_grupo = Grupo(limites[INFERIOR], limites[SUPERIOR])
for vertice in vertices_grupo:
valor_grupo += vertices[vertice]
novo_grupo.adiciona_vertice(vertice, arestas, valor_grupo)
return novo_grupo
def copia_grupos(grupos, vertices, arestas):
num_grupos = len(grupos)
novos_grupos = []
for i in range(num_grupos):
novo_grupo = copia_grupo(grupos[i], vertices, arestas)
novos_grupos.append(novo_grupo)
return novos_grupos
def ILS(grupos, vertices, arestas):
n = 0
n_total = 0
grupos = busca_local(grupos, vertices, arestas)
avaliacao_atual = calcula_pontuacao(grupos)
while(criterio_de_parada(n)):
n_total += 1
novos_grupos = copia_grupos(grupos, vertices, arestas)
novos_grupos = perturbacao(novos_grupos, vertices, arestas)
novos_grupos = busca_local(novos_grupos, vertices, arestas)
avaliacao_nova = calcula_pontuacao(novos_grupos)
if avaliacao_nova > avaliacao_atual:
avaliacao_atual = avaliacao_nova
grupos = copia_grupos(novos_grupos, vertices, arestas)
print('Iteracao ' + str(n_total) + ': ' + str(avaliacao_atual) + ' [estagnado há ' + str(n) + ' its.]')
#print('TEMPO: ' + str(time.time() - inicio))
n = 0
else:
n = n + 1
return grupos
def escreve_csv(arquivo, linha):
with open(arquivo, 'w', newline='') as writeFile:
writer = csv.writer(writeFile, delimiter=' ', quotechar='"', quoting=csv.QUOTE_MINIMAL)
writer.write(linha)
def formata_resultado(grupos):
string_grupos = '['
for grupo in grupos:
string_grupos += str(grupo.get_vertices()) + ','
string_grupos += ']'
string_grupos = string_grupos.replace(',]',']')
return string_grupos
def gbmv_com_isl(instancia):
num_vertices, num_grupos, grupos, grafo = processa_arquivo(instancia)
grupos = grupos_randomicos(grafo.get_vertices(), grupos, grafo.get_arestas())
for grupo in grupos:
mostra_grupo(grupo)
print("\nValor inicial: " + str(calcula_pontuacao(grupos)))
grupos = ILS(grupos, grafo.get_vertices(), grafo.get_arestas())
print(formata_resultado(grupos))
print("\nValor final: " + str(calcula_pontuacao(grupos)))
inicio = time.time()
SEMENTE = int(inicio)
random.seed(SEMENTE)
TAXA_PERTURBACAO = float(sys.argv[2])
gbmv_com_isl(sys.argv[1])
print("SEMENTE: " + str(SEMENTE))
tempo_total = time.time() - inicio
print("TEMPO TOTAL: " + str(tempo_total))