def FisherJaikumar_Routing_Dijkastra(graph, clusterAssignment, k_clusters, saveFolder): finalRoutes = [] demand = graph.getDemand() priorityQ = [] for k in range(len(k_clusters)): cluster = [] routes = [] for i in range(len(clusterAssignment)): if (clusterAssignment[i] == k): cluster.append(i + 1) for node in cluster: nodeRoute = Route(graph.getCapacity()) nodeRoute.addCustomer(0, demand[0], False) nodeRoute.addCustomer(node, demand[node], False) nodeRoute.setCost(graph.getValue(0, node)) priorityQ.append(nodeRoute) priorityQ.sort(key=lambda x: x.getCost(), reverse=True) while len(priorityQ) > 0: shortRoute = priorityQ.pop() prevNode = shortRoute.getCustomers()[len(shortRoute.getCustomers()) - 1] appoCluster = [] for v in cluster: if v != prevNode: if (shortRoute.checkCustomer(v) == -1): appoCluster.append(v) if len(appoCluster) > 0: index, value = graph.getNearestNeighbours( prevNode, appoCluster) costToAdd = shortRoute.getCost() + value shortRoute.setCost(costToAdd) control = shortRoute.addCustomer(appoCluster[index], demand[appoCluster[index]], False) if (control == -1): print("fail") priorityQ.append(shortRoute) priorityQ.sort(key=lambda x: x.getCost(), reverse=True) else: value = graph.getValue(prevNode, 0) costToAdd = shortRoute.getCost() + value shortRoute.setCost(costToAdd) shortRoute.addCustomer(0, 0, False) routes.append(shortRoute) routes.sort(key=lambda x: x.getCost(), reverse=True) route = routes.pop() route.printRoute("Route") finalRoutes.append(route) return finalRoutes
def FisherJaikumar_Routing(graph, clusterAssignment, k_clusters, saveFolder): routes = [] demand = graph.getDemand() capacity = graph.getCapacity() for k in range(len(k_clusters)): cluster = [] for i in range(len(clusterAssignment)): if (clusterAssignment[i] == k): cluster.append(i + 1) appoRoute = Route(capacity) appoRoute.addCustomer(0, 0, False) while (len(cluster) > 0): prevnode = appoRoute.getCustomers()[len(appoRoute.getCustomers()) - 1] distPrevNode = graph.getValue(prevnode, [c for c in cluster]) nearestN = cluster[np.argmin(distPrevNode)] if nearestN not in appoRoute.getCustomers(): appoRoute.addCustomer(nearestN, demand[nearestN], False) cluster.remove(nearestN) appoRoute.addCustomer(0, 0, False) appoRoute.printRoute("Route cluster:" + str(k)) routes.append(appoRoute) return routes
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 Crossover(winner1, winner2, graph: cvrpGraph, tabuSearch: bool = False, tabuLister: list = []): demand = graph.getDemand() capacity = graph.getCapacity() tabuList = tabuLister winner1Sequence = [] winner2Sequence = [] child1 = [] child2 = [] solution1 = [] solution2 = [] winner1Sequence += [p.getCustomers() for p in winner1] winner1Sequence = [y for x in winner1Sequence for y in x if y != 0] winner2Sequence += [p.getCustomers() for p in winner2] winner2Sequence = [y for x in winner2Sequence for y in x if y != 0] crossover_point1 = np.random.randint(int(len(winner1Sequence) / 4), (int(len(winner1Sequence) / 2))) crossover_point2 = np.random.randint( int(len(winner1Sequence) / 2), (int(len(winner1Sequence) / 2) + int(len(winner1Sequence) / 4))) #Form child one List for node in (winner1Sequence[crossover_point1:crossover_point2]): if node not in child1 and node != 0: child1.append(node) for node in (winner2Sequence[crossover_point2:]): if node not in child1 and node != 0: child1.append(node) for node in (winner2Sequence[:crossover_point2]): if node not in child1 and node != 0: child1.insert(0, node) #Build and check the child one Route i = 0 while (i < len(child1)): route = Route(capacity) cost = 0 route.setCost(0) route.addCustomer(0, demand[0], False) for node in child1[i:]: i = i + 1 if (route.addCustomer(node, demand[node], False) < 0): if (route.checkCustomer(node) == -1): route.addCustomer(0, demand[0], False) i = i - 1 break if (len(child1) == i): route.addCustomer(0, demand[0], False) for n in range(len(route.getCustomers()) - 1): cost += graph.getValue(route.getCustomers()[n], route.getCustomers()[n + 1]) route.setCost(cost) solution1.append(route) #Form child two List for node2 in (winner2Sequence[crossover_point1:crossover_point2]): if node2 not in child2 and node2 != 0: child2.append(node2) for node2 in (winner1Sequence[crossover_point2:]): if node2 not in child2 and node2 != 0: child2.append(node2) for node2 in (winner1Sequence[:crossover_point2]): if node2 not in child2 and node2 != 0: child2.append(node2) #Build and check the child one Route i = 0 while (i < len(child2)): route2 = Route(capacity) cost = 0 route2.setCost(0) route2.addCustomer(0, demand[0], True) for node in child2[i:]: i = i + 1 if (route2.addCustomer(node, demand[node], False) < 0): route2.addCustomer(0, demand[0], False) i = i - 1 break if (len(child2) == i): route2.addCustomer(0, demand[0], False) for n in range(len(route2.getCustomers()) - 1): cost += graph.getValue(route2.getCustomers()[n], route2.getCustomers()[n + 1]) route2.setCost(cost) solution2.append(route2) f1 = sum([c.getCost() for c in solution1]) f2 = sum([c.getCost() for c in solution2]) tabuState = [] if (f1 > f2): tabuState = f1 else: tabuState = f2 if (tabuSearch == True and int(tabuState) in tabuList): #print("TABULISTED ==> " +str(int(tabuState))) return Crossover(winner1, winner2, graph, tabuList) else: tabuList.append(int(tabuState)) if (f1 < f2): return solution1, tabuList, f1 else: return solution2, tabuList, f2
def ClusterFirst_RouteSecond(graph, saveFolder): finalRoutes = [] capacity = graph.getCapacity() demand = graph.getDemand() dimension = graph.getDimension() dist = [np.inf for i in range(dimension)] nodeQueue = [] auxGraph = [(i, Route(capacity)) for i in range(dimension)] #Source Node has 0 cost, in this case route Depot - 1- Depot dist[0] = 0 #nodeQueue = [(c+1,dist[c]) for c in range(len(dist))] route = Route(capacity) route.addCustomer(0, demand[0], False) route.addCustomer(1, demand[1], False) route.addCustomer(0, demand[0], False) route.setCost(graph.getValue(0, 1) + graph.getValue(1, 0)) nodeQueue = [(1, route.getCost(), route)] node = 0 nodeQueue.sort(key=lambda x: x[1], reverse=True) while len(nodeQueue) > 0: #Give the node in the auxiliary graph that has low cost nodeToexpand = nodeQueue.pop() node = nodeToexpand[0] cost = nodeToexpand[1] #Give the corresponding route, that contain node #auxGraph.pop() #Create each child of the node in the auxiliary graph for j in range(1, dimension): #j child if (j >= node): newRoute = Route(capacity) newRoute.setCost(0) newRoute.addCustomer(0, demand[0], False) control = -3 #for each child that not exceed the truck capacity for i in range(node, j + 1): #The not is not in the route and it not exceed the truck capacity #Add Node if (newRoute.checkCustomer(i) == -1): control = newRoute.addCustomer(i, demand[i], False) #Update Cost if (control > 0): newRoute.setCost( newRoute.getCost() + graph.getValue( newRoute.getCustomers()[node - i], i)) else: break #Close the route if (control > 0): newRoute.setCost(newRoute.getCost() + graph.getValue(j, 0)) newRoute.addCustomer(0, demand[0], False) if (dist[j] > newRoute.getCost() + cost): dist[j] = newRoute.getCost() + cost nodeQueue.append((j + 1, dist[j], newRoute)) auxGraph[j] = (node - 1, newRoute) nodeQueue.sort(key=lambda x: x[1], reverse=True) else: break u = len(auxGraph) - 1 while (u != 0): node = auxGraph[u] u = node[0] finalRoutes.append(node[1]) return finalRoutes
def Parallel_CW(routes, savings, graph: cvrpGraph): capacity = graph.getCapacity() demand = graph.getDemand() dimension = graph.getDimension() routes = [] for x in range(1, dimension): appoRoute = Route(capacity) appoRoute.addCustomer(x, demand[x], False) routes.append(appoRoute) for save in savings: i = save[1] j = save[2] customerI = -1 customerJ = -1 routeA = -1 routeB = -1 for route in routes: if (-2 < customerI < 0): customerI = route.checkCustomer(i) routeA = route if (-2 < customerJ < 0): customerJ = route.checkCustomer(j) routeB = route # both i and j have been served already, but from different routes, MERGE them if (customerI >= 0 and customerJ >= 0 and routeA != -1 and routeB != -1): if (routes.index(routeA) != routes.index(routeB)): # Does routeA and routeB merge's overload final route if (routeA.getPayload() + routeB.getPayload() <= graph.getCapacity()): #The edge that connect routeA to routeB resides in their heads if (customerI == 0 and customerJ == 0): for customer in routeA.getCustomers(): routeB.addCustomer(customer, demand[customer], True) routes.remove(routeA) #The edge that connect routeA to routeB resides in head of routeA and tail of routeB if (customerI == 0 and customerJ > 0): for customer in routeA.getCustomers(): routeB.addCustomer(customer, demand[customer], False) routes.remove(routeA) #The edge that connect routeA to routeB resides in head of routeB and tail of routeA if (customerI > 0 and customerJ == 0): for customer in routeB.getCustomers(): routeA.addCustomer(customer, demand[customer], False) routes.remove(routeB) #The edge that connect routeA to routeB resides in their tails if (customerI > 0 and customerJ > 0): for customer in reversed(routeB.getCustomers()): routeA.addCustomer(customer, demand[customer], False) routes.remove(routeB) print("Savings number :" + str(savings.index(save))) #savings.remove(save) #If a node is has not been served yet, let's add a route just for it # for node in range(1,graph.getDimension() -1): # checked = False # for r in routes: # if node in r.getCustomers(): # checked = True # if (checked == False): # adhocRoute = Route(graph.getCapacity()) # adhocRoute.addCustomer(node,demand[node],False) # routes.append(adhocRoute) return routes
def Sequential_CW(routes, savings, graph: cvrpGraph): capacity = graph.getCapacity() demand = graph.getDemand() toDo, checked, _ = SearchaAndCompleteSequence(routes, graph, True) #no routes have been created yet while (SearchaAndCompleteSequence(routes, graph) == True and len(savings) > 0): routeSelected = Route(capacity) printable = savings.copy() k = 0 saveNow = savings[0] l = saveNow[1] m = saveNow[2] if ((l not in checked) and (m not in checked) and (len(routeSelected.getCustomers()) == 0)): #No one served i and j so this route will be teh first routeSelected.addCustomer(l, demand[l], True) routeSelected.addCustomer(m, demand[m], False) savings.remove(saveNow) while k < len(savings): save = savings[k] k = k + 1 i = save[1] j = save[2] customerI = -1 customerJ = -1 toprint = save if (toDo == True): #Check if someone alraedy served i and j if ((i not in checked) and (j not in checked)): if (-2 < customerI < 0 and len(routeSelected.getCustomers()) > 0): customerI = routeSelected.checkCustomer(i) if (-2 < customerJ < 0 and len(routeSelected.getCustomers()) > 0): customerJ = routeSelected.checkCustomer(j) # case: i and j have not been served and they are not route first entry #customer i is served from this route but j is not. if (customerI >= 0 and customerJ == -1): if (customerI == 0): control = routeSelected.addCustomer( j, demand[j], True) if (control != -1): savings.remove(save) k = 0 else: control = routeSelected.addCustomer( j, demand[j], False) if (control != -1): savings.remove(save) k = 0 #customer j is served from this route but i is not. if (customerI == -1 and customerJ >= 0): if (customerJ == 0): control = routeSelected.addCustomer( i, demand[i], True) if (control != -1): savings.remove(save) k = 0 else: control = routeSelected.addCustomer( i, demand[i], False) if (control != -1): savings.remove(save) k = 0 print("Savings number :" + str(printable.index(toprint))) routes.append(routeSelected) routeCost = 0 for i in range(len(routeSelected.getCustomers()) - 1): routeCost += graph.getValue( routeSelected.getCustomers()[i], routeSelected.getCustomers()[i + 1]) routeSelected.setCost(routeCost) toDo, checked, _ = SearchaAndCompleteSequence(routes, graph, True) savings.append((float( graph.getValue(i, 0) + graph.getValue(0, j) - routeSelected.getCost()), i, j)) savings.sort(key=lambda x: x[0], reverse=True) else: savings.remove(saveNow) return routes