def main(): np.random.seed(7890) # recebendo instâncias r = ReadingDatas("dat/p01") r.readFile() # adicionando clientes Customers.addCustomers(r) # for cst in Customers.get_customersList().values(): # print(cst) # adicionando depósitos Depots.addDepots(r) # print("\n\n\n\") # for dpt in Depots.get_depotsList().values(): # print(dpt) # cálculo das distâncias Distances.euclidianDistanceAll(Customers.get_customersList(), Depots.get_depotsList()) # for cst in Customers.get_customersList(): # print(cst) # print(Customers.get_customersList()[cst].get_depotsDistances()) # print("\n\n\n") # for cst in Customers.get_customersList(): # print(cst) # print(Customers.get_customersList()[cst].get_neighborsDistances()) ga = GA() ga.GA()
def GilletJohnson(): SplitDepots._individual = Solution() SplitDepots._availableDepots = [] customersList = copy.deepcopy(csts.get_customersList()) # dicionário for dpt in dpts.get_depotsList(): SplitDepots._availableDepots.append( [dpt, dpts.get_depotsList()[dpt].get_loadTotal(), 0.0, 0] ) # depósito, carga totaL,demanda total atendida,clientes alocados unallocatedCustomers = SplitDepots.GilletJohnsonProcedure( customersList, len(SplitDepots._availableDepots)) # print("verificando") # print(SplitDepots._individual) return SplitDepots._individual
def main(SEED, POP, DESC, PROB_MUT, PROB_LS_POP, PROB_LS, PROB_LSB, PROB_LSBP, GEN_ILS, GEN_ILSA, DATFILE, INSTANCE): # redefinindo variáveis conforme Package Irace # config.FRAC_MAX_DISTRIBUTION = FRAC config.SIZE_POP = POP config.SIZE_DESC = DESC config.PROB_MUTATION = PROB_MUT config.PROB_LS_POP = PROB_LS_POP config.PROB_LS = PROB_LS config.PROB_LS_BEST = PROB_LSB config.PROB_LS_BEST_P = PROB_LSBP config.GEN_ILS = GEN_ILS config.GEN_ILSA = GEN_ILSA seed = SEED timeIni = time.time() # exit(0) # recebendo instâncias r = ReadingDatas(INSTANCE) r.readFile() # adicionando clientes Customers.addCustomers(r) # adicionando depósitos Depots.addDepots(r) # cálculo das distâncias Distances.euclidianDistanceAll(Customers.get_customersList(), Depots.get_depotsList()) ga = GA() best = ga.GA(seed) cost = best.get_cost() timeEnd = (time.time() - timeIni) / 60.0 logging.debug("Melhor indivíduo: %s" % best) logging.debug("tempo total: " + str(timeEnd) + " minutos.") logging.debug("------------fim algoritmo genético-----------") with open(DATFILE, 'w') as f: f.write(str(cost))
def __init__(self): self._giantTour = [] # lista de clientes, cada item um Customer self._routes = [] # lista de Route # self._idRoutes = [] # indicativo da rota self._cost = 0 self._depots = [ ] # lista de depósitos, cada item o Depot de cada cliente self._infeasible = False nRoutesByDepot = [] for dpt in Depots.get_depotsList(): nRoutesByDepot.append((dpt, 0)) # número de rotas por depósitos self._nRoutesByDepot = dict(nRoutesByDepot)
def splitByDepot(listCustomers): customers = list(copy.deepcopy(listCustomers)) depots = dpts.get_depotsList() # dicionário split = [] # cada indice da lista uma subrota SplitDepots._individual = Solution() nDepots = len(depots) base = len(customers) / float(nDepots) maxCustomers = round(config.FRAC_MAX_DISTRIBUTION * base) # print(maxCustomers) # dividir em n grupos de clientes aux = nDepots for n in depots.values(): control = [0, 0] # carregamento, duração tour = [] # se existir cliente não alocado while (control[0] < n.get_loadTotal() and control[1] < n.get_durationTotal()) or aux == 1: if len(customers) == 0 or (aux > 1 and len(tour) >= maxCustomers): break control[0] = control[0] + customers[0].get_demand() control[1] = control[1] + customers[0].get_duration() if (control[0] <= n.get_loadTotal() and control[1] <= n.get_durationTotal()) or aux == 1: tour.append(customers[0]) del customers[0] # atualizar lista else: control[0] = control[0] - customers[0].get_demand() control[1] = control[1] - customers[0].get_duration() break split.append(tour) aux -= 1 # associar o primeiro cliente da subrota ao depósito mais próximo depotsAvailable = list(copy.deepcopy(depots).keys()) for s in split: i = 0 depot = s[0].get_depotsDistances()[i] while str(depot[0]) not in depotsAvailable: i += 1 depot = s[0].get_depotsDistances()[i] for cst in s: SplitDepots._individual.addGiantTour(cst, depots[str(depot[0])]) depotsAvailable.remove(str(depot[0])) return SplitDepots._individual
def calculateCost(self, extraPenalty=0): self._cost = 0.0 depots = Depots.get_depotsList() for r in self._routes: self._cost += r.get_totalCost() # penalidade por excesso de rotas if extraPenalty > 0: self._cost += extraPenalty self._infeasible = True else: # verificar número de rotas por depósito for i in self.get_nRoutesByDepot(): nRoutes = self.get_nRoutesByDepot()[i] nVehicles = depots[i].get_numberVehicles() if nVehicles < nRoutes: # excedente exceed = nRoutes - nVehicles self._cost += exceed * 1000
def removeRoutesEmpty(self): auxRoutes = [] # verificar depósitos com excesso de rotas exceed = [] depots = Depots.get_depotsList() for c in self._nRoutesByDepot: if depots[c].get_numberVehicles() < self._nRoutesByDepot[c]: exceed.append(c) # eliminar rotas vazias for r in self._routes: if r.get_tour(): auxRoutes.append(r) else: # está vazia keyDpt = str(r.get_depot().get_id()) self.decreaseRoute(keyDpt) if keyDpt in exceed and depots[keyDpt].get_numberVehicles( ) >= self._nRoutesByDepot[keyDpt]: self._cost -= 1000 self._routes = auxRoutes
def M10(self, solution): solution1 = copy.deepcopy(solution) depots = dpts.get_depotsList() #escolha da rota routes = solution1.get_routes() idRoute = np.random.randint(len(routes)) route = copy.deepcopy(routes[idRoute]) length = len(route.get_tour()) # comprimento da rota oldDepot = route.get_depot() costWithoutRoute = solution1.get_cost() - route.get_totalCost() penalty = route.get_totalCost() - route.get_costWithoutPenalty() extraPenalty = 0 # print(penalty) cont = 0 bestRoute = copy.deepcopy(route) # print("tamanho de rotas") # print(len(routes)) # print("route") # print(route) if length > 0: route1 = copy.deepcopy(route) #rotação da rota for i in range(length): #rotacionar # print(route1) aux = route1.get_tour()[0] # print(aux) cost = route1.costWithoutNode(0) route1.removeCustomer(aux) route1.set_cost(cost[1], cost[2], cost[3]) cost = route1.costWithNode(aux, length - 1) route1.addCustomer(aux) route1.set_cost(cost[1], cost[2], cost[3]) # print(route1) # print("-----") # verificar se rota gerada é melhor (considerando mesmo depósito) if bestRoute.get_totalCost() > route1.get_totalCost(): extraPenalty = 0 bestRoute = copy.deepcopy(route1) cont = 1 # verificar transferência da rota em outro depósito for dpt in depots.values(): if str(dpt) != str(oldDepot): # verificar rota para o novo depósito tour = route1.get_tour() # tirar o custo associado ao depósito cost1 = route1.get_totalCost() - dist.euclidianDistance(tour[0].get_x_coord(), tour[0].get_y_coord(), oldDepot.get_x_coord(), oldDepot.get_y_coord()) - \ dist.euclidianDistance(tour[length-1].get_x_coord(), tour[length-1].get_y_coord(), oldDepot.get_x_coord(), oldDepot.get_y_coord()) # computar custo com o novo depósito newCost = cost1 + dist.euclidianDistance(tour[0].get_x_coord(), tour[0].get_y_coord(), dpt.get_x_coord(), dpt.get_y_coord()) + \ dist.euclidianDistance(tour[length-1].get_x_coord(), tour[length-1].get_y_coord(), dpt.get_x_coord(), dpt.get_y_coord()) if bestRoute.get_totalCost() > newCost: # verifica número de veículos utilizados pelo depósito nVehicles = 0 for r in solution1.get_routes(): if r.get_depot() == dpt: nVehicles += 1 if nVehicles < dpt.get_numberVehicles(): if (costWithoutRoute + newCost ) < solution1.get_cost(): # é melhor extraPenalty = 0 bestRoute = copy.deepcopy(route1) bestRoute.set_depot(dpt) newCost1 = newCost - penalty bestRoute.set_cost( newCost1, bestRoute.get_totalDemand(), bestRoute.get_totalService()) cont = 1 # else: # if (costWithoutRoute + newCost + 1000) < solution1.get_cost(): # ainda é melhor # extraPenalty = 1000 #penalização por rota a mais # bestRoute.set_depot(dpt) # newCost1 = newCost - penalty # bestRoute.set_cost(newCost1, bestRoute.get_totalDemand(), # bestRoute.get_totalService()) # cont = 1 if cont == 1: # print(penalty) # # print(bestRoute.get_totalCost()) # print(route) # # print("best") # print(bestRoute) solution1.setRoute(bestRoute, idRoute) solution1.formGiantTour() solution1.calculateCost(extraPenalty) return solution1 return solution
def mountRoutes(solution): solution1 = copy.deepcopy(solution) allDepots = dpts.get_depotsList() numberDepots = dpts.get_numberDepots() customers = solution1.get_giantTour() depots = solution1.get_depots() numberVehicles = depots[0].get_numberVehicles() # print("customers: "+str(customers)) # print("deposts: "+str(depots)) # depósitos já vem separados, utilizar heurística de Prins2004 para separar as rotas # separar conjuntos for i in allDepots: depot = allDepots[i] path = [] for j in range(len(customers)): if str(depot.get_id()) == str(depots[j].get_id()): path.append(customers[j]) # print("path: "+str(path)) # gerar rotas para cada caminho # método retorna lista de predecessores pred = SplitAlgorithms.splitRoute(path, depot) # método retorna lista de lista com rotas para um depósito (número máximo de veículos não delimitado) allroutes = SplitAlgorithms.extractVRP(pred, path) # verificar número de rotas formadas routes = [] for l in allroutes: if len(l) > 0: # há rota routes.append(l) # print("routes: "+ str(routes)) # caso tenha mais rotas que veículos if len(routes) > numberVehicles: # ordenada em ordem crescente de demanda routes = sorted(routes, key=lambda x: x[1]) # juntar rotas com menor demanda aux = len(routes) - numberVehicles while aux > 0: r0 = routes[0][0] r1 = routes[1][0] r0 = r0 + r1 demand = routes[0][1] + routes[1][1] routes[0] = [r0, demand] del routes[1] # ordenada em ordem crescente de demanda routes = sorted(routes, key=lambda x: x[1]) aux -= 1 k = -1 for l in routes: route = Route(depot) if len(l) > 0: for m in l[0]: route.addCustomer(m) k += 1 # calcular custo da rota formada route.startValues() route.calculeCost() solution1.addRoutes(route) solution1.formGiantTour() solution1.calculateCost() # print(solution1) return solution1
def splitLinearBounded(solution): solution1 = copy.deepcopy(solution) solution2 = copy.deepcopy(solution) depotsList = dpts.get_depotsList() customers = solution1.get_giantTour() depots = solution1.get_depots() for dpt in depotsList: listCst = [] depot = depotsList[dpt] for j in range(len(customers)): if dpt == str(depots[j].get_id()): listCst.append(customers[j]) sumDistance = [0.0 for x in range(len(listCst) + 1)] sumLoad = [0.0 for x in range(len(listCst) + 1)] sumDistance[0] = 0 # distancia do depósito # distância do depósito ao primeiro nó sumDistance[1] = dist.euclidianDistance(listCst[0].get_x_coord(), listCst[0].get_y_coord(), depot.get_x_coord(), depot.get_y_coord()) sumLoad[0] = 0 sumLoad[1] = customers[0].get_demand() # inicializar com o somatório distancia de i-1 a i e a demanda de i-1 a i for i in range(2, len(listCst) + 1): sumDistance[i] = sumDistance[i - 1] + dist.euclidianDistance( listCst[i - 2].get_x_coord(), listCst[i - 2].get_y_coord(), listCst[i - 1].get_x_coord(), listCst[i - 1].get_y_coord()) sumLoad[i] = sumLoad[i - 1] + listCst[i - 1].get_demand() potential = [] pred = [] for k in range(depot.get_numberVehicles() + 1): potential.append([1.e30 for x in range(len(listCst) + 1)]) pred.append([-1 for x in range(len(listCst) + 1)]) potential[0][0] = 0 for k in range(depot.get_numberVehicles()): queue = [k] i = k + 1 while (i <= len(listCst)) and (len(queue) > 0): # o primeiro da fila será o melhor predecessor de i potential[k + 1][i] = SplitAlgorithms.propagatek( queue[0], i, k, listCst, sumDistance, potential, depot) # calcula custo de i a j pred[k + 1][i] = queue[0] # se i não é dominado pelo último da pilha if i < len(listCst): if not (SplitAlgorithms.dominatesk( queue[len(queue) - 1], i, k, listCst, sumDistance, potential, sumLoad, depot)): # então i será inserido, precisando remover quem ele domina while len( queue ) > 0 and SplitAlgorithms.dominatesRightk( queue[len(queue) - 1], i, k, listCst, sumDistance, potential, depot): del queue[len(queue) - 1] queue.append(i) # Verifica se a frente consegue chegar ao próximo nó, caso contrário ele desaparecerá. while len(queue) > 0 and ( sumLoad[i + 1] - sumLoad[queue[0]]) > ( depot.get_loadVehicle() + 0.0001): del queue[0] i += 1 if potential[depot.get_numberVehicles()][len(listCst)] > 1.e29: # print("ERRO: nenhuma solução de divisão foi propagada até o último nó") del solution1 return SplitAlgorithms.mountRoutes(solution2) else: # achando o número ótimo de rotas minCost = 1.e30 nRoutes = 0 for k in range(1, depot.get_numberVehicles() + 1): if potential[k][len(listCst)] < minCost: minCost = potential[k][len(listCst)] # print("minCost "+str(minCost)) nRoutes = k cour = len(listCst) for i in range(nRoutes - 1, -1, -1): route = Route(depot) j = pred[i + 1][cour] for k in range(j + 1, cour + 1): route.addCustomer(listCst[k - 1]) cour = j # calcular custo da rota formada route.startValues() route.calculeCost() solution1.addRoutes(route) solution1.formGiantTour() solution1.calculateCost() # print(solution) return solution1
def splitLinear(solution, limitRoutes=True): solution1 = copy.deepcopy(solution) depotsList = dpts.get_depotsList() customers = solution1.get_giantTour() depots = solution1.get_depots() penalty = 0.0 for dpt in depotsList: listCst = [] depot = depotsList[dpt] for j in range(len(customers)): if dpt == str(depots[j].get_id()): listCst.append(customers[j]) lenListCst = len(listCst) sumDistance = [] sumLoad = [] potential = [] pred = [] for x in range(lenListCst + 1): sumDistance.append(0.0) sumLoad.append(0.0) potential.append(1.e30) pred.append(-1) sumDistance[0] = 0 # distancia do depósito # distância do depósito ao primeiro nó sumDistance[1] = dist.euclidianDistance(listCst[0].get_x_coord(), listCst[0].get_y_coord(), depot.get_x_coord(), depot.get_y_coord()) sumLoad[0] = 0 sumLoad[1] = customers[0].get_demand() potential[0] = 0 # inicializar com o somatório distancia de i-1 a i e a demanda de i-1 a i for i in range(2, lenListCst + 1): sumDistance[i] = sumDistance[i - 1] + dist.euclidianDistance( listCst[i - 2].get_x_coord(), listCst[i - 2].get_y_coord(), listCst[i - 1].get_x_coord(), listCst[i - 1].get_y_coord()) sumLoad[i] = sumLoad[i - 1] + listCst[i - 1].get_demand() queue = [0] for i in range(1, lenListCst + 1): # da frente é o melhor predecessor de 1 potential[i] = SplitAlgorithms.propagate( queue[0], i, listCst, sumDistance, potential, depot) pred[i] = queue[0] if i < lenListCst: # se i não é dominado pelo último da pilha if not SplitAlgorithms.dominates( queue[len(queue) - 1], i, listCst, sumDistance, potential, sumLoad, depot): # então i será inserido, precisando remover quem ele domina while len( queue) > 0 and SplitAlgorithms.dominatesRight( queue[len(queue) - 1], i, listCst, sumDistance, potential, depot): del queue[len(queue) - 1] queue.append(i) # Verifica se a frente consegue chegar ao próximo nó, caso contrário ele desaparecerá. while len(queue) > 0 and (sumLoad[i + 1] - sumLoad[ queue[0]]) > (depot.get_loadVehicle() + 0.0001): del queue[0] if potential[len(listCst)] > 1.e29: print( "ERRO: nenhuma solução de divisão foi propagada até o último nó" ) exit(1) else: # achando o número ótimo de rotas minCost = 1.e30 nRoutes = 0 cour = lenListCst while cour > 0: cour = pred[cour] nRoutes += 1 cour = len(listCst) # print(listCst) # print(pred) # print(cour) trip = [] for i in range(nRoutes - 1, -1, -1): t = [] j = pred[cour] load = 0 for k in range(j + 1, cour + 1): t.append(listCst[k - 1]) load += listCst[k - 1].get_demand() cour = j trip.append([t, load]) # se o número de rotas formadas for maior que o número de veículos, juntar as de menor demanda numberVehicles = depot.get_numberVehicles() if nRoutes > numberVehicles: # ordenada em ordem crescente de demanda trip = sorted(trip, key=lambda x: x[1]) # juntar rotas com menor demanda aux = len(trip) - numberVehicles aux1 = aux if limitRoutes: while aux > 0: r0 = trip[0][0] r1 = trip[1][0] r0 = r0 + r1 demand = trip[0][1] + trip[1][1] trip[0] = [r0, demand] del trip[1] # ordenada em ordem crescente de demanda trip = sorted(trip, key=lambda x: x[1]) aux -= 1 else: penalty += 1000 * aux1 # adicionar rotas a solucao for r in trip: route = Route(depot) # print("r") # print(r) for c in r[0]: # print("c") # print(c) route.addCustomer(c) # calcular custo da rota formada route.startValues() route.calculeCost() solution1.addRoutes(route) solution1.formGiantTour() solution1.calculateCost(penalty) # print(solution1.get_routes()) # exit(1) return solution1
def randomDistribution(): #print('Entrou aqui') #np.random.seed(idum) SplitDepots._individual = Solution() customersList = copy.deepcopy(csts.get_customersList()) # dicionário # lista com as chaves dos clientes keysCst = list(customersList.keys()) depots = dpts.get_depotsList() # dicionário nDepots = len(depots) base = len(customersList) / float(nDepots) maxCustomers = round(config.FRAC_MAX_DISTRIBUTION * base) nCustomers = len(keysCst) solution = {} # (depósito, [total de demanda, número de clientes alocados] control = {} for depot in depots: control[depot] = [0, 0] while nCustomers > 0: # enquanto tiver cliente não alocado # cliente aleatório idCst = np.random.randint(0, len(keysCst)) customer = customersList[keysCst[idCst]] # depósito mais próximo i = 0 dpt = customer.get_depotsDistances()[i] cont = len(customer.get_depotsDistances()) aux = 0 while (control[str(dpt[0])][0] >= depots[str(dpt[0])].get_loadTotal() + 0.0001 or (cont > 1 and control[str(dpt[0])][1] > maxCustomers)) and cont > 0: if cont == 1: aux = 1 # indica que todos os depósitos anteriores estão lotados i += 1 dpt = customer.get_depotsDistances()[i] cont -= 1 depot = depots[str(dpt[0])] control[str( dpt[0])][0] = control[str(dpt[0])][0] + customer.get_demand() control[str(dpt[0])][1] = control[str(dpt[0])][1] + 1 # adicionar cliente ao depósito SplitDepots._individual.addGiantTour(customer, depot) del keysCst[idCst] # atualizar lista nCustomers -= 1 # escolher três clientes aleatórios if len(keysCst) > 0: idcst1 = np.random.randint(0, len(keysCst)) neighbor1 = customersList[keysCst[idcst1]] dist1 = dist.euclidianDistance(customer.get_x_coord(), customer.get_y_coord(), neighbor1.get_x_coord(), neighbor1.get_y_coord()) idcst2 = np.random.randint(0, len(keysCst)) neighbor2 = customersList[keysCst[idcst2]] dist2 = dist.euclidianDistance(customer.get_x_coord(), customer.get_y_coord(), neighbor2.get_x_coord(), neighbor2.get_y_coord()) idcst3 = np.random.randint(0, len(keysCst)) neighbor3 = customersList[keysCst[idcst3]] dist3 = dist1 = dist.euclidianDistance(customer.get_x_coord(), customer.get_y_coord(), neighbor3.get_x_coord(), neighbor3.get_y_coord()) # ver o mais próximo ao cliente if dist1 <= dist2 and dist1 <= dist3: close = neighbor1 id = idcst1 elif dist2 <= dist1 and dist2 <= dist3: close = neighbor2 id = idcst2 else: close = neighbor3 id = idcst3 control[str( dpt[0])][0] = control[str(dpt[0])][0] + close.get_demand() control[str(dpt[0])][1] = control[str(dpt[0])][1] + 1 if (control[str(dpt[0])][0] <= depot.get_loadTotal() + 0.0001 and control[str(dpt[0])][1] <= maxCustomers) or aux == 1: # adicionar vizinho mais próximo a solução SplitDepots._individual.addGiantTour(close, depot) del keysCst[id] # atualizar lista nCustomers -= 1 else: control[str(dpt[0])][0] = control[str( dpt[0])][0] - close.get_demand() control[str(dpt[0])][1] = control[str(dpt[0])][1] - 1 # print(self._individual.get_giantTour()) # print(SplitDepots._individual.get_depots()) return SplitDepots._individual
def GilletJohnsonProcedure(customersList, nDepotsAvailable): unallocatedCustomers = customersList numberDepotsAvailable = nDepotsAvailable depots = dpts.get_depotsList() auxiliar = [] base = len(csts.get_customersList()) / float(len(depots)) maxCustomers = round(config.FRAC_MAX_DISTRIBUTION * base) # print("maxCustomers:") # print(maxCustomers) # print(unallocatedCustomers) for cst in unallocatedCustomers: depotsDistances = unallocatedCustomers[cst].get_depotsDistances() depotsAvailable = [] # recuperar apenas depósitos com vagas for dptDist in depotsDistances: for adpts in SplitDepots._availableDepots: if str(dptDist[0]) == adpts[0]: depotsAvailable.append(dptDist) break # print("saiu do for") # print(depotsAvailable) if len(depotsAvailable) > 1: fstDepot = depotsAvailable[0] # primeiro depósito mais próximo sndDepot = depotsAvailable[1] # segundo depósito mais próximo fstDistance = fstDepot[1] # distância do primeiro depósito sndDistance = sndDepot[1] # distância do segundo depósito ratio = fstDistance / float(sndDistance) auxiliar.append( [unallocatedCustomers[cst], ratio, str(fstDepot[0])]) elif len(depotsAvailable) == 1: fstDepot = depotsAvailable[0] # primeiro depósito mais próximo ratio = 1.0 auxiliar.append( [unallocatedCustomers[cst], ratio, str(fstDepot[0])]) # print("check") # print(unallocatedCustomers[cst]) # ordenar lista auxiliar em ordem decrescente pts = sorted(auxiliar, key=lambda x: x[1], reverse=True) # print("pts:") # print(pts) # print(SplitDepots._individual) for dpt in SplitDepots._availableDepots: control = 0 for pt in pts: # print(pt) if dpt[0] == pt[2]: dpt[2] = dpt[2] + pt[0].get_demand() dpt[3] = dpt[3] + 1 # demanda total > carga total (considera cheio) if (dpt[2] > dpt[1] or dpt[3] > maxCustomers): if numberDepotsAvailable > 1: dpt[2] = dpt[2] - pt[0].get_demand() dpt[3] = dpt[3] - 1 dpt[0] = "-1" numberDepotsAvailable -= 1 #print("é menor") else: # se ainda faltarem clientes para serem alocados e restar apenas 1 depósito, a carga total será desrespeitada #print("último depósito disponível") # print(SplitDepots._availableDepots) # adiciona o cliente no depósito mais próximo SplitDepots._individual.addGiantTour( pt[0], depots[dpt[0]]) # remove da lista de unallocatedCustomers unallocatedCustomers.pop(str(pt[0].get_id()), -1) control += 1 else: # adiciona o cliente no depósito mais próximo SplitDepots._individual.addGiantTour( pt[0], depots[dpt[0]]) # remove da lista de unallocatedCustomers unallocatedCustomers.pop(str(pt[0].get_id()), -1) control += 1 # print(":") # print(SplitDepots._availableDepots) # print(unallocatedCustomers) # print(SplitDepots._availableDepots) if len(unallocatedCustomers) > 0: return SplitDepots.GilletJohnsonProcedure(unallocatedCustomers, numberDepotsAvailable) else: return unallocatedCustomers