# %matplotlib notebook import numpy as np import matplotlib.pyplot as plt import sys from mpl_toolkits.mplot3d import Axes3D import math import random ########################################### #PARAMETROS DEL PROBLEMA 16 X 10 clientes = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63] ##Vector de clientes servicios = [0,1,2,3,4,5,6,7,8,9] #Vector de servicios cap = [28512,18144,10692,9072,7128,6804,5346,4536,3564,3402] #Capacidad máxima de los modulos del INEs distancia = [ [0.450,0.450,0.450,0.450,37.5,37.5,37.5,37.5,34.6,34.6,34.6,34.6,40.4,40.4,40.4,40.4,25,25,25,25,28.6,28.6,28.6,28.6,40.1,40.1,40.1,40.1,37.6,37.6,37.6,37.6,39.3,39.3,39.3,39.3,36.9,36.9,36.9,36.9,33.1,33.1,33.1,33.1,31.7,31.7,31.7,31.7,43.3,43.3,43.3,43.3,17.2,17.2,17.2,17.2,37.6,37.6,37.6,37.6,12.7,12.7,12.7,12.7], [35.1,35.1,35.1,35.1,24.8,24.8,24.8,24.8,14.9,14.9,14.9,14.9,0.4,0.4,0.4,0.4,13.4,13.4,13.4,13.4,16.4,16.4,16.4,16.4,6.8,6.8,6.8,6.8,23.5,23.5,23.5,23.5,24.7,24.7,24.7,24.7,22.6,22.6,22.6,22.6,5.5,5.5,5.5,5.5,32.9,32.9,32.9,32.9,30.2,30.2,30.2,30.2,18.4,18.4,18.4,18.4,23.3,23.3,23.3,23.3,27,27,27,27], [24.9,24.9,24.9,24.9,18,18,18,18,16,16,16,16,11.7,11.7,11.7,11.7,5.1,5.1,5.1,5.1,9.9,9.9,9.9,9.9,17.3,17.3,17.3,17.3,23.2,23.2,23.2,23.2,18.2,18.2,18.2,18.2,16,16,16,16,10.2,10.2,10.2,10.2,32.5,32.5,32.5,32.5,23.5,23.5,23.5,23.5,7.9,7.9,7.9,7.9,22.9,22.9,22.9,22.9,15.8,15.8,15.8,15.8], [34,34,34,34,17.7,17.7,17.7,17.7,8.6,8.6,8.6,8.6,5.2,5.2,5.2,5.2,8.6,8.6,8.6,8.6,9.7,9.7,9.7,9.7,8.3,8.3,8.3,8.3,24.3,24.3,24.3,24.3,20.8,20.8,20.8,20.8,18.7,18.7,18.7,18.7,0.550,0.550,0.550,0.550,33.7,33.7,33.7,33.7,26.3,26.3,26.3,26.3,17.1,17.1,17.1,17.1,23.8,23.8,23.8,23.8,24.5,24.5,24.5,24.5], [31.1,31.1,31.1,31.1,41.7,41.7,41.7,41.7,35.7,35.7,35.7,35.7,30.4,30.4,30.4,30.4,33.6,33.6,33.6,33.6,33.4,33.4,33.4,33.4,38.3,38.3,38.3,38.3,9.5,9.5,9.5,9.5,41.7,41.7,41.7,41.7,39.5,39.5,39.5,39.5,31,31,31,31,0.170,0.170,0.170,0.170,47.1,47.1,47.1,47.1,24,24,24,24,12.8,12.8,12.8,12.8,34.9,34.9,34.9,34.9], [42.7,42.7,42.7,42.7,7.7,7.7,7.7,7.7,15.9,15.9,15.9,15.9,30.6,30.6,30.6,30.6,19.5,19.5,19.5,19.5,14.7,14.7,14.7,14.7,30.5,30.5,30.5,30.5,43.9,43.9,43.9,43.9,6,6,6,6,7.9,7.9,7.9,7.9,26.6,26.6,26.6,26.6,47.2,47.2,47.2,47.2,0.35,0.35,0.35,0.35,25.4,25.4,25.4,25.4,43.6,43.6,43.6,43.6,34.5,34.5,34.5,34.5], [16.3,16.3,16.3,16.3,18.3,18.3,18.3,18.3,19.6,19.6,19.6,19.6,16.9,16.9,16.9,16.9,9.5,9.5,9.5,9.5,13.5,13.5,13.5,13.5,23.2,23.2,23.2,23.2,21.2,21.2,21.2,21.2,22.1,22.1,22.1,22.1,19.6,19.6,19.6,19.6,17.5,17.5,17.5,17.5,24,24,24,24,27.2,27.2,27.2,27.2,2.1,2.1,2.1,2.1,21,21,21,21,9.1,9.1,9.1,9.1], [18.9,18.9,18.9,18.9,19.4,19.4,19.4,19.4,17.2,17.2,17.2,17.2,15.1,15.1,15.1,15.1,7.2,7.2,7.2,7.2,11.1,11.1,11.1,11.1,21.4,21.4,21.4,21.4,20.8,20.8,20.8,20.8,19.7,19.7,19.7,19.7,17.3,17.3,17.3,17.3,15.7,15.7,15.7,15.7,23.6,23.6,23.6,23.6,24.9,24.9,24.9,24.9,1.6,1.6,1.6,1.6,20.6,20.6,20.6,20.6,12.5,12.5,12.5,12.5], [31.9,31.9,31.9,31.9,37.6,37.6,37.6,37.6,27.3,27.3,27.3,27.3,22,22,22,22,25.2,25.2,25.2,25.2,29.3,29.3,29.3,29.3,25.7,25.7,25.7,25.7,5.4,5.4,5.4,5.4,37.9,37.9,37.9,37.9,35.4,35.4,35.4,35.4,22.6,22.6,22.6,22.6,13.7,13.7,13.7,13.7,43.1,43.1,43.1,43.1,20,20,20,20,1.2,1.2,1.2,1.2,29.6,29.6,29.6,29.6], [12.7,12.7,12.7,12.7,27.9,27.9,27.9,27.9,25.7,25.7,25.7,25.7,25.8,25.8,25.8,25.8,15.7,15.7,15.7,15.7,19.6,19.6,19.6,19.6,31.3,31.3,31.3,31.3,32.1,32.1,32.1,32.1,28.2,28.2,28.2,28.2,25.7,25.7,25.7,25.7,27.5,27.5,27.5,27.5,24.2,24.2,24.2,24.2,33.3,33.3,33.3,33.3,9.4,9.4,9.4,9.4,31.8,31.8,31.8,31.8,1.6,1.6,1.6,1.6] ] # Matriz de costos, el costo es la distancia en kilometros req = [ [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124], [8204,8204,8204,8203,2062,2062,2062,2062,2026,2026,2026,2027,1687,1687,1687,1687,1630,1630,1630,1631,1067,1067,1067,1068,951,951,951,950,921,921,921,921,861,861,861,861,688,688,688,688,661,661,661,662,531,531,531,529,321,321,321,322,156,156,156,157,136,136,136,135,125,125,124,124] ] #definiendo numero de individuos en la poblacion num_individuos = 100 #definiendo número de funciones objetivo num_func_objetivo = 2 distancia_max = 200 max_iteraciones = 2 #porcentaje de cruza p_crossover=1.0 p_mutate = 1.0 #Definiendo conjunto de soluciones iniciales poblacion = [[] for i in range(0,num_func_objetivo)] poblacion_evaluada = np.zeros((num_func_objetivo,num_individuos)) #Inicializando valores d = 1 #dimension menos 1 de las funciones lower_inic = None upper_inic = None lower_inic = lower_inic if lower_inic is not None else -np.ones((1, d)) upper_inic = upper_inic if upper_inic is not None else np.ones((1, d)) def funcion1(vector): #Funcion que minimiza el costo total Min (f1) = dijαXij suma = 0 #asignaciones = np.zeros(len(clientes)) for k in range(0,len(vector)): aux = distancia[vector[k]][k] alpha =1 X_ij = 1 aux = aux * alpha * X_ij suma = suma + aux return suma def funcion2(vector): aux_cap = cap suma = 0 for k in range(0,len(vector)): aux = req[vector[k]][k] aux_cap[vector[k]] = aux_cap[vector[k]] - aux Yij = 0 Dmij = 0 if (aux_cap[vector[k]] >= 0): Yij = 1 if (distancia[vector[k]][k] <= distancia_max): Dmij = 1 suma = suma + (aux*Yij*Dmij) return suma def inicializando_solucion(): #CREANDO MATRIZ DE DIMENSION (funciones x población) #print("POBLACION---",poblacion) for i in range(0,num_func_objetivo): for j in range(0,num_individuos): aux = [] for k in range(0,len(clientes)): aux.append(random.randint(0,len(servicios)-1)) print(aux) poblacion[i].append(aux) return poblacion def evalua(poblacion): #print("POBLACION EVALUADA---",poblacion) #input("") #Evaluando cada funcion objetivo for i in range(0,len(poblacion[0])):#Clientes #Evaluando respecto a funcion objetivo 1 #print("x-",poblacion[0][i]) res1 = funcion1(poblacion[0][i]) #print("Res x-",res1) poblacion_evaluada[0][i] = res1 #Evaluando respecto a funcion objetivo 2 #print("x-",poblacion[1][i]) res2 = funcion2(poblacion[1][i]) #print("Res x-",res2) poblacion_evaluada[1][i] = res2 return poblacion_evaluada def ordenamiento_no_dominado(poblacion_evaluada): #Ordenando los valores de columna de cada funcion objetivo de mayor a menor #print("NO ordenados---",poblacion_evaluada) poblacion_evaluada.sort(axis=0) #Ordena cada solumna de mayor a menor #Comienza a clasificar fornteras max_front = 0 #Establece el valor inicial máximo de frontera rank = [] front_id = np.inf*np.ones(len(poblacion_evaluada[0])) #Crea un vector con N elementos llamados "inf" #print("front_id---", front_id) #La función np.unique() recupera todos los indices de los valores únicos en la columna pop_cost[:,0] (primera columna de la funcion objetivo 1) #loc = np.unique(poblacion_evaluada[0]) #print("SI ordenados---",poblacion_evaluada) #print("loc--",loc) poblacion_evaluada = np.transpose(poblacion_evaluada) while np.sum(front_id < np.inf) < len(front_id): max_front += 1 #Aumenta uno a la frontera for i in np.where(front_id==np.inf)[0]: #recorre cada inf, si encuentra inf en el front_id #print("i--",i) #print("front_id--",front_id) #input("") dominated = False #Al principio no hay dominación for j in range(i, 0, -1):#Recorrido descendente, desde N hasta 0 if front_id[j-1] == max_front: m=2 while(m<=num_func_objetivo) and (poblacion_evaluada[i,m-1] >= poblacion_evaluada[j-1,m-1]): #Compara cada elemento de la segunda funcion objetivo para ver si cumple las condiciones m += 1 dominated = m > num_func_objetivo if dominated or num_func_objetivo==2: break if not dominated: front_id[i] = max_front print("Frontera a la que pertenece cada elemnto de la población") print(front_id) return front_id, max_front def crowding_distance(front_id): ''' Calcula la distancia de amontonamiento por cada frontera de Pareto Parametro de entrada: front_id, de dimensión (Nx1) donde front_i[i] es el número de frontera de pop[i] Valor de retorno: crowd_dis de dimensión (Nx1) contiene las distancias de amontonamiento ''' N = len(poblacion[0]) #Numero de individuos en la poblacion pop_cost = np.transpose(poblacion_evaluada) #Matriz con individuos de la población evaluados en cada una de las funciones objetivo #print("pop_cost--",pop_cost) crowd_dis = np.zeros(N) # Vector de dimension (1xN) fronts = np.unique(front_id) #Obtiene las fronteras no repetidas en fron_id fronts = fronts[fronts!=np.inf] #Deja todos las fronteras diferentes de "inf" #print("FRONTS--",fronts) for f in range(len(fronts)): #Recorre cada una de las N fronteras front = np.where(front_id==f+1)[0] #Selecciona elementos(ids) de la frontera si el identificador de la frontera es igual a la frontera (f) actualmente evaluada #print("Front-xxx---",front) fmax = np.max(pop_cost[front, :], axis=0) #Obtiene los valores maximos de cada funcion objetivo que están en front fmin = np.min(pop_cost[front, :], axis=0) #Obtiene los valores minimos de cada funcion objetivo que están en front #print("FMAX---",fmax) #print("FMIN---",fmin) for i in range(num_func_objetivo): #Ciclo desde 0 hasta (m) funciones objetivo rank = np.argsort(pop_cost[front, i]) #Ordena de menor a mayor los indices de cada uno de los valores de la frontera (f) crowd_dis[front[rank[0]]] = np.inf #Coloca un "inf" en cada uno de los primeros indices de rank y almacenarlo en crowd_dis crowd_dis[front[rank[-1]]] = np.inf #Coloca un "inf" en cada uno de los ultimos indices de rank y almacenarlo en crowd_dis #print("crowd_dis---",crowd_dis) for j in range(1, len(front)-1): #Se recorre los valores de la frontera pero sin considerar el valor del inicio y del final crowd_dis[front[rank[j]]] = crowd_dis[front[rank[j]]] + \ (pop_cost[front[rank[j+1]], i] - pop_cost[front[rank[j-1]], i]) / (fmax[i]-fmin[i]) #realiza la siguiente operacion para cada funcion objetivo(j+1 - j-1) /(fmax - fmin) return crowd_dis def tournament(fit, K=2): ''' Realiza torneo entre los individuos de la poblacion Parametros de entrada: K: Número de parámetros a considerar para el fitness fit: (N, K) Matriz de valores fitness, donde la columna más alta significa mayor preferencia Valor de retorno: indices de los individuos que ganaron el torneo ''' n_total = len(fit) #Numero total de individuos a = np.random.randint(n_total, size= num_individuos) #Vector de N numeros enteros aleatorios b = np.random.randint(n_total, size=(num_individuos, K)) # Matriz de (N x K) numeros enteros aleatorios for i in range(num_individuos): #Ciclo de 0 a N for j in range(K): #Ciclo de 0 a K for r in range(fit[0, :].size): #Ciclo de 0 al numero de columnas de (fit) if fit[b[i, j], r] < fit[a[i], r]: #Se eligen valores aleatorios dando prioridad a los valores con menor distancia de amontonamiento a[i] = b[i,j] return a def evolve(parents, boundary=None): #print("+++parents:--",parents) #input("") ''' Crea la descendencia de los padres a través de cruce + mutación Param: parents: (Nxm) matriz de padres para participar en la mutación boundary: límites (inferior, superior) de las restricciones ''' dis_c, dis_m = 500, 500 parents = parents[:(len(parents)//2)*2, :] (n, d) = parents.shape parent_1, parent_2 = parents[:n//2, :], parents[n//2:, :] ## CRUZA beta = np.empty((n//2, d)) mu = np.random.random((n//2, d)) beta[mu <= 0.5]= np.power(2 * mu[mu <= 0.5], 1 / (dis_c + 1)) beta[mu > 0.5] = np.power(2 * mu[mu > 0.5], -1 / (dis_c + 1)) beta = beta * ((-1)** np.random.randint(2, size=(n // 2, d))) beta[np.random.random((n // 2, d)) < 0.5] = 1 beta[np.tile(np.random.random((n // 2, 1)) > p_crossover, (1, d))] = 1 # beta=1 significa sin cruza offspring = np.vstack(((parent_1 + parent_2) / 2 + beta * (parent_1 - parent_2) / 2, (parent_1 + parent_2) / 2 - beta * (parent_1 - parent_2) / 2)) ## Mutacion site = np.random.random((n, d)) < p_mutate / d mu = np.random.random((n, d)) temp = site & (mu <= 0.5) if boundary is None: lower, upper = np.tile(lower_inic, (n, 1)), np.tile(upper_inic, (n,1)) else: lower, upper = boundary norm = (offspring[temp] - lower[temp]) / (upper[temp] - lower[temp]) offspring[temp] += (upper[temp] - lower[temp]) * \ (np.power(2. * mu[temp] + (1. - 2. * mu[temp]) * np.power(1. - norm, dis_m + 1.), 1. / (dis_m + 1)) - 1.) temp = ~temp norm = (upper[temp] - offspring[temp]) / (upper[temp] - lower[temp]) offspring[temp] += (upper[temp] - lower[temp])* \ (1. - np.power( 2. * (1. - mu[temp]) + 2. * (mu[temp] - 0.5) * np.power(1. - norm, dis_m + 1.), 1. / (dis_m + 1.))) offspring = np.maximum(np.minimum(offspring, upper), lower) return offspring def selection(): '''Realiza la selección del entorno de front_ids y crowding_distance ''' front_id, max_front = ordenamiento_no_dominado(poblacion_evaluada) max_front = max(front_id) next_label = np.zeros(front_id.shape[0], dtype=bool) next_label[front_id cap[i]): bandera = False print("falso") #print("cap--",cap[i]) #print("sumaa-",suma) #input("") if (bandera == True): print("AL FINNNN--",poblacion) input("") break '''for x in aux_modulos: matriz_cargas = [[] for i in range(len(servicios)) ] for i in range(0,len(x)): matriz_cargas[].append() ''' '''for a in range(0,len(aux_modulos)): aux = sum(aux_modulos[a]) sum_modulos.append(aux) if(aux <= cap[a]): bandera = True print("AL FINN") break ''' print(aux_modulos) print("sum_modulos--",sum_modulos) print(sum(sum_modulos)) return bandera ############################################################################################ print("Iniciando ejecución de NSGA-II") bandera_sobrecarga = False poblacion_inic =inicializando_solucion() print("Inicializando solución aleatoria: ",poblacion_inic) poblacion_evaluada = evalua(poblacion_inic) print("Evaluando cada individuo de la población: ",poblacion_evaluada) front_id, max_front = ordenamiento_no_dominado(poblacion_evaluada) print("Elementos no dominados: ", front_id) crowd_dis = crowding_distance(front_id) print("Calculando distancia de amontonamiento: ",crowd_dis) iteraciones = 0 poblacion = np.transpose(poblacion_evaluada) print("poblacion inicial--",poblacion) #input("") while (iteraciones >= 0 and iteraciones<=max_iteraciones or bandera_sobrecarga == False): fit = np.vstack((front_id, crowd_dis)).T #Concatena dos arreglos: front_id y crowd_dis y los transponeÇ #print("FIT--",fit) #input("") mating_pool = tournament(fit) #Realiza torneo entre los individuos de la población de acuerdo con la distancia de amontonamiento #print("Matting pool--",mating_pool) #input("") #print("Elementos elegidos del torneo: ",mating_pool) #print("población:--",poblacion) #parent = np.transpose([mating_pool, poblacion[:,mating_pool]]) parent = [np.transpose([mating_pool]),poblacion[np.transpose(mating_pool),:]] #print("PARENT----",parent) #parent = [np.transpose(np.array([mating_pool])),poblacion] #Selecciona a los padres a partir del torneo y la población inicial aux = parent[0].astype(float) offspring = evolve(aux) #Crea la cruza y mutación de los padres #print("offspring 11--",offspring) offspring_cost = evalua(poblacion_inic) #Evaluación de la nueva población P+1, mediante las N funciones objetivo #print("offspring_cost--",poblacion) #input("") #poblacion_inic = mating_pool #front_id, crowd_dis, _ = selection() poblacion = [[] for i in range(0,num_func_objetivo)] poblacion_inic =inicializando_solucion() poblacion_evaluada = evalua(poblacion_inic) print("Evaluando cada individuo de la población: ",poblacion_evaluada) front_id, max_front = ordenamiento_no_dominado(poblacion_evaluada) print("Elementos no dominados: ", front_id) crowd_dis = crowding_distance(front_id) print("Calculando distancia de amontonamiento: ",crowd_dis) poblacion = np.transpose(poblacion_evaluada) print("poblacion inicial--",poblacion) bandera_sobrecarga = evalua_sobrecarga(poblacion_inic) print("Número de iteration: {} ".format(iteraciones)) iteraciones = iteraciones + 1 print("Soluciones finales:", poblacion_inic) print("Evaluacion de soluciones:", poblacion_evaluada)