Exemplo n.º 1
0
Arquivo: CVRP.py Projeto: polakus/mpi
    def __init__(self, M, D, nroV, capac, archivo, solI, tADD, tDROP, tiempo,
                 optimo):
        self._G = Grafo(M, D)  #Grafo original
        self.__S = Solucion(M, D, sum(D))  #Solucion general del CVRP
        self.__Distancias = M  #Mareiz de distancias
        self.__Demandas = D  #Demandas de los clientes
        self.__capacidadMax = capac  #Capacidad max por vehiculo
        self.__rutas = []  #Soluciones por vehiculo (lista de soluciones)
        self.__nroVehiculos = nroV  #Nro de vehiculos disponibles
        self.__tipoSolucionIni = solI  #Tipo de solucion inicial (Clark & Wright, Vecino cercano, Secuencial o al Azar)
        self.__beta = 1  #Parametro de dispersion
        self.__umbralMin = 0  #Umbral de granularidad minimo
        self.__optimosLocales = []  #Lista de optimos locales
        self.__porcentajeParada = 5.0  #Porcentaje de desvio minimo como condicion de parada
        self.__optimo = optimo  #Mejor valor de la instancia
        self.__tenureADD = tADD
        self.__tenureMaxADD = int(tADD * 1.7)
        self.__tenureDROP = tDROP
        self.__tenureMaxDROP = int(tDROP * 1.7)
        self.__txt = clsTxt(str(archivo))
        self.__tiempoMaxEjec = float(tiempo)
        self.escribirDatos()
        self.__S.setCapacidadMax(self.__capacidadMax)
        self.__rutas = self.__S.rutasIniciales(self.__tipoSolucionIni,
                                               self.__nroVehiculos,
                                               self.__Demandas,
                                               self.__capacidadMax)
        self.__S = self.cargaSolucion(self.__rutas)

        self.tabuSearch()
Exemplo n.º 2
0
 def __init__(self, M, D, nroV, capac, solI, tADD, tDROP, tiempo):
     self._G = Grafo(M, D)  #Grafo original
     self.__S = Solucion(M, D, sum(D))  #Solucion general del CVRP
     self.__Distancias = M  #Mareiz de distancias
     self.__Demandas = D  #Demandas de los clientes
     self.__capacidadMax = capac  #Capacidad max por vehiculo
     self.__rutas = []  #Soluciones por vehiculo (lista de soluciones)
     self.__nroVehiculos = nroV  #Nro de vehiculos disponibles
     self.__tipoSolucionIni = solI  #Tipo de solucion inicial (Clark & Wright, Vecino cercano, Secuencial o al Azar)
     self.__beta = 1  #Parametro de dispersion
     self.__umbralMin = 0  #Umbral de granularidad minimo
     self.__optimosLocales = []  #Lista de optimos locales
     self.__tenureADD = tADD
     self.__tenureMaxADD = int(tADD * 1.7)
     self.__tenureDROP = tDROP
     self.__tenureMaxDROP = int(tDROP * 1.7)
     self.__tiempoMaxEjec = float(tiempo)
     self.__S.setCapacidadMax(self.__capacidadMax)
     tiempoIni = time()
     self.__rutas = self.__S.rutasIniciales(self.__tipoSolucionIni,
                                            self.__nroVehiculos,
                                            self.__Demandas,
                                            self.__capacidadMax)
     # print("tiempo solucion inicial: ", time()-tiempoIni)
     self.__tiempoMaxEjec = self.__tiempoMaxEjec - (
         (time() - tiempoIni) / 60)
     tiempoIni = time()
     print("\nSolucion Inicial:")
     self.__S = self.cargaSolucion(self.__rutas)
     print(str(self.__S.getV()))
     # print("tiempo solucion inicial: ", time()-tiempoIni)
     print("Nro vehiculos: ", self.__nroVehiculos)
Exemplo n.º 3
0
    def __init__(self, M, D, nroV, capac, archivo, solI, opt, tADD, tDROP,
                 tiempo, optimo):
        self._G = Grafo(M, D)  #Grafo original
        print(len(M))
        self.__S = Solucion(M, D, sum(D))  #Solucion general del CVRP
        self.__Distancias = M
        self.__Demandas = D  #Demandas de los clientes
        self.__capacidadMax = capac  #Capacidad max por vehiculo
        self.__rutas = []  #Soluciones por vehiculo
        self.__costoTotal = 0
        self.__nroVehiculos = nroV
        self.__tipoSolucionIni = solI
        self.__beta = 1
        self.__optimosLocales = []

        self.__opt = opt
        self.__optimo = optimo
        self.__tenureADD = tADD
        self.__tenureMaxADD = int(tADD * 1.7)
        self.__tenureDROP = tDROP
        self.__tenureMaxDROP = int(tDROP * 1.7)
        self.__txt = clsTxt(str(archivo))
        self.__tiempoMaxEjec = float(tiempo)
        self.__frecMatriz = []

        #Iniciliza una matriz de frecuencias
        for i in range(0, len(self._G.getMatriz())):
            fila = []
            for j in range(0, len(self._G.getMatriz())):
                fila.append(0)
                j
            self.__frecMatriz.append(fila)
            i

        self.escribirDatos()
        self.__S.setCapacidadMax(self.__capacidadMax)
        self.__rutas = self.__S.rutasIniciales(self.__tipoSolucionIni,
                                               self.__nroVehiculos,
                                               self.__Demandas,
                                               self.__capacidadMax)
        self.__S = self.cargaSolucion(self.__rutas)

        print("\nSolucion general:" + str(self.__S))
        self.tabuSearch()
Exemplo n.º 4
0
    def cargaSolucion(self, rutas):
        A = []
        V = []
        S = Solucion(self.__Distancias, self.__Demandas, sum(self.__Demandas))
        cap = 0
        costoTotal = 0
        sol_ini = ""

        #print("+-+-++-+-++-+-++-+-+Rutas+-+-++-+-++-+-++-+-+")
        for i in range(0, len(rutas)):
            s = rutas[i]
            try:
                costoTotal += float(s.getCostoAsociado())
            except AttributeError:
                print("s: " + str(s))
                print("rutas: " + str(rutas))
                print("i: ", i)
                a = 1 / 0
            cap += s.getCapacidad()
            A.extend(s.getA())
            V.extend(s.getV())
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(s.getV())
            #sol_ini+="\nAristas: "+str(s.getA())
            sol_ini += "\nCosto asociado: " + str(
                s.getCostoAsociado()) + "      Capacidad: " + str(
                    s.getCapacidad()) + "\n"
        sol_ini += "\n--> Costo total: " + str(
            costoTotal) + "          Capacidad total: " + str(cap)
        #print(sol_ini)
        # print("+-+-++-+-++-+-++-+-++-+-++-+-++-+-++-+-+")
        S.setA(A)
        S.setV(V)
        costoTotal = round(costoTotal, 3)
        S.setCostoAsociado(costoTotal)
        S.setCapacidad(cap)
        S.setCapacidadMax(self.__capacidadMax)

        return S
Exemplo n.º 5
0
class CVRP:
    #def __init__(self, M, D, nroV, capac, archivo, carpeta, solI, tADD, tDROP, tiempo, porcentaje, optimo):
    def __init__(self, M, D, nroV, capac, solI, tADD, tDROP, tiempo):
        self._G = Grafo(M, D)  #Grafo original
        self.__S = Solucion(M, D, sum(D))  #Solucion general del CVRP
        self.__Distancias = M  #Mareiz de distancias
        self.__Demandas = D  #Demandas de los clientes
        self.__capacidadMax = capac  #Capacidad max por vehiculo
        self.__rutas = []  #Soluciones por vehiculo (lista de soluciones)
        self.__nroVehiculos = nroV  #Nro de vehiculos disponibles
        self.__tipoSolucionIni = solI  #Tipo de solucion inicial (Clark & Wright, Vecino cercano, Secuencial o al Azar)
        self.__beta = 1  #Parametro de dispersion
        self.__umbralMin = 0  #Umbral de granularidad minimo
        self.__optimosLocales = []  #Lista de optimos locales
        self.__tenureADD = tADD
        self.__tenureMaxADD = int(tADD * 1.7)
        self.__tenureDROP = tDROP
        self.__tenureMaxDROP = int(tDROP * 1.7)
        self.__tiempoMaxEjec = float(tiempo)
        self.__S.setCapacidadMax(self.__capacidadMax)
        tiempoIni = time()
        self.__rutas = self.__S.rutasIniciales(self.__tipoSolucionIni,
                                               self.__nroVehiculos,
                                               self.__Demandas,
                                               self.__capacidadMax)
        # print("tiempo solucion inicial: ", time()-tiempoIni)
        self.__tiempoMaxEjec = self.__tiempoMaxEjec - (
            (time() - tiempoIni) / 60)
        tiempoIni = time()
        print("\nSolucion Inicial:")
        self.__S = self.cargaSolucion(self.__rutas)
        print(str(self.__S.getV()))
        # print("tiempo solucion inicial: ", time()-tiempoIni)
        print("Nro vehiculos: ", self.__nroVehiculos)

    #Carga la solucion general a partir de las rutas
    def cargaSolucion(self, rutas):
        A = []
        V = []
        S = Solucion(self.__Distancias, self.__Demandas, sum(self.__Demandas))
        cap = 0
        costoTotal = 0
        sol_ini = ""

        #print("+-+-++-+-++-+-++-+-+Rutas+-+-++-+-++-+-++-+-+")
        for i in range(0, len(rutas)):
            s = rutas[i]
            try:
                costoTotal += float(s.getCostoAsociado())
            except AttributeError:
                print("s: " + str(s))
                print("rutas: " + str(rutas))
                print("i: ", i)
                a = 1 / 0
            cap += s.getCapacidad()
            A.extend(s.getA())
            V.extend(s.getV())
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(s.getV())
            #sol_ini+="\nAristas: "+str(s.getA())
            sol_ini += "\nCosto asociado: " + str(
                s.getCostoAsociado()) + "      Capacidad: " + str(
                    s.getCapacidad()) + "\n"
        sol_ini += "\n--> Costo total: " + str(
            costoTotal) + "          Capacidad total: " + str(cap)
        #print(sol_ini)
        # print("+-+-++-+-++-+-++-+-++-+-++-+-++-+-++-+-+")
        S.setA(A)
        S.setV(V)
        costoTotal = round(costoTotal, 3)
        S.setCostoAsociado(costoTotal)
        S.setCapacidad(cap)
        S.setCapacidadMax(self.__capacidadMax)

        return S

    #Umbral de granularidad: phi = Beta*(c/(n+k))
    #Beta = 1  parametro de dispersion. Sirve para modificar el grafo disperso para incluir la diversificación y la intensificación
    #          durante la búsqueda.
    #c = valor de una sol. inicial
    #k = nro de vehiculos
    #n = nro de clientes
    def calculaUmbral(self, costo):
        c = costo
        k = self.__nroVehiculos
        n = len(self.__Distancias) - 1
        phi = c / (n + k)
        phi = phi * self.__beta
        return round(phi, 3)

    #+-+-+-+-+-+-+- Empezamos con Tabu Search +-+-+-+-+-+-+-+-+#
    #lista_tabu: tiene objetos de la clase Tabu (una arista con su tenure)
    #Lista_permitidos: o grafo disperso tiene elementos del tipo Arista que no estan en la lista tabu y su distancia es menor al umbral
    #nuevas_rutas: nuevas rutas obtenidas a partir de los intercambios
    #nueva_solucion: nueva solucion obtenida a partir de los intercambios
    #rutas_refer: rutas de referencia que sirve principalmente para evitar estancamiento, admitiendo una solucion peor y hacer los intercambios
    #             a partir de esas
    #solucion_refer: idem al anterior
    #tiempoIni: tiempo inicial de ejecucion - tiempoMax: tiempo maximo de ejecucion - tiempoEjecuc: tiempo de ejecución actual
    #iteracEstancamiento: iteraciones de estancamiento para admitir una solución peor, modificar Beta y escapar del estancamiento
    #iterac: cantidad de iteraciones actualmente
    def tabuSearch(self):
        lista_tabu = []
        ind_permitidos = np.array([], dtype=int)
        rutas_refer = copy.deepcopy(self.__rutas)
        nuevas_rutas = rutas_refer
        solucion_refer = copy.deepcopy(self.__S)
        nueva_solucion = solucion_refer
        nuevo_costo = self.__S.getCostoAsociado()

        #Atributos de tiempo e iteraciones
        tiempoIni = time()
        tiempoMax = float(self.__tiempoMaxEjec * 60)
        tiempoEstancamiento = tiempoIni
        tiempoEjecuc = 0
        iteracEstancamiento = 1
        iteracEstancamiento_Opt = 1
        iteracEstancMax = 300
        iterac = 1
        indOptimosLocales = -2
        umbral = self.calculaUmbral(self.__S.getCostoAsociado())
        #porc_Estancamiento = 1.05
        #porc_EstancamientoMax = 1.15
        cond_Optimiz = True
        cond_Estancamiento = False

        Aristas_Opt = np.array([], dtype=object)
        for EP in self._G.getA():
            if (EP.getOrigen().getValue() < EP.getDestino().getValue()
                    and EP.getPeso() <= umbral):
                Aristas_Opt = np.append(Aristas_Opt, EP)
                ind_permitidos = np.append(ind_permitidos, EP.getId())
        Aristas = Aristas_Opt
        ind_AristasOpt = copy.deepcopy(ind_permitidos)

        self.__optimosLocales.append(nuevas_rutas)

        while (tiempoEjecuc < tiempoMax):
            if (cond_Optimiz):
                ind_permitidos, Aristas = self.getPermitidos(
                    Aristas, lista_tabu, umbral, solucion_refer,
                    rutas_refer)  #Lista de elementos que no son tabu
                self.__umbralMin = 0
            cond_Optimiz = False
            ADD = []
            DROP = []

            ind_random = np.arange(0, len(ind_permitidos))
            random.shuffle(ind_random)

            indRutas = indAristas = []
            nuevo_costo, k_Opt, indRutas, indAristas, aristasADD, aristasDROP = nueva_solucion.evaluarOpt(
                self._G.getA(), ind_permitidos, ind_random, rutas_refer,
                cond_Estancamiento)

            nuevo_costo = round(nuevo_costo, 3)

            tenureADD = self.__tenureADD
            tenureDROP = self.__tenureDROP

            costoSolucion = self.__S.getCostoAsociado()

            #Si encontramos una mejor solucion que la tomada como referencia
            if (nuevo_costo < solucion_refer.getCostoAsociado()
                    and aristasADD != []):
                cad = "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Iteracion %d  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n" % (
                    iterac)

                nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0],
                                                   rutas_refer, indRutas,
                                                   indAristas)
                #print("tiempo swap: "+str(time()-tiempo))
                #tiempo = time()
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                #print("tiempo cargaSol: "+str(time()-tiempo))
                if (nuevo_costo != nueva_solucion.getCostoAsociado()):
                    print("\n\nERROR!!!!!!")
                    print("ADD: " + str(aristasADD) + "     DROP: " +
                          str(aristasDROP) + "\n\n")
                    print("nueva solucion:" + str(nueva_solucion.getV()))
                    print("solucion refer:" + str(solucion_refer.getV()))

                    print("\nRutas ahora")
                    for i in range(0, len(rutas_refer)):
                        x = rutas_refer[i]
                        print("ruta #%d: %s" % (i, str(x.getV())))
                    print("nuevo costo: ", nuevo_costo,
                          "          getCostoAsociado: ",
                          nueva_solucion.getCostoAsociado())
                    a = 1 / 0

                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas

                #Si la nueva solucion es mejor que la obtenida hasta el momento
                if (nuevo_costo < costoSolucion):
                    tiempoTotal = time() - tiempoEstancamiento
                    print(cad)
                    cad = "\nLa solución anterior duró " + str(
                        int(tiempoTotal / 60)) + "min " + str(
                            int(tiempoTotal % 60))
                    cad += "seg    -------> Nuevo optimo local. Costo: " + str(
                        nuevo_costo)

                    self.__S = nueva_solucion
                    self.__rutas = nuevas_rutas
                    self.__beta = 1
                    tiempoEstancamiento = time()
                    if (len(self.__optimosLocales) >= 15):
                        self.__optimosLocales.pop(0)
                    self.__optimosLocales.append(nuevas_rutas)
                    indOptimosLocales = -2
                    cond_Estancamiento = False
                    print(cad)
                else:
                    cad += "\nSolucion peor. Costo: " + str(
                        nueva_solucion.getCostoAsociado())
                cad += "\nLista tabu: " + str(lista_tabu)

                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
                tenureADD = self.__tenureMaxADD
                tenureDROP = self.__tenureMaxDROP
                cond_Optimiz = True
                Aristas = Aristas_Opt
                iteracEstancamiento = 1
                iteracEstancamiento_Opt = 1
                iteracEstancMax = 300
            #Si se estancó, tomamos a beta igual a 2
            elif (iteracEstancamiento > iteracEstancMax and self.__beta < 2):
                tiempoTotal = time() - tiempoEstancamiento
                print(
                    "Se estancó durante %d min %d seg. Incrementanos Beta para diversificar"
                    % (int(tiempoTotal / 60), int(tiempoTotal % 60)))
                self.__beta = 2
                self.__umbralMin = umbral
                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
                cond_Optimiz = True
                iteracEstancamiento = 1
                iteracEstancMax = 200
                Aristas = Aristas_Opt
            #Si se estancó nuevamente, tomamos la proxima sol peor que difiera un 5% del optimo o la penultima de los optimos locales
            elif (iteracEstancamiento > iteracEstancMax
                  and len(self.__optimosLocales) >= indOptimosLocales * (-1)):
                nuevas_rutas = self.__optimosLocales[indOptimosLocales]
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                costo = nueva_solucion.getCostoAsociado()
                tiempoTotal = time() - tiempoEstancamiento
                cad = "Se estancó durante %d min %d seg. Admitimos el penultimo optimo local " % (
                    int(tiempoTotal / 60), int(tiempoTotal % 60))
                print(cad + "-->    Costo: " + str(costo))

                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                umbral = self.calculaUmbral(costo)
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                cond_Optimiz = True
                Aristas = Aristas_Opt
                iteracEstancamiento = 1
                indOptimosLocales -= 1
                iteracEstancMax = 100
                self.__beta = 3
            elif (iteracEstancamiento > iteracEstancMax and aristasADD != []):
                print(aristasADD)
                nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0],
                                                   rutas_refer, indRutas,
                                                   indAristas)
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                tiempoTotal = time() - tiempoEstancamiento
                costo = nueva_solucion.getCostoAsociado()
                cad = "Se estancó durante %d min %d seg. Admitimos una solucion peor para diversificar" % (
                    int(tiempoTotal / 60), int(tiempoTotal % 60))
                print(cad + "-->    Costo: " + str(costo))

                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                umbral = self.calculaUmbral(costo)
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                cond_Optimiz = True
                iteracEstancamiento = 1
                Aristas = Aristas_Opt
                iteracEstancMax = 300
            elif (ind_permitidos == []):
                nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0],
                                                   rutas_refer, indRutas,
                                                   indAristas)
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
                cond_Optimiz = True
                self.__beta = 3
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                Aristas = Aristas_Opt
                umbral = self.calculaUmbral(costo)
            else:
                nuevas_rutas = rutas_refer
                nueva_solucion = solucion_refer

            #Añado y elimino de la lista tabu
            if (aristasADD != []):
                ADD.append(Tabu(aristasADD[0], tenureADD))
                for i in range(0, len(aristasDROP)):
                    DROP.append(Tabu(aristasDROP[i], tenureDROP))
                self.decrementaTenure(lista_tabu, ind_permitidos)
                lista_tabu.extend(DROP)
                lista_tabu.extend(ADD)
            else:
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                Aristas = Aristas_Opt
                cond_Optimiz = True

            tiempoEjecuc = time() - tiempoIni
            iterac += 1
            iteracEstancamiento += 1
            iteracEstancamiento_Opt += 1
        #Fin del while. Imprimo los valores obtenidos
        self.escribirDatosFinales(tiempoIni, iterac, tiempoEstancamiento)

        return self.__S.solucionToJSON(), self.__S.getCostoAsociado()

    def getPermitidos(self, Aristas, lista_tabu, umbral, solucion,
                      rutas_refer):
        AristasNuevas = []
        ind_permitidos = np.array([], dtype=int)

        #No tengo en consideracion a las aristas que exceden el umbral y las que pertencen a S
        A_solucion = copy.copy(solucion.getA())
        for EP in Aristas:
            pertS = False
            i = 0
            while (i < len(A_solucion)):
                A_S = A_solucion[i]
                if A_S == EP:
                    A_solucion.pop(i)
                    pertS = True
                    break
                i += 1
            if (not pertS and self.__umbralMin <= EP.getPeso()
                    and EP.getPeso() <= umbral):
                AristasNuevas.append(EP)
                ind_permitidos = np.append(ind_permitidos, EP.getId())
        ind_permitidos = np.unique(ind_permitidos)

        return ind_permitidos, AristasNuevas

    #Decrementa el Tenure en caso de que no sea igual a -1. Si luego de decrementar es 0, lo elimino de la lista tabu
    def decrementaTenure(self, lista_tabu, ind_permitidos):
        i = 0
        while (i < len(lista_tabu)):
            elemTabu = lista_tabu[i]
            elemTabu.decrementaT()
            if (elemTabu.getTenure() == 0):
                ind_permitidos = np.append(ind_permitidos,
                                           elemTabu.getElemento().getId())
                lista_tabu.pop(i)
                i -= 1
            i += 1

    def escribirDatosFinales(self, tiempoIni, iterac, tiempoEstancamiento):
        print("\nMejor solucion obtenida: " + str(self.__rutas) +
              "       costo: " + str(self.__S.getCostoAsociado()))
        tiempoTotal = time() - tiempoIni
        print("\nTermino!! :)")
        print("Tiempo total: " + str(int(tiempoTotal / 60)) + "min " +
              str(int(tiempoTotal % 60)) + "seg\n")
Exemplo n.º 6
0
    def cargaSolucion(self, rutas):
        A = []
        V = []
        S = Solucion(self.__Distancias, self.__Demandas, sum(self.__Demandas))
        cap = 0
        costoTotal = 0
        sol_ini = ""

        for i in range(0, len(rutas)):
            try:
                s = rutas[i]
            except ValueError:
                print("i: " + str(i))
                print("rutas: " + str(s))
            costoTotal += s.getCostoAsociado()
            cap += s.getCapacidad()
            A.extend(s.getA())
            V.extend(s.getV())
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(
                self.__rutas[i].getV())
            sol_ini += "\nCosto asociado: " + str(
                self.__rutas[i].getCostoAsociado(
                )) + "      Capacidad: " + str(
                    self.__rutas[i].getCapacidad()) + "\n"
        sol_ini += "--> Costo total: " + str(
            costoTotal) + "          Capacidad total: " + str(cap)
        #print(sol_ini)
        self.__txt.escribir(sol_ini)
        S.setA(A)
        S.setV(V)
        S.setCostoAsociado(costoTotal)
        S.setCapacidad(cap)
        S.setCapacidadMax(self.__capacidadMax)

        return S
Exemplo n.º 7
0
class CVRP:
    def __init__(self, M, D, nroV, capac, archivo, solI, opt, tADD, tDROP,
                 tiempo, optimo):
        self._G = Grafo(M, D)  #Grafo original
        print(len(M))
        self.__S = Solucion(M, D, sum(D))  #Solucion general del CVRP
        self.__Distancias = M
        self.__Demandas = D  #Demandas de los clientes
        self.__capacidadMax = capac  #Capacidad max por vehiculo
        self.__rutas = []  #Soluciones por vehiculo
        self.__costoTotal = 0
        self.__nroVehiculos = nroV
        self.__tipoSolucionIni = solI
        self.__beta = 1
        self.__optimosLocales = []

        self.__opt = opt
        self.__optimo = optimo
        self.__tenureADD = tADD
        self.__tenureMaxADD = int(tADD * 1.7)
        self.__tenureDROP = tDROP
        self.__tenureMaxDROP = int(tDROP * 1.7)
        self.__txt = clsTxt(str(archivo))
        self.__tiempoMaxEjec = float(tiempo)
        self.__frecMatriz = []

        #Iniciliza una matriz de frecuencias
        for i in range(0, len(self._G.getMatriz())):
            fila = []
            for j in range(0, len(self._G.getMatriz())):
                fila.append(0)
                j
            self.__frecMatriz.append(fila)
            i

        self.escribirDatos()
        self.__S.setCapacidadMax(self.__capacidadMax)
        self.__rutas = self.__S.rutasIniciales(self.__tipoSolucionIni,
                                               self.__nroVehiculos,
                                               self.__Demandas,
                                               self.__capacidadMax)
        self.__S = self.cargaSolucion(self.__rutas)

        print("\nSolucion general:" + str(self.__S))
        self.tabuSearch()

    #Escribe los datos iniciales: el grafo inicial y la demanda
    def escribirDatos(self):
        self.__txt.escribir(
            "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ GRAFO CARGADO +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )
        self.__txt.escribir(str(self._G))
        cad = "\nDemandas:"
        print(cad)
        for v in self._G.getV():
            cad_aux = str(v) + ": " + str(v.getDemanda())
            print(cad_aux)
            cad += "\n" + cad_aux
        self.__txt.escribir(cad)
        print("SumDemanda: ", sum(self.__Demandas))
        print("Nro vehiculos: ", self.__nroVehiculos)
        self.__txt.escribir(
            "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ SOLUCION INICIAL +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )

    #Carga la solucion general a partir de las rutas
    def cargaSolucion(self, rutas):
        A = []
        V = []
        S = Solucion(self.__Distancias, self.__Demandas, sum(self.__Demandas))
        cap = 0
        costoTotal = 0
        sol_ini = ""

        for i in range(0, len(rutas)):
            try:
                s = rutas[i]
            except ValueError:
                print("i: " + str(i))
                print("rutas: " + str(s))
            costoTotal += s.getCostoAsociado()
            cap += s.getCapacidad()
            A.extend(s.getA())
            V.extend(s.getV())
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(
                self.__rutas[i].getV())
            sol_ini += "\nCosto asociado: " + str(
                self.__rutas[i].getCostoAsociado(
                )) + "      Capacidad: " + str(
                    self.__rutas[i].getCapacidad()) + "\n"
        sol_ini += "--> Costo total: " + str(
            costoTotal) + "          Capacidad total: " + str(cap)
        #print(sol_ini)
        self.__txt.escribir(sol_ini)
        S.setA(A)
        S.setV(V)
        S.setCostoAsociado(costoTotal)
        S.setCapacidad(cap)
        S.setCapacidadMax(self.__capacidadMax)

        return S

    def masVisitados(self):
        masVisitada = self.__S.getA()[0]
        for a in self.__S.getA()[1:]:
            if (a.getFrecuencia() > masVisitada.getFrecuencia()):
                masVisitada = a

    #Umbral de granularidad: phi = Beta*(c/(n+k))
    #Beta = 1  parametro de dispersion. Sirve para modificar el grafo disperso para incluir la diversificación y la intensificación
    #          durante la búsqueda.
    #c = valor de una sol. inicial
    #k = nro de vehiculos
    #n = nro de clientes
    def calculaUmbral(self, costo):
        c = costo
        k = self.__nroVehiculos
        n = len(self.__Distancias) - 1
        phi = c / (n + k)
        phi = phi * self.__beta
        return round(phi, 3)

    #+-+-+-+-+-+-+- Empezamos con Tabu Search +-+-+-+-+-+-+-+-+#
    #lista_tabu: tiene objetos de la clase Tabu (una arista con su tenure)
    #Lista_permitidos: o grafo disperso tiene elementos del tipo Arista que no estan en la lista tabu y su distancia es menor al umbral
    #nuevas_rutas: nuevas rutas obtenidas a partir de los intercambios
    #nueva_solucion: nueva solucion obtenida a partir de los intercambios
    #rutas_refer: rutas de referencia que sirve principalmente para evitar estancamiento, admitiendo una solucion peor y hacer los intercambios
    #             a partir de esas
    #solucion_refer: idem al anterior
    #umbral: valor de umbral de granularidad
    #tiempoIni: tiempo inicial de ejecucion - tiempoMax: tiempo maximo de ejecucion - tiempoEjecuc: tiempo de ejecución actual
    #iteracEstancamiento: iteraciones de estancamiento para admitir una solución peor, modificar Beta y escapar del estancamiento
    #iterac: cantidad de iteraciones actualmente
    def tabuSearch(self):
        lista_tabu = []
        lista_permitidos = []
        nuevas_rutas = copy.deepcopy(self.__rutas)
        rutas_refer = copy.deepcopy(nuevas_rutas)
        nueva_solucion = copy.deepcopy(self.__S)
        solucion_refer = copy.deepcopy(nueva_solucion)
        nuevo_costo = self.__S.getCostoAsociado()

        #Atributos de tiempo e iteraciones
        tiempoIni = time()
        tiempoMax = float(self.__tiempoMaxEjec * 60)
        tiempoEstancamiento = tiempoIni
        tiempoEjecuc = 0
        iteracEstancamiento = 1
        iteracEstancamiento_Opt = 1
        iterac = 1
        umbral = self.calculaUmbral(self.__S.getCostoAsociado())

        porc_Estancamiento = 1.05
        porc_EstancamientoMax = 1.2

        cond_2opt = True
        cond_3opt = True
        cond_Optimiz = True

        Aristas_Opt = []
        for EP in self._G.getA():
            if (EP.getOrigen() != EP.getDestino() and EP.getDestino() != 1
                    and EP.getPeso() <= umbral):
                Aristas_Opt.append(EP)
        Aristas = Aristas_Opt

        print("Aplicamos 2-opt")
        while (tiempoEjecuc < tiempoMax):
            timeGrafoDisperso = time()
            lista_permitidos, Aristas = self.getPermitidos(
                Aristas, lista_tabu, umbral, cond_Optimiz,
                solucion_refer)  #Lista de elementos que no son tabu
            #print("tiempo grafo disperso: "+str(time()-timeGrafoDisperso))
            cond_Optimiz = False
            ADD = []
            DROP = []

            ind_random = [x for x in range(0, len(lista_permitidos))]
            random.shuffle(ind_random)

            if (iteracEstancamiento_Opt > 50):
                iteracEstancamiento_Opt = 1
                if (cond_2opt):
                    print("Aplicamos 3-opt")
                    cond_2opt = False
                elif (cond_3opt):
                    print("Aplicamos 4-opt")
                    cond_3opt = False
                else:
                    print("Aplicamos 2-opt")
                    cond_2opt = cond_3opt = True

            timeSwap = time()
            if (cond_2opt):
                nuevas_rutas, aristas_ADD, aristas_DROP, nuevo_costo = nueva_solucion.swap_2opt(
                    lista_permitidos, ind_random, rutas_refer)
            #Para aplicar, cada ruta tiene que tener al menos 3 clientes (o 4 aristas)
            elif (cond_3opt):
                nuevas_rutas, aristas_ADD, aristas_DROP, nuevo_costo = nueva_solucion.swap_3opt(
                    lista_permitidos, ind_random, rutas_refer)
            #Para aplicar, cada ruta tiene que tener al menos 3 clientes (o 4 aristas)
            else:
                nuevas_rutas, aristas_ADD, aristas_DROP, nuevo_costo = nueva_solucion.swap_4opt(
                    lista_permitidos, ind_random, rutas_refer)
            #print("time swap: "+str(time()-timeSwap))

            tenureADD = self.__tenureADD
            tenureDROP = self.__tenureDROP

            costo_sol = self.__S.getCostoAsociado()
            #Si encontramos una mejor solucion que la tomada como referencia
            if (nuevo_costo < solucion_refer.getCostoAsociado()):
                cad = "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Iteracion %d  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n" % (
                    iterac)
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                #Si la nueva solucion es mejor que la obtenida hasta el momento
                if (nueva_solucion.getCostoAsociado() <
                        self.__S.getCostoAsociado()):
                    tiempoTotal = time() - tiempoEstancamiento
                    cad += "\nLa solución anterior duró " + str(
                        int(tiempoTotal / 60)) + "min " + str(
                            int(tiempoTotal % 60))
                    cad += "seg    -------> Nuevo optimo local. Costo: " + str(
                        nueva_solucion.getCostoAsociado())
                    cad += "\nrutas: " + str(nuevas_rutas)
                    print(cad)
                    self.__S = nueva_solucion
                    self.__rutas = nuevas_rutas
                    tiempoEstancamiento = time()
                    self.__beta = 1
                else:
                    cad += "\nNuevo optimo. Costo: " + str(
                        nueva_solucion.getCostoAsociado())
                    print(cad)
                cad += "\nLista tabu: " + str(lista_tabu)
                self.__txt.escribir(cad)
                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
                tenureADD = self.__tenureMaxADD
                tenureDROP = self.__tenureMaxDROP
                cond_Optimiz = True
                Aristas = Aristas_Opt
                iteracEstancamiento = 1
                iteracEstancamiento_Opt = 1
                porc_Estancamiento = 1.05
                porc_EstancamientoMax = 1.2
            #Si se estancó, tomamos la proxima solución peor que difiera un 5% del optimo como referencia
            elif (nuevo_costo < costo_sol * porc_EstancamientoMax
                  and nuevo_costo > costo_sol * porc_Estancamiento
                  and iteracEstancamiento > 100):
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                tiempoTotal = time() - tiempoEstancamiento
                print(
                    "Se estancó durante %d min %d seg. Admitimos una solucion peor para diversificar"
                    % (int(tiempoTotal / 60), int(tiempoTotal % 60)))
                self.__beta = 1.5
                if (porc_EstancamientoMax < 1.3):
                    porc_Estancamiento += 0.02
                    porc_EstancamientoMax += 0.02
                else:
                    print("reiniciamos la lista tabu")
                    porc_Estancamiento = 1.05
                    porc_EstancamientoMax = 1.2
                lista_tabu = []
                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                cond_Optimiz = True
                iteracEstancamiento = 1
                Aristas = Aristas_Opt
            elif (iteracEstancamiento > 100):
                porc_Estancamiento = 1.05
                porc_EstancamientoMax = 1.2
                self.__beta = 2
                lista_tabu = []
                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
            else:
                nuevas_rutas = rutas_refer
                nueva_solucion = solucion_refer

            if (aristas_ADD != []):
                ADD.append(Tabu(aristas_ADD[0], tenureADD))
                for i in range(0, len(aristas_DROP)):
                    DROP.append(Tabu(aristas_DROP[i], tenureDROP))
                self.decrementaTenure(lista_tabu)
                lista_tabu.extend(DROP)
                lista_tabu.extend(ADD)
            else:
                lista_tabu = []
                porc_Estancamiento = 1.05
                porc_EstancamientoMax = 1.2

            tiempoEjecuc = time() - tiempoIni
            iterac += 1
            iteracEstancamiento += 1
            iteracEstancamiento_Opt += 1
        #Fin del while. Imprimo los valores obtenidos

        print("\nMejor solucion obtenida: " + str(self.__rutas))
        tiempoTotal = time() - tiempoIni
        print("\nTermino!! :)")
        print("Tiempo total: " + str(int(tiempoTotal / 60)) + "min " +
              str(int(tiempoTotal % 60)) + "seg\n")
        self.__txt.escribir(
            "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Solucion Optima +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )
        sol_ini = ""
        for i in range(0, len(self.__rutas)):
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(
                self.__rutas[i].getV())
            sol_ini += "\nCosto asociado: " + str(
                self.__rutas[i].getCostoAsociado(
                )) + "      Capacidad: " + str(
                    self.__rutas[i].getCapacidad()) + "\n"
        self.__txt.escribir(sol_ini)
        porcentaje = round(self.__S.getCostoAsociado() / self.__optimo - 1.0,
                           3)
        self.__txt.escribir("\nCosto total:  " +
                            str(self.__S.getCostoAsociado()) +
                            "        Optimo real:  " + str(self.__optimo) +
                            "      Desviación: " + str(porcentaje * 100) + "%")
        self.__txt.escribir("\nCantidad de iteraciones: " + str(iterac))
        self.__txt.escribir("Nro de vehiculos: " + str(self.__nroVehiculos))
        self.__txt.escribir("Capacidad Maxima/Vehiculo: " +
                            str(self.__capacidadMax))
        self.__txt.escribir("Tiempo total: " + str(int(tiempoTotal / 60)) +
                            "min " + str(int(tiempoTotal % 60)) + "seg")
        tiempoTotal = time() - tiempoEstancamiento
        self.__txt.escribir("Tiempo de estancamiento: " +
                            str(int(tiempoTotal / 60)) + "min " +
                            str(int(tiempoTotal % 60)) + "seg")
        self.__txt.imprimir()

    def getPermitidos(self, Aristas, lista_tabu, umbral, cond_Optimiz,
                      solucion):
        ListaPermit = [
        ]  #Aristas permitidas de todas las aristas del grafo original
        AristasNuevas = []

        #No tengo en consideracion a las aristas que exceden el umbral y las que pertencen a S
        if (cond_Optimiz):
            for EP in Aristas:
                pertS = False
                for A_S in solucion.getA():
                    if A_S == EP:
                        pertS = True
                        A_S.incFrecuencia()
                        break
                if (not pertS and EP.getPeso() <= umbral):
                    AristasNuevas.append(EP)
        else:
            AristasNuevas = Aristas

        #La lista tabu esta vacia, entonces la lista de permitidas tiene todas las aristas anteriores
        if (len(lista_tabu) == 0):
            print("len: " + str(len(lista_tabu)))
            ListaPermit = AristasNuevas
            print("aristas_nuevas: " + str(AristasNuevas))
        #La lista tabu tiene elementos, agrego los que no estan en lista tabu
        else:
            for i in range(0, len(AristasNuevas)):
                EP = AristasNuevas[i]
                cond = True
                j = 0
                while (j < len(lista_tabu) and cond):
                    ET = lista_tabu[j]
                    if (EP == ET.getElemento()):
                        cond = False
                    j += 1
                if (cond):
                    ListaPermit.append(EP)

        return ListaPermit, AristasNuevas

    #Decrementa el Tenure en caso de que no sea igual a -1. Si luego de decrementar es 0, lo elimino de la lista tabu
    def decrementaTenure(self, lista_tabu: list):
        i = 0
        while (i < len(lista_tabu)):
            elemTabu = lista_tabu[i]
            if (elemTabu.getTenure() != -1):
                elemTabu.decrementaT()
            if (elemTabu.getTenure() == 0):
                lista_tabu.pop(i)
                i -= 1
            i += 1
class CVRPparalelo:
    def __init__(self, M, D, nroV, capac, archivo, carpeta, solI, tADD, tDROP,
                 tiempo, porcentaje, optimo):
        self.__comm = MPI.COMM_WORLD
        self.__tiempoMPI = 0
        self.__rank = self.__comm.Get_rank()
        self.__poolSol = []
        self.__contSol = 0

        self._G = Grafo(M, D)  #Grafo original
        self.__S = Solucion(M, D, sum(D))  #Solucion general del CVRP
        self.__Distancias = M  #Mareiz de distancias
        self.__Demandas = D  #Demandas de los clientes
        self.__capacidadMax = capac  #Capacidad max por vehiculo
        self.__rutas = []  #Soluciones por vehiculo (lista de soluciones)
        self.__nroVehiculos = nroV  #Nro de vehiculos disponibles
        self.__tipoSolucionIni = solI  #Tipo de solucion inicial (Clark & Wright, Vecino cercano, Secuencial o al Azar)
        self.__beta = 1  #Parametro de dispersion
        self.__umbralMin = 0  #Umbral de granularidad minimo
        self.__optimosLocales = []  #Lista de optimos locales
        self.__porcentajeParada = float(
            porcentaje)  #Porcentaje de desvio minimo como condicion de parada
        self.__optimo = optimo  #Mejor valor de la instancia
        self.__tenureADD = tADD
        self.__tenureMaxADD = int(tADD * 1.7)
        self.__tenureDROP = tDROP
        self.__tenureMaxDROP = int(tDROP * 1.7)
        self.__txt = clsTxt(str(archivo), str(carpeta))
        self.__tiempoMaxEjec = float(tiempo)
        self.escribirDatos()
        self.__S.setCapacidadMax(self.__capacidadMax)
        tiempoIni = time()
        self.__rutas = self.__S.rutasIniciales(self.__tipoSolucionIni,
                                               self.__nroVehiculos,
                                               self.__Demandas,
                                               self.__capacidadMax)
        print("tiempo solucion inicial: ", time() - tiempoIni)
        self.__tiempoMaxEjec = self.__tiempoMaxEjec - (
            (time() - tiempoIni) / 60)
        tiempoIni = time()
        self.__S = self.cargaSolucion(self.__rutas)
        print("tiempo solucion inicial: ", time() - tiempoIni)
        print("Nro vehiculos: ", self.__nroVehiculos)
        self.tabuSearch()

    #Escribe los datos iniciales: el grafo inicial y la demanda
    def escribirDatos(self):
        self.__txt.escribir(
            "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ GRAFO CARGADO +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )
        self.__txt.escribir(str(self._G))
        cad = "\nDemandas:"
        for v in self._G.getV():
            cad_aux = str(v) + ": " + str(v.getDemanda())
            cad += "\n" + cad_aux
        self.__txt.escribir(cad)
        print("\nSuma Demanda: ", sum(self.__Demandas))
        print("Nro vehiculos: ", self.__nroVehiculos)
        self.__txt.escribir(
            "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ SOLUCION INICIAL +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )

    #Carga la solucion general a partir de las rutas
    def cargaSolucion(self, rutas):
        A = []
        V = []
        S = Solucion(self.__Distancias, self.__Demandas, sum(self.__Demandas))
        cap = 0
        costoTotal = 0
        sol_ini = ""

        #print("+-+-++-+-++-+-++-+-+Rutas+-+-++-+-++-+-++-+-+")
        for i in range(0, len(rutas)):
            s = rutas[i]
            try:
                costoTotal += float(s.getCostoAsociado())
            except AttributeError:
                print("s: " + str(s))
                print("rutas: " + str(rutas))
                print("i: ", i)
                a = 1 / 0
            cap += s.getCapacidad()
            A.extend(s.getA())
            V.extend(s.getV())
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(s.getV())
            #sol_ini+="\nAristas: "+str(s.getA())
            sol_ini += "\nCosto asociado: " + str(
                s.getCostoAsociado()) + "      Capacidad: " + str(
                    s.getCapacidad()) + "\n"
        sol_ini += "\n--> Costo total: " + str(
            costoTotal) + "          Capacidad total: " + str(cap)
        # print(sol_ini)
        # print("+-+-++-+-++-+-++-+-++-+-++-+-++-+-++-+-+")
        self.__txt.escribir(sol_ini)
        S.setA(A)
        S.setV(V)
        costoTotal = round(costoTotal, 3)
        S.setCostoAsociado(costoTotal)
        S.setCapacidad(cap)
        S.setCapacidadMax(self.__capacidadMax)

        return S

    #Umbral de granularidad: phi = Beta*(c/(n+k))
    #Beta = 1  parametro de dispersion. Sirve para modificar el grafo disperso para incluir la diversificación y la intensificación
    #          durante la búsqueda.
    #c = valor de una sol. inicial
    #k = nro de vehiculos
    #n = nro de clientes
    def calculaUmbral(self, costo):
        c = costo
        k = self.__nroVehiculos
        n = len(self.__Distancias) - 1
        phi = c / (n + k)
        phi = phi * self.__beta
        return round(phi, 3)

    #+-+-+-+-+-+-+- Empezamos con Tabu Search +-+-+-+-+-+-+-+-+#
    #lista_tabu: tiene objetos de la clase Tabu (una arista con su tenure)
    #Lista_permitidos: o grafo disperso tiene elementos del tipo Arista que no estan en la lista tabu y su distancia es menor al umbral
    #nuevas_rutas: nuevas rutas obtenidas a partir de los intercambios
    #nueva_solucion: nueva solucion obtenida a partir de los intercambios
    #rutas_refer: rutas de referencia que sirve principalmente para evitar estancamiento, admitiendo una solucion peor y hacer los intercambios
    #             a partir de esas
    #solucion_refer: idem al anterior
    #tiempoIni: tiempo inicial de ejecucion - tiempoMax: tiempo maximo de ejecucion - tiempoEjecuc: tiempo de ejecución actual
    #iteracEstancamiento: iteraciones de estancamiento para admitir una solución peor, modificar Beta y escapar del estancamiento
    #iterac: cantidad de iteraciones actualmente
    def tabuSearch(self):
        print(str(self.__Demandas))
        self.__comm.Barrier()
        lista_tabu = []
        ind_permitidos = np.array([], dtype=int)
        rutas_refer = copy.deepcopy(self.__rutas)
        nuevas_rutas = rutas_refer
        solucion_refer = copy.deepcopy(self.__S)
        nueva_solucion = solucion_refer
        nuevo_costo = self.__S.getCostoAsociado()

        #Atributos de tiempo e iteraciones
        tiempoIni = time()
        tiempoMax = float(self.__tiempoMaxEjec * 60)
        tiempoEstancamiento = tiempoIni
        tiempoEjecuc = 0
        iteracEstancamiento = 1
        iteracEstancamiento_Opt = 1
        iteracEstancMax = 300
        iterac = 1
        indOptimosLocales = -2
        umbral = self.calculaUmbral(self.__S.getCostoAsociado())
        porc_Estancamiento = 1.05
        porc_EstancamientoMax = 1.15
        cond_Optimiz = True
        cond_Estancamiento = False

        tiempo = time()
        Aristas_Opt = np.array([], dtype=object)
        for EP in self._G.getA():
            if (EP.getOrigen().getValue() < EP.getDestino().getValue()
                    and EP.getPeso() <= umbral):
                Aristas_Opt = np.append(Aristas_Opt, EP)
                ind_permitidos = np.append(ind_permitidos, EP.getId())
        Aristas = Aristas_Opt
        ind_AristasOpt = copy.deepcopy(ind_permitidos)
        print("tiempo get AristasOpt: " + str(time() - tiempo))

        self.__optimosLocales.append(nuevas_rutas)
        porcentaje = round(self.__S.getCostoAsociado() / self.__optimo - 1.0,
                           3)
        print("Costo sol Inicial: " + str(self.__S.getCostoAsociado()) +
              "      ==> Optimo: " + str(self.__optimo) + "  Desvio: " +
              str(round(porcentaje * 100, 3)) + "%")

        cantIntercambios = 20
        self.__tiempoMPI = tiempoMax / cantIntercambios
        tCoord = time()
        nroIntercambios = 0
        indPoolSol = -1
        bandera = True  #Bandera para forzar detención de ejecución
        condMPIopt = True

        while (tiempoEjecuc < tiempoMax
               and porcentaje * 100 > self.__porcentajeParada):
            if (cond_Optimiz):
                if (
                        not time() - tCoord > self.__tiempoMPI
                ):  #Condición para chequear si ya es tiempo de compartir datos antes de ejecutar self.getPermitidos
                    tiempo = time()
                    ind_permitidos, Aristas = self.getPermitidos(
                        Aristas, lista_tabu, umbral, solucion_refer,
                        rutas_refer)  #Lista de elementos que no son tabu
                    # print("tiempo getPerm: "+str(time()-tiempo))
                    self.__umbralMin = 0
                    condMPIopt = True
                else:
                    condMPIopt = False  # Con esta condición nos evitamos de realizaar todas las actividades que vienen despues de compartir los datos hasta realizaar el self.getPermitidos

            # AÚN NO SE SI ESTO ES NECESARIO ( EVITAR QUE LOS NODOS SIGAN EJECUTANDO UNA VEZ TERMINADO EL tiempoMax)
            # if(not tiempoEjecuc < tiempoMax and bandera):
            #     print ("LOS NODOS YA CUMPLIERON SU TIEMPO DE EJECUCIÓN. FORZANDO DETENCIÓN")
            #     l = self.__comm.allgather(nroIntercambios)
            #     cantIntercambios = max(l)+1
            #     bandera = False
            tCoord, nroIntercambios = self.__paralelismo(
                time() - tCoord > self.__tiempoMPI, tCoord, nroIntercambios)

            if condMPIopt:  # Condicion para no ejecutar el código de adentro hasta que se realice el self.getPermitidos
                cond_Optimiz = False
                ADD = []
                DROP = []

                ind_random = np.arange(0, len(ind_permitidos))
                random.shuffle(ind_random)

                indRutas = indAristas = []
                nuevo_costo, k_Opt, indRutas, indAristas, aristasADD, aristasDROP = nueva_solucion.evaluarOpt(
                    self._G.getA(), ind_permitidos, ind_random, rutas_refer,
                    cond_Estancamiento)

                nuevo_costo = round(nuevo_costo, 3)

                tenureADD = self.__tenureADD
                tenureDROP = self.__tenureDROP

                costoSolucion = self.__S.getCostoAsociado()

                #Si encontramos una mejor solucion que la tomada como referencia
                if (nuevo_costo < solucion_refer.getCostoAsociado()
                        and aristasADD != []):
                    cad = "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Iteracion %d nodo %d +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n" % (
                        iterac, self.__rank)
                    self.__txt.escribir(cad)

                    nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0],
                                                       rutas_refer, indRutas,
                                                       indAristas)
                    #print("tiempo swap: "+str(time()-tiempo))
                    #tiempo = time()
                    nueva_solucion = self.cargaSolucion(nuevas_rutas)
                    #print("tiempo cargaSol: "+str(time()-tiempo))

                    if (nuevo_costo != nueva_solucion.getCostoAsociado()):
                        print("\n\nERROR!!!!!!")
                        print("ADD: " + str(aristasADD) + "     DROP: " +
                              str(aristasDROP) + "\n\n")
                        print("nueva solucion:" + str(nueva_solucion.getV()))
                        print("solucion refer:" + str(solucion_refer.getV()))

                        print("\nRutas ahora")
                        for i in range(0, len(rutas_refer)):
                            x = rutas_refer[i]
                            print("ruta #%d: %s" % (i, str(x.getV())))
                        print("nuevo costo: ", nuevo_costo,
                              "          getCostoAsociado: ",
                              nueva_solucion.getCostoAsociado())
                        a = 1 / 0

                    solucion_refer = nueva_solucion
                    rutas_refer = nuevas_rutas

                    #Si la nueva solucion es mejor que la obtenida hasta el momento
                    if (nuevo_costo < costoSolucion):
                        # print("nueva solucion:"+str(nueva_solucion.getV()))
                        # print("solucion refer:"+str(solucion_refer.getV()))

                        # print("\nRutas ahora")
                        # for i in range(0, len(rutas_refer)):
                        #     x = rutas_refer[i]
                        #     print("ruta #%d: %s" %(i, str(x.getV())))
                        # print("nuevo costo: ", nuevo_costo,"          getCostoAsociado: ", nueva_solucion.getCostoAsociado())

                        porcentaje = round(nuevo_costo / self.__optimo - 1.0,
                                           3)
                        tiempoTotal = time() - tiempoEstancamiento
                        print(cad)
                        self.__contSol += 1
                        cad = "\nLa solución anterior duró " + str(
                            int(tiempoTotal / 60)) + "min " + str(
                                int(tiempoTotal % 60)) + " y ya van " + str(
                                    self.__contSol) + " soluciones encontradas"
                        cad += "seg    -------> Nuevo optimo local. Costo: " + str(
                            nuevo_costo)
                        cad += "       ==> Optimo: " + str(
                            self.__optimo) + "  Desvio: " + str(
                                porcentaje * 100) + "%"

                        # if(porcentaje*100 > 1000):
                        #     print("rutas: "+str(nuevas_rutas))
                        #     print("ADD: "+str(aristasADD))
                        #     print("DROP: "+str(aristasDROP))
                        #     print("ind_AristasOpt: "+str(ind_AristasOpt))
                        #     print("ind_permitidos: "+str(ind_permitidos))
                        self.__S = nueva_solucion
                        self.__rutas = nuevas_rutas
                        self.__beta = 1
                        tiempoEstancamiento = time()
                        if (len(self.__optimosLocales) >= 15):
                            self.__optimosLocales.pop(0)
                        self.__optimosLocales.append(nuevas_rutas)
                        indOptimosLocales = -2
                        cond_Estancamiento = False
                        print(cad)
                    else:
                        cad += "\nSolucion peor. Costo: " + str(
                            nueva_solucion.getCostoAsociado())
                    cad += "\nLista tabu: " + str(lista_tabu)
                    self.__txt.escribir(cad)
                    umbral = self.calculaUmbral(
                        nueva_solucion.getCostoAsociado())
                    tenureADD = self.__tenureMaxADD
                    tenureDROP = self.__tenureMaxDROP
                    cond_Optimiz = True
                    Aristas = Aristas_Opt
                    iteracEstancamiento = 1
                    iteracEstancamiento_Opt = 1
                    iteracEstancMax = 300
                #Si se estancó, tomamos a beta igual a 2
                elif (iteracEstancamiento > iteracEstancMax
                      and self.__beta < 2):
                    tiempoTotal = time() - tiempoEstancamiento
                    print(
                        "Se estancó durante %d min %d seg. Incrementanos Beta para diversificar"
                        % (int(tiempoTotal / 60), int(tiempoTotal % 60)))
                    self.__beta = 2
                    self.__umbralMin = umbral
                    umbral = self.calculaUmbral(
                        nueva_solucion.getCostoAsociado())
                    cond_Optimiz = True
                    iteracEstancamiento = 1
                    iteracEstancMax = 200
                    Aristas = Aristas_Opt
                #CONDICION PARA MPI. Si se estancó y el pool de soluciones tiene elementos entonces partimos de ahi
                elif (iteracEstancamiento > iteracEstancMax
                      and len(self.__poolSol) > 0):
                    nuevas_rutas = self.__poolSol.pop(len(self.__poolSol) - 1)
                    nueva_solucion = self.cargaSolucion(nuevas_rutas)
                    costo = nueva_solucion.getCostoAsociado()
                    tiempoTotal = time() - tiempoEstancamiento
                    cad = "Se estancó durante %d min %d seg. Admitimos el penultimo elemento del pool de soluciones. Quedan %d en nodo %d" % (
                        int(tiempoTotal / 60), int(tiempoTotal % 60),
                        len(self.__poolSol), self.__rank)
                    print(cad + "-->    Costo: " + str(costo))

                    lista_tabu = []
                    ind_permitidos = ind_AristasOpt
                    umbral = self.calculaUmbral(costo)
                    solucion_refer = nueva_solucion
                    rutas_refer = nuevas_rutas
                    cond_Optimiz = True
                    Aristas = Aristas_Opt
                    iteracEstancamiento = 1
                    iteracEstancMax = 100
                    self.__beta = 2

                #Si se estancó nuevamente, tomamos la proxima sol peor que difiera un 5% del optimo o la penultima de los optimos locales
                elif (iteracEstancamiento > iteracEstancMax
                      and len(self.__optimosLocales) >= indOptimosLocales *
                      (-1)):
                    nuevas_rutas = self.__optimosLocales[indOptimosLocales]
                    nueva_solucion = self.cargaSolucion(nuevas_rutas)
                    costo = nueva_solucion.getCostoAsociado()
                    tiempoTotal = time() - tiempoEstancamiento
                    cad = "Se estancó durante %d min %d seg. Admitimos el penultimo optimo local " % (
                        int(tiempoTotal / 60), int(tiempoTotal % 60))
                    print(cad + "-->    Costo: " + str(costo))

                    lista_tabu = []
                    ind_permitidos = ind_AristasOpt
                    umbral = self.calculaUmbral(costo)
                    solucion_refer = nueva_solucion
                    rutas_refer = nuevas_rutas
                    cond_Optimiz = True
                    Aristas = Aristas_Opt
                    iteracEstancamiento = 1
                    indOptimosLocales -= 1
                    iteracEstancMax = 100
                    self.__beta = 3
                elif (iteracEstancamiento > iteracEstancMax
                      and costoSolucion * porc_Estancamiento > nuevo_costo
                      and nuevo_costo < costoSolucion * porc_EstancamientoMax):
                    nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0],
                                                       rutas_refer, indRutas,
                                                       indAristas)
                    nueva_solucion = self.cargaSolucion(nuevas_rutas)
                    tiempoTotal = time() - tiempoEstancamiento
                    costo = nueva_solucion.getCostoAsociado()
                    cad = "Se estancó durante %d min %d seg. Admitimos una solucion peor para diversificar" % (
                        int(tiempoTotal / 60), int(tiempoTotal % 60))
                    print(cad + "-->    Costo: " + str(costo))

                    lista_tabu = []
                    ind_permitidos = ind_AristasOpt
                    umbral = self.calculaUmbral(costo)
                    solucion_refer = nueva_solucion
                    rutas_refer = nuevas_rutas
                    cond_Optimiz = True
                    iteracEstancamiento = 1
                    Aristas = Aristas_Opt
                    iteracEstancMax = 300
                elif (ind_permitidos == []):
                    nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0],
                                                       rutas_refer, indRutas,
                                                       indAristas)
                    nueva_solucion = self.cargaSolucion(nuevas_rutas)
                    solucion_refer = nueva_solucion
                    rutas_refer = nuevas_rutas
                    umbral = self.calculaUmbral(
                        nueva_solucion.getCostoAsociado())
                    cond_Optimiz = True
                    self.__beta = 3
                    lista_tabu = []
                    ind_permitidos = ind_AristasOpt
                    Aristas = Aristas_Opt
                    umbral = self.calculaUmbral(costo)
                else:
                    nuevas_rutas = rutas_refer
                    nueva_solucion = solucion_refer

                #Añado y elimino de la lista tabu
                if (aristasADD != []):
                    ADD.append(Tabu(aristasADD[0], tenureADD))
                    for i in range(0, len(aristasDROP)):
                        DROP.append(Tabu(aristasDROP[i], tenureDROP))
                    self.decrementaTenure(lista_tabu, ind_permitidos)
                    lista_tabu.extend(DROP)
                    lista_tabu.extend(ADD)
                else:
                    lista_tabu = []
                    ind_permitidos = ind_AristasOpt
                    Aristas = Aristas_Opt
                    cond_Optimiz = True

                tiempoEjecuc = time() - tiempoIni
                iterac += 1
                iteracEstancamiento += 1
                iteracEstancamiento_Opt += 1
        #Fin del while. Imprimo los valores obtenidos
        self.escribirDatosFinales(tiempoIni, iterac, tiempoEstancamiento)

    def getCostoAsociadoRutas(self, rutas):
        acu = 0
        for r in rutas:
            acu += r.getCostoAsociado()
        return acu

    def __paralelismo(self, cond, tCoord, nroIntercambios):
        if cond:
            nroIntercambios += 1
            print(
                "Intercambio %d con %f de diferencia de tiempo <<<<---------------------------------------------------------------- MPI <<<<---------------------------------"
                % (nroIntercambios, (time() - tCoord) - self.__tiempoMPI))

            delay = (time() - tCoord) - self.__tiempoMPI
            listaS = self.__comm.allgather(
                (self.__S, self.__rank, self.__rutas, delay, self.__contSol)
            )  #solucion_refer, Aristas, lista_tabu, nueva_solucion, ind_permitidos, ind_permitidos, self.__rutas, Aristas, lista_tabu, ind_permitidos, rutas_refer, self._G, nueva_solucion
            if delay > 2:
                menor = listaS[0]
                for i in range(1, len(listaS)):
                    if (listaS[i][3] < menor[3]):
                        menor = listaS[i]
                tCoord += menor[3]
                print("Se aumentó el tiempo de coordinación a %d" % (menor[3]))
            masSol = listaS[0]
            for i in range(1, len(listaS)):
                if (listaS[i][4] > masSol[4]):
                    masSol = listaS[i]
            print("El nodo %d fue el que encontró mas soluciones: %d" %
                  (masSol[1], masSol[4]))
            smCosto = listaS[0]
            for i in range(1, len(listaS)):
                if (listaS[i][0].getCostoAsociado() <
                        smCosto[0].getCostoAsociado()):
                    smCosto = listaS[i]
            self.__S = copy.deepcopy(smCosto[0])
            self.__rutas = copy.deepcopy(smCosto[2])
            # Eliminamos repetidos
            i = 0
            while i < len(listaS):
                j = i + 1
                while j < len(listaS):
                    if listaS[i][0] == listaS[j][0]:
                        listaS.pop(j)
                        print("Se quitó una solución repetida")
                    else:
                        j += 1
                i += 1
            # Eliminamos optimos locales que ya existen en las soluciones
            i = 0
            while i < len(self.__poolSol):
                j = i
                while j < len(listaS):
                    costo = abs(
                        self.getCostoAsociadoRutas(self.__poolSol[i]) -
                        self.getCostoAsociadoRutas(listaS[j][2]))
                    if costo < 0.00001:
                        listaS.pop(j)
                        print(
                            "Se quitó una solución repetida con el mismo peso que un óptimo local"
                        )
                    else:
                        j += 1
                i += 1
            for tupla in listaS:
                self.__poolSol.append(tupla[2])
            self.__poolSol.append(copy.deepcopy(self.__rutas))
            while len(self.__poolSol) >= 50:
                self.__poolSol.pop(0)
            tCoord = time()
        return tCoord, nroIntercambios

    def getPermitidos(self, Aristas, lista_tabu, umbral, solucion,
                      rutas_refer):
        AristasNuevas = []
        ind_permitidos = np.array([], dtype=int)

        #No tengo en consideracion a las aristas que exceden el umbral y las que pertencen a S
        A_solucion = copy.copy(solucion.getA())
        for EP in Aristas:
            pertS = False
            i = 0
            while (i < len(A_solucion)):
                A_S = A_solucion[i]
                if A_S == EP:
                    A_solucion.pop(i)
                    pertS = True
                    break
                i += 1
            if (not pertS and self.__umbralMin <= EP.getPeso()
                    and EP.getPeso() <= umbral):
                AristasNuevas.append(EP)
                ind_permitidos = np.append(ind_permitidos, EP.getId())
        ind_permitidos = np.unique(ind_permitidos)

        return ind_permitidos, AristasNuevas

    #Decrementa el Tenure en caso de que no sea igual a -1. Si luego de decrementar es 0, lo elimino de la lista tabu
    def decrementaTenure(self, lista_tabu, ind_permitidos):
        i = 0
        while (i < len(lista_tabu)):
            elemTabu = lista_tabu[i]
            elemTabu.decrementaT()
            if (elemTabu.getTenure() == 0):
                ind_permitidos = np.append(ind_permitidos,
                                           elemTabu.getElemento().getId())
                lista_tabu.pop(i)
                i -= 1
            i += 1

    def escribirDatosFinales(self, tiempoIni, iterac, tiempoEstancamiento):
        print("\nMejor solucion obtenida: " + str(self.__rutas))
        tiempoTotal = time() - tiempoIni
        print("\nTermino!! :)")
        print("Tiempo total: " + str(int(tiempoTotal / 60)) + "min " +
              str(int(tiempoTotal % 60)) + "seg\n")
        self.__txt.escribir(
            "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Solucion Optima +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )
        sol_ini = ""
        for i in range(0, len(self.__rutas)):
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(
                self.__rutas[i].getV())
            sol_ini += "\nCosto asociado: " + str(
                self.__rutas[i].getCostoAsociado(
                )) + "      Capacidad: " + str(
                    self.__rutas[i].getCapacidad()) + "\n"
        self.__txt.escribir(sol_ini)
        porcentaje = round(self.__S.getCostoAsociado() / self.__optimo - 1.0,
                           3)
        self.__txt.escribir("\nCosto total:  " +
                            str(self.__S.getCostoAsociado()) +
                            "        Optimo real:  " + str(self.__optimo) +
                            "      Desviación: " + str(porcentaje * 100) + "%")
        self.__txt.escribir("\nCantidad de iteraciones: " + str(iterac))
        self.__txt.escribir("Nro de vehiculos: " + str(self.__nroVehiculos))
        self.__txt.escribir("Capacidad Maxima/Vehiculo: " +
                            str(self.__capacidadMax))
        self.__txt.escribir("Tiempo total: " + str(int(tiempoTotal / 60)) +
                            "min " + str(int(tiempoTotal % 60)) + "seg")
        tiempoTotal = time() - tiempoEstancamiento
        self.__txt.escribir("Tiempo de estancamiento: " +
                            str(int(tiempoTotal / 60)) + "min " +
                            str(int(tiempoTotal % 60)) + "seg")
        self.__txt.imprimir()
Exemplo n.º 9
0
class CVRP_mpi:
    def __init__(self, M, D, nroV, capac, archivo, solI, tADD, tDROP, tiempo, optimo, betaMin, betaMax):
        self.__comm = MPI.COMM_WORLD
        self.__tiempoMPI = 0
        self.__rank = self.__comm.Get_rank()
        self._G = Grafo(M, D)                #Grafo original
        self.__S = Solucion(M, D, sum(D))    #Solucion general del CVRP
        self.__Distancias = M                #Mareiz de distancias
        self.__Demandas = D                  #Demandas de los clientes
        self.__capacidadMax = capac          #Capacidad max por vehiculo
        self.__rutas = []                    #Soluciones por vehiculo (lista de soluciones)
        self.__nroVehiculos = nroV           #Nro de vehiculos disponibles
        self.__tipoSolucionIni = solI        #Tipo de solucion inicial (Clark & Wright, Vecino cercano, Secuencial o al Azar)
        #self.__beta = beta                      #Parametro de dispersion
        self.__optimosLocales = []           #Lista de optimos locales 
        self.__porcentajeParada = 5.0        #Porcentaje de desvio minimo como condicion de parada
        self.__optimo = optimo               #Mejor valor de la instancia
        self.__tenureADD =  tADD             
        self.__tenureMaxADD = int(tADD*1.7)
        self.__tenureDROP =  tDROP
        self.__tenureMaxDROP = int(tDROP*1.7)
        self.__txt = clsTxt(str(archivo))
        self.__tiempoMaxEjec = float(tiempo)
        self.escribirDatos()
        self.__S.setCapacidadMax(self.__capacidadMax)
        self.__rutas = self.__S.rutasIniciales(self.__tipoSolucionIni, self.__nroVehiculos, self.__Demandas, self.__capacidadMax)
        self.__S = self.cargaSolucion(self.__rutas)
        self.__costoAnterior = self.__S.getCostoAsociado()
 
        if self.__rank == 0:
            self.__mpiTxt = clsTxt("MPI-"+str(archivo)+"_Proces #"+str(self.__rank))
            self.__betaMin = betaMin
            self.__beta = betaMin
            self.__umbralMin = 0                 #Umbral de granularidad minimo
            self.__umbralMin = self.calculaUmbral(self.__S.getCostoAsociado())
            self.__beta = betaMax
        else:
            self.__betaMin = betaMin
            self.__beta = betaMin                   #Parametro de dispersion
            self.__umbralMin = self.calculaUmbral(self.__S.getCostoAsociado())
            self.__beta = betaMax

        self.tabuSearch()

    #Escribe los datos iniciales: el grafo inicial y la demanda
    def escribirDatos(self):
        self.__txt.escribir("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ GRAFO CARGADO +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-")
        self.__txt.escribir(str(self._G))
        cad = "\nDemandas:"
        for v in self._G.getV():
            cad_aux = str(v)+": "+str(v.getDemanda())
            cad+="\n"+ cad_aux
        self.__txt.escribir(cad)
        print("\nSuma Demanda: ",sum(self.__Demandas))
        print("Nro vehiculos: ",self.__nroVehiculos)
        self.__txt.escribir("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ SOLUCION INICIAL +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-")

    #Carga la solucion general a partir de las rutas
    def cargaSolucion(self, rutas):
        A = []
        V = []
        S = Solucion(self.__Distancias, self.__Demandas, sum(self.__Demandas))
        cap = 0
        costoTotal = 0
        sol_ini = ""
        
        for i in range(0, len(rutas)):
            s = rutas[i]
            costoTotal += s.getCostoAsociado()
            cap += s.getCapacidad()
            A.extend(s.getA())
            V.extend(s.getV())
            sol_ini+="\nRuta #"+str(i+1)+": "+str(s.getV())
            sol_ini+="\nCosto asociado: "+str(s.getCostoAsociado())+"      Capacidad: "+str(s.getCapacidad())+"\n"
        sol_ini+="\n--> Costo total: "+str(costoTotal)+"          Capacidad total: "+str(cap)
        self.__txt.escribir(sol_ini)
        S.setA(A)
        S.setV(V)
        costoTotal = round(costoTotal, 3)
        S.setCostoAsociado(costoTotal)
        S.setCapacidad(cap)
        S.setCapacidadMax(self.__capacidadMax)
        
        return S

    #Umbral de granularidad: phi = Beta*(c/(n+k))
    #Beta = 1  parametro de dispersion. Sirve para modificar el grafo disperso para incluir la diversificación y la intensificación
    #          durante la búsqueda.
    #c = valor de una sol. inicial
    #k = nro de vehiculos
    #n = nro de clientes
    def calculaUmbral(self, costo):
        c = costo
        k = self.__nroVehiculos
        n = len(self.__Distancias)-1
        phi = c/(n+k)
        phi = phi*self.__beta
        return round(phi,3)

    #+-+-+-+-+-+-+- Empezamos con Tabu Search +-+-+-+-+-+-+-+-+#
    #lista_tabu: tiene objetos de la clase Tabu (una arista con su tenure)
    #Lista_permitidos: o grafo disperso tiene elementos del tipo Arista que no estan en la lista tabu y su distancia es menor al umbral
    #nuevas_rutas: nuevas rutas obtenidas a partir de los intercambios
    #nueva_solucion: nueva solucion obtenida a partir de los intercambios
    #rutas_refer: rutas de referencia que sirve principalmente para evitar estancamiento, admitiendo una solucion peor y hacer los intercambios
    #             a partir de esas
    #solucion_refer: idem al anterior
    #tiempoIni: tiempo inicial de ejecucion - tiempoMax: tiempo maximo de ejecucion - tiempoEjecuc: tiempo de ejecución actual
    #iteracEstancamiento: iteraciones de estancamiento para admitir una solución peor, modificar Beta y escapar del estancamiento
    #iterac: cantidad de iteraciones actualmente
    def tabuSearch(self):
        lista_tabu = []
        ind_permitidos = np.array([], dtype = int)
        tiempo=time()
        rutas_refer = copy.deepcopy(self.__rutas)
        nuevas_rutas = rutas_refer
        solucion_refer = copy.deepcopy(self.__S)
        nueva_solucion = solucion_refer
        nuevo_costo = self.__S.getCostoAsociado()
        print("tiempo deepcopy: "+str(time()-tiempo))
        
        #Atributos de tiempo e iteraciones
        tiempoIni = time()
        tiempoMax = float(self.__tiempoMaxEjec*60)
        tiempoEstancamiento = tiempoIni
        tiempoEjecuc = 0
        iteracEstancamiento = 1
        iteracEstancamiento_Opt = 1
        iteracEstancMax = 200
        iterac = 1
        indOptimosLocales = -2
        umbral = self.calculaUmbral(self.__S.getCostoAsociado())
        porc_Estancamiento = 1.05
        porc_EstancamientoMax = 1.15
        cond_Optimiz = True
        cond_Estancamiento = False

        Aristas_Opt = np.array([], dtype = object)
        for EP in self._G.getA():
            if(EP.getOrigen().getValue() < EP.getDestino().getValue() and EP.getPeso() <= umbral):
                Aristas_Opt = np.append(Aristas_Opt, EP)
                ind_permitidos = np.append(ind_permitidos, EP.getId())
        #ind_permitidos = np.unique(ind_permitidos)
        Aristas = Aristas_Opt
        
        self.__optimosLocales.append(nuevas_rutas)
        porcentaje = round(self.__S.getCostoAsociado()/self.__optimo -1.0, 3)
        print("Costo sol Inicial: "+str(self.__S.getCostoAsociado())+"      ==> Optimo: "+str(self.__optimo)+"  Desvio: "+str(round(porcentaje*100,3))+"%")
        
        self.__tiempoMPI = tiempoMax / 40
        tCoord = time()
        
        while(tiempoEjecuc < tiempoMax and porcentaje*100 > self.__porcentajeParada):
            if(cond_Optimiz):
                #tiempo = time()
                ind_permitidos, Aristas = self.getPermitidos(Aristas, lista_tabu, umbral, solucion_refer)    #Lista de elementos que no son tabu
                ind_AristasOpt = copy.deepcopy(ind_permitidos)
                #self.__umbralMin = self.__umbralMin

            if(time () - tCoord > self.__tiempoMPI and not cond_Estancamiento):
                tCoord, cond_Estancamiento = self.compartir(ind_permitidos, Aristas)
                #print("Tiempo getPermitidos: ", (time()-tiempo))
            cond_Optimiz = False
            ADD = []
            DROP = []
            
            ind_random = np.arange(0,len(ind_permitidos))
            random.shuffle(ind_random)
            
            indRutas = indAristas = []
            nuevo_costo, k_Opt, indRutas, indAristas, aristasADD, aristasDROP = nueva_solucion.evaluarOpt(self._G.getA(), ind_permitidos, ind_random, rutas_refer)
            nuevo_costo = round(nuevo_costo, 3)

            tenureADD = self.__tenureADD
            tenureDROP = self.__tenureDROP
            
            costoSolucion = self.__S.getCostoAsociado()
            #tiempo = time()
            #Si encontramos una mejor solucion que la tomada como referencia
            if(nuevo_costo < solucion_refer.getCostoAsociado()):
                cad = "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Iteracion %d  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n" %(iterac)
                rank = self.__comm.Get_rank()
                cad += "Proceso #%d   betaMin: %f    betaMax: %f   umbralMin: %f       umbralMax: %f" %(rank, self.__betaMin, self.__beta, self.__umbralMin, umbral)
                #print(cad)
                self.__txt.escribir(cad)
                if(len(aristasADD) > 0 and len(k_Opt)>0 and len(rutas_refer)>0):
                    print("k_opt: "+str(k_Opt))
                    print("len(rutas_refer)"+)
                    nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0], rutas_refer, indRutas, indAristas)
                else:
                    print("Aristas ADD: "+str(aristasADD))
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                #print("Tiempo swap: "+str(time()-tiempo))
                
                #Si la nueva solucion es mejor que la obtenida hasta el momento
                if(nuevo_costo < costoSolucion):
                    porcentaje = round(nuevo_costo/self.__optimo -1.0, 3)
                    tiempoTotal = time()-tiempoEstancamiento
                    cad += "\nLa solución anterior duró " + str(int(tiempoTotal/60))+"min "+ str(int(tiempoTotal%60))
                    cad += "seg    -------> Nuevo optimo local. Costo: "+str(nuevo_costo)
                    cad += "       ==> Optimo: "+str(self.__optimo)+"  Desvio: "+str(porcentaje*100)+"%"
                    self.__S = nueva_solucion
                    self.__rutas = nuevas_rutas
                    self.__beta = 1
                    tiempoEstancamiento = time()
                    if(len(self.__optimosLocales) >= 15):
                        self.__optimosLocales.pop(0)
                    self.__optimosLocales.append(nuevas_rutas)
                    indOptimosLocales = -2
                    cond_Estancamiento = False
                else:
                    cad += "\nNuevo optimo como referencia. Costo: "+str(nueva_solucion.getCostoAsociado())
                print(cad)
                cad += "\nLista tabu: "+str(lista_tabu)
                self.__txt.escribir(cad)
                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
                tenureADD = self.__tenureMaxADD
                tenureDROP = self.__tenureMaxDROP
                cond_Optimiz = True
                Aristas = Aristas_Opt
                iteracEstancamiento = 1
                iteracEstancamiento_Opt = 1
                iteracEstancMax = 200
            #Si se estancó, tomamos a beta igual a 2
            # elif(iteracEstancamiento > iteracEstancMax and self.__beta < 2):
            #     tiempoTotal = time()-tiempoEstancamiento
            #     print("\nSe estancó durante %d min %d seg. Incrementanos Beta para diversificar" %(int(tiempoTotal/60), int(tiempoTotal%60)))
            #     self.__beta += 0.25
            #     self.__umbralMin = umbral
            #     umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
            #     cond_Optimiz = True
            #     cond_Estancamiento = True
            #     iteracEstancamiento = 1
            #     iteracEstancMax = 150
            #     Aristas = Aristas_Opt
            #Si se estancó nuevamente, tomamos la proxima sol peor que difiera un 5% del optimo o la penultima de los optimos locales
            elif(iteracEstancamiento > iteracEstancMax and len(self.__optimosLocales) >= indOptimosLocales*(-1)):
                nuevas_rutas = self.__optimosLocales[indOptimosLocales]
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                costo = nueva_solucion.getCostoAsociado()
                tiempoTotal = time()-tiempoEstancamiento
                cad = "Se estancó durante %d min %d seg. Admitimos el penultimo optimo local " %(int(tiempoTotal/60), int(tiempoTotal%60))
                print(cad + "-->    Costo: "+str(costo))
                
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                umbral = self.calculaUmbral(costo)
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                cond_Optimiz = True
                cond_Estancamiento = True
                Aristas = Aristas_Opt
                iteracEstancamiento = 1
                indOptimosLocales -= 1
                iteracEstancMax = 100
            elif(iteracEstancamiento > iteracEstancMax and costoSolucion*porc_Estancamiento > nuevo_costo and nuevo_costo < costoSolucion*porc_EstancamientoMax):
                nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0], rutas_refer, indRutas, indAristas)
                nueva_solucion = self.cargaSolucion(nuevas_rutas)
                tiempoTotal = time()-tiempoEstancamiento
                costo = nueva_solucion.getCostoAsociado()
                cad = "Se estancó durante %d min %d seg. Admitimos una solucion peor para diversificar" %(int(tiempoTotal/60), int(tiempoTotal%60))
                print(cad + "-->    Costo: "+str(costo))
                
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                umbral = self.calculaUmbral(costo)
                solucion_refer = nueva_solucion
                rutas_refer = nuevas_rutas
                cond_Optimiz = True
                cond_Estancamiento = True
                iteracEstancamiento = 1
                Aristas = Aristas_Opt
                iteracEstancMax = 200
            elif(iteracEstancamiento > iteracEstancMax):
                nuevas_rutas = nueva_solucion.swap(k_Opt, aristasADD[0], rutas_refer, indRutas, indAristas)
                nueva_solucion = self.cargaSolucion(nuevas_rutas)            
                umbral = self.calculaUmbral(nueva_solucion.getCostoAsociado())
                cond_Optimiz = True
                cond_Estancamiento = True
            else:
                nuevas_rutas = rutas_refer
                nueva_solucion = solucion_refer

            #Añado y elimino de la lista tabu
            if (aristasADD != []):
                ADD.append(Tabu(aristasADD[0], tenureADD))
                for i in range(0, len(aristasDROP)):
                    DROP.append(Tabu(aristasDROP[i], tenureDROP))
                self.decrementaTenure(lista_tabu, ind_permitidos)
                lista_tabu.extend(DROP)
                lista_tabu.extend(ADD)
            else:
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
            
            tiempoEjecuc = time()-tiempoIni
            iterac += 1
            iteracEstancamiento += 1
            iteracEstancamiento_Opt += 1
        #Fin del while. Imprimo los valores obtenidos

        print("\nMejor solucion obtenida: "+str(self.__rutas))
        tiempoTotal = time() - tiempoIni
        print("\nTermino!! :)")
        print("Tiempo total: " + str(int(tiempoTotal/60))+"min "+str(int(tiempoTotal%60))+"seg\n")
        self.__txt.escribir("\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Solucion Optima +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-")
        sol_ini = ""
        for i in range(0, len(self.__rutas)):
            sol_ini+="\nRuta #"+str(i+1)+": "+str(self.__rutas[i].getV())
            sol_ini+="\nCosto asociado: "+str(self.__rutas[i].getCostoAsociado())+"      Capacidad: "+str(self.__rutas[i].getCapacidad())+"\n"
        self.__txt.escribir(sol_ini)
        porcentaje = round(self.__S.getCostoAsociado()/self.__optimo -1.0, 3)
        self.__txt.escribir("\nCosto total:  " + str(self.__S.getCostoAsociado()) + "        Optimo real:  " + str(self.__optimo)+
                            "      Desviación: "+str(porcentaje*100)+"%")
        self.__txt.escribir("\nCantidad de iteraciones: "+str(iterac))
        self.__txt.escribir("Nro de vehiculos: "+str(self.__nroVehiculos))
        self.__txt.escribir("Capacidad Maxima/Vehiculo: "+str(self.__capacidadMax))
        self.__txt.escribir("Tiempo total: " + str(int(tiempoTotal/60))+"min "+str(int(tiempoTotal%60))+"seg")
        tiempoTotal = time()-tiempoEstancamiento
        self.__txt.escribir("Tiempo de estancamiento: "+str(int(tiempoTotal/60))+"min "+str(int(tiempoTotal%60))+"seg")
        self.__txt.imprimir()

    def getCostoAsociadoRutas(self, rutas):
        acu = 0
        for r in rutas:
            acu += r.getCostoAsociado()
        return acu

    def getPermitidos(self, Aristas, lista_tabu, umbral, solucion):
        AristasNuevas = []
        ind_permitidos = np.array([], dtype = int)

        #No tengo en consideracion a las aristas que exceden el umbral y las que pertencen a S
        A_solucion = copy.copy(solucion.getA())
        for EP in Aristas:
            pertS = False
            i=0
            while(i < len(A_solucion)):
                A_S = A_solucion[i]
                if A_S == EP:
                    A_solucion.pop(i)
                    pertS = True
                    break
                i+=1
            if(not pertS and self.__umbralMin <= EP.getPeso() and EP.getPeso() <= umbral):
                AristasNuevas.append(EP)
                ind_permitidos = np.append(ind_permitidos, EP.getId())
        ind_permitidos = np.unique(ind_permitidos)

        return ind_permitidos, AristasNuevas

    #Decrementa el Tenure en caso de que no sea igual a -1. Si luego de decrementar es 0, lo elimino de la lista tabu
    def decrementaTenure(self, lista_tabu, ind_permitidos):
        i=0
        while (i < len(lista_tabu)):
            elemTabu=lista_tabu[i]
            elemTabu.decrementaT()
            if(elemTabu.getTenure()==0):
                ind_permitidos = np.append(ind_permitidos, elemTabu.getElemento().getId())
                lista_tabu.pop(i)
                i-=1
            i+=1
    
    def compartir(self, ind_permitidos, Aristas):
        print ("\nCompartiendo    <<<<---------------------------------------------------------------- MPI")
        #self.__rank = self.__comm.Get_rank()
        cond_Estancamiento = False
        listaS = self.__comm.allgather((self.__S, self.__rank,self.__rutas, ind_permitidos,Aristas)) #solucion_refer, Aristas, lista_tabu, nueva_solucion, ind_permitidos, ind_permitidos, self.__rutas, Aristas, lista_tabu, ind_permitidos, rutas_refer, self._G, nueva_solucion
        smCosto = listaS[0]
        ind = -1
        for i in range(1,len(listaS)):
            if(listaS[i][0].getCostoAsociado() < smCosto[0].getCostoAsociado()):
                smCosto = listaS[i]
                ind_permitidos = listaS[i][3]
                Aristas = listaS[i][4]
                ind = i
        self.__costoAnterior = self.__S.getCostoAsociado()
        print("Costo: ", self.__S.getCostoAsociado())
        if(self.__costoAnterior == smCosto[0].getCostoAsociado()):
            print("Todavia no encontre sol optima desde la ultima vez q se compartio")
            cond_Estancamiento = True
        else:
            self.__S = copy.deepcopy(smCosto[0])
            self.__rutas = copy.deepcopy(smCosto[2])
            aux = listaS.pop(ind)
            # Eliminamos repetidos
            i = 0
            while i < len(listaS):
                j=i+1
                while j < len(listaS):
                    if listaS[i][0] == listaS[j][0]:
                        listaS.pop(j)
                        #print ("Se quitó una solución repetida")
                    else:
                        j+=1
                i+=1
            # Eliminamos optimos locales que ya existen en las soluciones
            i = 0
            while i < len(self.__optimosLocales):
                j = i
                while j < len(listaS):
                    costo = abs(self.getCostoAsociadoRutas(self.__optimosLocales[i]) - self.getCostoAsociadoRutas(listaS[j][2]))
                    if costo<0.00001:
                        listaS.pop(j)
                        #print ("Se quitó una solución repetida con el mismo peso que un óptimo local")
                    else:
                        j+=1
                i+=1
            for tupla in listaS:
                self.__optimosLocales.append(tupla[2])
            self.__optimosLocales.append(aux[2])
            while len(self.__optimosLocales) >= 15:
                self.__optimosLocales.pop(0)
            indOptimosLocales = -2
            if self.__rank == 0:
                self.__mpiTxt.escribir("Compartiendo soluciones:")
                self.__mpiTxt.escribir("Mejor solucion encontrada de nodo %d: \n %s"%(smCosto[1], str(smCosto[0])))
        tCoord=time()

        return tCoord, cond_Estancamiento    
Exemplo n.º 10
0
class CVRP:
    def __init__(self, M, D, nroV, capac, archivo, carpeta, solI, tADD, tDROP,
                 tiempo, porcentaje, optimo):
        self._G = Grafo(M, D, True)  #Grafo original
        self.__S = Solucion(M, D, capac, nroV)  #Solucion general del CVRP
        self.__Distancias = M  #Mareiz de distancias
        self.__Demandas = D  #Demandas de los clientes
        self.__capacidadMax = capac  #Capacidad max por vehiculo
        self.__rutas = []  #Soluciones por vehiculo (lista de soluciones)
        self.__nroVehiculos = nroV  #Nro de vehiculos disponibles
        self.__tipoSolucionIni = solI  #Tipo de solucion inicial (Clark & Wright, Vecino cercano, Secuencial o al Azar)
        self.__beta = 1  #Parametro de dispersion
        self.__umbralMin = 0  #Umbral de granularidad minimo
        self.__optimosLocales = []  #Lista de optimos locales
        self.__porcentajeParada = float(
            porcentaje)  #Porcentaje de desvio minimo como condicion de parada
        self.__optimo = optimo  #Mejor valor de la instancia
        self.__tenureADD = tADD
        self.__tenureMaxADD = int(tADD * 1.7)
        self.__tenureDROP = tDROP
        self.__tenureMaxDROP = int(tDROP * 1.7)
        self.__txt = clsTxt(str(archivo))
        self.__tiempoMaxEjec = float(tiempo)
        self.escribirDatos()
        t = time()
        self.__S.rutasIniciales(self.__tipoSolucionIni)
        print("Rutas iniciales: ", time() - t)
        print(self.__S)
        self.tabuSearch()
        #self.Grafico = Grafico(coord,rutas)

    #Escribe los datos iniciales: el grafo inicial y la demanda
    def escribirDatos(self):
        self.__txt.escribir(
            "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ GRAFO CARGADO +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )
        self.__txt.escribir(str(self._G))
        cad = "\nDemandas:"
        for v in self._G.getV():
            cad_aux = str(v) + ": " + str(v.getDemanda())
            cad += "\n" + cad_aux
        self.__txt.escribir(cad)
        print("\nSuma Demanda: ", sum(self.__Demandas))
        print("Nro vehiculos: ", self.__nroVehiculos)
        self.__txt.escribir(
            "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ SOLUCION INICIAL +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )

    #Carga la solucion general a partir de las rutas

    #Umbral de granularidad: phi = Beta*(c/(n+k))
    #Beta = 1  parametro de dispersion. Sirve para modificar el grafo disperso para incluir la diversificación y la intensificación
    #          durante la búsqueda.
    #c = valor de una sol. inicial
    #k = nro de vehiculos
    #n = nro de clientes
    def calculaUmbral(self, costo):
        c = costo
        k = self.__nroVehiculos
        n = len(self.__Distancias) - 1
        phi = c / (n + k)
        phi = phi * self.__beta
        return round(phi, 3)

    def mostrarError(self):
        porcentaje = round(self.__S.getCostoTotal() / self.__optimo - 1.0, 3)
        print(str(round(porcentaje * 100, 3)) + "%")

    #+-+-+-+-+-+-+- Empezamos con Tabu Search +-+-+-+-+-+-+-+-+#
    #lista_tabu: tiene objetos de la clase Tabu (una arista con su tenure)
    #Lista_permitidos: o grafo disperso tiene elementos del tipo Arista que no estan en la lista tabu y su distancia es menor al umbral
    #nuevas_rutas: nuevas rutas obtenidas a partir de los intercambios
    #nueva_solucion: nueva solucion obtenida a partir de los intercambios
    #rutas_refer: rutas de referencia que sirve principalmente para evitar estancamiento, admitiendo una solucion peor y hacer los intercambios
    #             a partir de esas
    #solucion_refer: idem al anterior
    #tiempoIni: tiempo inicial de ejecucion - tiempoMax: tiempo maximo de ejecucion - tiempoEjecuc: tiempo de ejecución actual
    #iteracEstancamiento: iteraciones de estancamiento para admitir una solución peor, modificar Beta y escapar del estancamiento
    #iterac: cantidad de iteraciones actualmente
    def tabuSearch(self):
        lista_tabu = []
        ind_permitidos = np.array([], dtype=int)
        # tiempo=time()
        solucion_refer = copy.deepcopy(self.__S)
        nueva_solucion = solucion_refer
        nuevo_costo = self.__S.getCostoTotal()
        # print("tiempo deepcopy: "+str(time()-tiempo))

        #Atributos de tiempo e iteraciones
        tiempoIni = time()
        tiempoMax = float(self.__tiempoMaxEjec * 60)
        tiempoEstancamiento = tiempoIni
        tiempoEjecuc = 0
        iteracEstancamiento = 1
        iteracEstancamiento_Opt = 1
        iteracEstancMax = 300
        iterac = 1
        indOptimosLocales = -2
        umbral = self.calculaUmbral(self.__S.getCostoTotal())
        porc_Estancamiento = 1.05
        porc_EstancamientoMax = 1.15
        cond_Optimiz = True
        cond_Estancamiento = False

        N = self._G.getGrado()
        Aristas_Opt = []
        ind_permitidos = []

        for i in range(1, N):
            j = i + 1
            while (j < N):
                A = self._G.buscarArista((i, j))
                if (A.getPeso() <= umbral):
                    Aristas_Opt.append(A)
                    ind_permitidos.append(A.getId())
                j += 1
        Aristas = Aristas_Opt
        ind_AristasOpt = copy.deepcopy(ind_permitidos)
        print(self.__S)
        self.__optimosLocales.append(nueva_solucion)
        #print(Aristas_Opt)

        porcentaje = round(self.__S.getCostoTotal() / self.__optimo - 1.0, 3)
        print("Costo sol Inicial: " + str(self.__S.getCostoTotal()) +
              "      ==> Optimo: " + str(self.__optimo) + "  Desvio: " +
              str(round(porcentaje * 100, 3)) + "%")

        while (tiempoEjecuc < tiempoMax
               and porcentaje * 100 > self.__porcentajeParada):
            if (cond_Optimiz):
                #tiempo = time()
                ind_permitidos, Aristas = self.getPermitidos(
                    Aristas, lista_tabu, umbral,
                    solucion_refer)  #Lista de elementos que no son tabu
                self.__umbralMin = 0
                #print("Tiempo getPermitidos: ", (time()-tiempo))
            #print("ind_AristasOpt: "+str(ind_AristasOpt))
            cond_Optimiz = False
            ADD = []
            DROP = []

            ind_random = np.arange(0, len(ind_permitidos))
            random.shuffle(ind_random)

            indRutas = indAristas = []
            nuevo_costo, k_Opt, indRutas, indAristas, aristasADD, aristasDROP = nueva_solucion.evaluarOpt(
                self._G.getA(), ind_permitidos, ind_random)
            nuevo_costo = round(nuevo_costo, 3)

            tenureADD = self.__tenureADD
            tenureDROP = self.__tenureDROP

            costoSolucion = self.__S.getCostoTotal()
            tiempo = time()
            #Si encontramos una mejor solucion que la tomada como referencia
            if (nuevo_costo < solucion_refer.getCostoTotal()
                    and nuevo_costo != float("inf")):
                cad = "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Iteracion %d  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n" % (
                    iterac)
                self.__txt.escribir(cad)
                # cad = "Rutas antes:"
                # for i in indRutas:
                #     cad+="\nruta #%d: %s"%(i,str(nuevas_rutas[i].getA()))
                # print(cad)
                # print("Opcion: Swap %d-opt opcion: %d " %(k_Opt[0], k_Opt[1]))
                # print("ADD: %s          DROP: %s" %(str(aristasADD), str(aristasDROP)))
                # print("indADD: "+str(indAristas))
                nueva_solucion.swap(k_Opt, aristasADD[0], indRutas, indAristas)

                # cad = "\nRUtas ahora:"
                # for i in indRutas:
                #     cad+="\nruta #%d: %s"%(i,str(nuevas_rutas[i].getA()))
                #print(cad)
                # print("nuevo costo: ", nuevo_costo)
                # print("nueva solucion (cargaSolucion): ", nueva_solucion.getCostoAsociado())
                # print("costo solucion: ", costoSolucion)
                # print("costo solucion: ", self.__S.getCostoAsociado())
                # print("Opcion: Swap %d-opt opcion: %d " %(k_Opt[0], k_Opt[1]))
                # print("ADD: %s          DROP: %s" %(str(aristasADD), str(aristasDROP)))
                # print("indADD: "+str(indAristas))

                solucion_refer = nueva_solucion
                # print("Tiempo swap: "+str(time()-tiempo))
                #Si la nueva solucion es mejor que la obtenida hasta el momento
                if (nuevo_costo < costoSolucion):
                    porcentaje = round(nuevo_costo / self.__optimo - 1.0, 3)
                    tiempoTotal = time() - tiempoEstancamiento
                    print(cad)
                    cad = "\nLa solución anterior duró " + str(
                        int(tiempoTotal / 60)) + "min " + str(
                            int(tiempoTotal % 60))
                    cad += "seg    -------> Nuevo optimo local. Costo: " + str(
                        nuevo_costo)
                    cad += "       ==> Optimo: " + str(
                        self.__optimo) + "  Desvio: " + str(
                            porcentaje * 100) + "%"
                    self.__S = nueva_solucion
                    self.__beta = 1
                    tiempoEstancamiento = time()
                    if (len(self.__optimosLocales) >= 15):
                        self.__optimosLocales.pop(0)
                    self.__optimosLocales.append(nueva_solucion)
                    indOptimosLocales = -2
                    print(cad)
                else:
                    cad += "\nSolucion peor. Costo: " + str(
                        nueva_solucion.getCostoTotal())
                cad += "\nLista tabu: " + str(lista_tabu)
                self.__txt.escribir(cad)
                umbral = self.calculaUmbral(nueva_solucion.getCostoTotal())
                tenureADD = self.__tenureMaxADD
                tenureDROP = self.__tenureMaxDROP
                cond_Optimiz = True
                Aristas = Aristas_Opt
                iteracEstancamiento = 1
                iteracEstancamiento_Opt = 1
                iteracEstancMax = 300
            #Si se estancó, tomamos a beta igual a 2
            elif (iteracEstancamiento > iteracEstancMax and self.__beta < 2):
                tiempoTotal = time() - tiempoEstancamiento
                print(
                    "Se estancó durante %d min %d seg. Incrementanos Beta para diversificar"
                    % (int(tiempoTotal / 60), int(tiempoTotal % 60)))
                self.__beta = 2
                self.__umbralMin = umbral
                umbral = self.calculaUmbral(nueva_solucion.getCostoTotal())
                cond_Optimiz = True
                iteracEstancamiento = 1
                iteracEstancMax = 200
                Aristas = Aristas_Opt
            #Si se estancó nuevamente, tomamos la proxima sol peor que difiera un 5% del optimo o la penultima de los optimos locales
            elif (iteracEstancamiento > iteracEstancMax
                  and len(self.__optimosLocales) >= indOptimosLocales * (-1)):
                solucion_peor = self.__optimosLocales[indOptimosLocales]
                nueva_solucion = copy.deepcopy(solucion_peor)
                costo = nueva_solucion.getCostoTotal()
                tiempoTotal = time() - tiempoEstancamiento
                cad = "Se estancó durante %d min %d seg. Admitimos el penultimo optimo local " % (
                    int(tiempoTotal / 60), int(tiempoTotal % 60))
                print(cad + "-->    Costo: " + str(costo))
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                umbral = self.calculaUmbral(costo)
                solucion_refer = copy.deepcopy(nueva_solucion)
                cond_Optimiz = True
                Aristas = Aristas_Opt
                iteracEstancamiento = 1
                indOptimosLocales -= 1
                iteracEstancMax = 100
                self.__beta = 3
            elif (iteracEstancamiento > iteracEstancMax
                  and costoSolucion * porc_Estancamiento > nuevo_costo):
                nueva_solucion.swap(k_Opt, aristasADD[0], indRutas, indAristas)
                tiempoTotal = time() - tiempoEstancamiento
                costo = nueva_solucion.getCostoTotal()
                cad = "Se estancó durante %d min %d seg. Admitimos una solucion peor para diversificar" % (
                    int(tiempoTotal / 60), int(tiempoTotal % 60))
                print(cad + "-->    Costo: " + str(costo))
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                umbral = self.calculaUmbral(costo)
                solucion_refer = copy.deepcopy(nueva_solucion)
                cond_Optimiz = True
                iteracEstancamiento = 1
                Aristas = Aristas_Opt
                iteracEstancMax = 300
            elif (iteracEstancamiento > iteracEstancMax):
                nueva_solucion.swap(k_Opt, aristasADD[0], indRutas, indAristas)
                solucion_refer = copy.deepcopy(nueva_solucion)
                cond_Optimiz = True
                self.__beta = 3
                lista_tabu = []
                ind_permitidos = ind_AristasOpt
                umbral = self.calculaUmbral(costo)
            else:
                nueva_solucion = solucion_refer

            #Añado y elimino de la lista tabu
            if (aristasADD != []):
                ADD.append(Tabu(aristasADD[0], tenureADD))
                for i in range(0, len(aristasDROP)):
                    DROP.append(Tabu(aristasDROP[i], tenureDROP))
                self.decrementaTenure(lista_tabu, ind_permitidos)
                lista_tabu.extend(DROP)
                lista_tabu.extend(ADD)
            else:
                #print("Lista tabu: "+str(lista_tabu))
                lista_tabu = []
                #print("ind permitidos antes: "+str(ind_permitidos))
                ind_permitidos = copy.copy(ind_AristasOpt)
                #print("ind permitidos despues: "+str(ind_permitidos))

            tiempoEjecuc = time() - tiempoIni
            iterac += 1
            iteracEstancamiento += 1
            iteracEstancamiento_Opt += 1
        #Fin del while. Imprimo los valores obtenidos

        print("\nMejor solucion obtenida: " + str(self.__S))
        tiempoTotal = time() - tiempoIni
        print("\nTermino!! :)")
        print("Tiempo total: " + str(int(tiempoTotal / 60)) + "min " +
              str(int(tiempoTotal % 60)) + "seg\n")
        self.__txt.escribir(
            "\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- Solucion Optima +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
        )
        sol_ini = ""
        for i in range(0, len(self.__rutas)):
            sol_ini += "\nRuta #" + str(i + 1) + ": " + str(
                self.__rutas[i].getV())
            sol_ini += "\nCosto asociado: " + str(
                self.__rutas[i].getCostoAsociado(
                )) + "      Capacidad: " + str(
                    self.__rutas[i].getCapacidad()) + "\n"
        self.__txt.escribir(sol_ini)
        porcentaje = round(self.__S.getCostoTotal() / self.__optimo - 1.0, 3)
        self.__txt.escribir("\nCosto total:  " +
                            str(self.__S.getCostoTotal()) +
                            "        Optimo real:  " + str(self.__optimo) +
                            "      Desviación: " + str(porcentaje * 100) + "%")
        self.__txt.escribir("\nCantidad de iteraciones: " + str(iterac))
        self.__txt.escribir("Nro de vehiculos: " + str(self.__nroVehiculos))
        self.__txt.escribir("Capacidad Maxima/Vehiculo: " +
                            str(self.__capacidadMax))
        self.__txt.escribir("Tiempo total: " + str(int(tiempoTotal / 60)) +
                            "min " + str(int(tiempoTotal % 60)) + "seg")
        tiempoTotal = time() - tiempoEstancamiento
        self.__txt.escribir("Tiempo de estancamiento: " +
                            str(int(tiempoTotal / 60)) + "min " +
                            str(int(tiempoTotal % 60)) + "seg")
        self.__txt.imprimir()

    def getPermitidos(self, Aristas, lista_tabu, umbral, solucion):
        AristasNuevas = []
        #ind_permitidos = np.array([], dtype = int)
        ind_permitidos = []
        #No tengo en consideracion a las aristas que exceden el umbral y las que pertencen a S
        #print(solucion.rutas)
        for EP in Aristas:
            cond1 = solucion.contieneArista(
                EP)  #Este es para la arista EP normal
            cond2 = solucion.contieneArista(
                EP.getAristaInvertida())  #Para la arista EP invertida
            if (self.__umbralMin <= EP.getPeso() and EP.getPeso() <= umbral
                    and not cond1 and not cond2):
                AristasNuevas.append(EP)
                ind_permitidos.append(EP.getId())
        ind_permitidos = np.unique(ind_permitidos)

        return ind_permitidos, AristasNuevas

    #Decrementa el Tenure en caso de que no sea igual a -1. Si luego de decrementar es 0, lo elimino de la lista tabu
    def decrementaTenure(self, lista_tabu, ind_permitidos):
        i = 0
        while (i < len(lista_tabu)):
            elemTabu = lista_tabu[i]
            elemTabu.decrementaT()
            if (elemTabu.getTenure() == 0):
                ind_permitidos = np.append(ind_permitidos,
                                           elemTabu.getElemento().getId())
                lista_tabu.pop(i)
                i -= 1
            i += 1