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
示例#3
0
    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
示例#4
0
    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
示例#5
0
    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