Source code for pso.clases.class_particula

################################################################################
#                              CLASE PARTÍCULA                                 #
################################################################################

[docs]class Particula: """ Esta clase representa nueva partícula con una posición inicial definida por una combinación de valores numéricos aleatorios y velocidad de 0. El rango de posibles valores para cada variable (posición) puede estar acotado. Al crear una nueva partícula, solo se dispone de información sobre su posición inicial y velocidad, el resto de atributos están vacíos. Parameters ---------- n_variables : `int` número de variables que definen la posición de la partícula. limites_inf : `list` or `numpy.ndarray`, optional límite inferior de cada variable. Si solo se quiere predefinir límites de alguna variable, emplear ``None``. Los ``None`` serán remplazados por el valor (-10**3). (default is ``None``) limites_sup : `list` or `numpy.ndarray`, optional límite superior de cada variable. Si solo se quiere predefinir límites de alguna variable, emplear ``None``. Los ``None`` serán remplazados por el valor (+10**3). (default is ``None``) verbose : `bool`, optional mostrar información de la partícula creada. (default is ``False``) Attributes ---------- n_variables : `int` número de variables que definen la posición de la partícula. limites_inf : `list` or `numpy.ndarray` límite inferior de cada variable. Si solo se quiere predefinir límites de alguna variable, emplear ``None``. Los ``None`` serán remplazados por el valor (-10**3). limites_sup : `list` or `numpy.ndarray` límite superior de cada variable. Si solo se quiere predefinir límites de alguna variable, emplear ``None``. Los``None`` serán remplazados por el valor (+10**3). mejor_valor : `numpy.ndarray` mejor valor que ha tenido la partícula hasta el momento. mejor_posicion : `numpy.ndarray` posición en la que la partícula ha tenido el mejor valor hasta el momento. valor : `float` valor actual de la partícula. Resultado de evaluar la función objetivo con la posición actual. velocidad : `numpy.ndarray` array con la velocidad actual de la partícula. posicion : `numpy.ndarray` posición actual de la partícula. Raises ------ raise Exception si `limites_inf` es distinto de None y su longitud no coincide con `n_variables`. raise Exception si `limites_sup` es distinto de None y su longitud no coincide con `n_variables`. Examples -------- Ejemplo creación partícula. >>> part = Particula( n_variables = 3, limites_inf = [-1,2,0], limites_sup = [4,10,20], verbose = True ) """ def __init__(self, n_variables, limites_inf=None, limites_sup=None, verbose=False): # Número de variables de la partícula self.n_variables = n_variables # Límite inferior de cada variable self.limites_inf = limites_inf # Límite superior de cada variable self.limites_sup = limites_sup # Posición de la partícula self.posicion = np.repeat(None, n_variables) # Velocidad de la parícula self.velocidad = np.repeat(None, n_variables) # Valor de la partícula self.valor = np.repeat(None, 1) # Mejor valor que ha tenido la partícula hasta el momento self.mejor_valor = None # Mejor posición en la que ha estado la partícula hasta el momento self.mejor_posicion = None # CONVERSIONES DE TIPO INICIALES # ---------------------------------------------------------------------- # Si limites_inf o limites_sup no son un array numpy, se convierten en # ello. if self.limites_inf is not None \ and not isinstance(self.limites_inf,np.ndarray): self.limites_inf = np.array(self.limites_inf) if self.limites_sup is not None \ and not isinstance(self.limites_sup,np.ndarray): self.limites_sup = np.array(self.limites_sup) # COMPROBACIONES INICIALES: EXCEPTIONS Y WARNINGS # ---------------------------------------------------------------------- if self.limites_inf is not None \ and len(self.limites_inf) != self.n_variables: raise Exception( "limites_inf debe tener un valor por cada variable. " + "Si para alguna variable no se quiere límite, emplear None. " + "Ejemplo: limites_inf = [10, None, 5]" ) elif self.limites_sup is not None \ and len(self.limites_sup) != self.n_variables: raise Exception( "limites_sup debe tener un valor por cada variable. " + "Si para alguna variable no se quiere límite, emplear None. " + "Ejemplo: limites_sup = [10, None, 5]" ) elif (self.limites_inf is None) or (self.limites_sup is None): warnings.warn( "Es altamente recomendable indicar los límites dentro de los " + "cuales debe buscarse la solución de cada variable. " + "Por defecto se emplea [-10^3, 10^3]." ) elif any(np.concatenate((self.limites_inf, self.limites_sup)) == None): warnings.warn( "Los límites empleados por defecto cuando no se han definido " + "son: [-10^3, 10^3]." ) # COMPROBACIONES INICIALES: ACCIONES # ---------------------------------------------------------------------- # Si no se especifica limites_inf, el valor mínimo que pueden tomar las # variables es -10^3. if self.limites_inf is None: self.limites_inf = np.repeat(-10**3, self.n_variables) # Si no se especifica limites_sup, el valor máximo que pueden tomar las # variables es 10^3. if self.limites_sup is None: self.limites_sup = np.repeat(+10**3, self.n_variables) # Si los límites no son nulos, se reemplazan aquellas posiciones None por # el valor por defecto -10^3 y 10^3. if self.limites_inf is not None: self.limites_inf[self.limites_inf == None] = -10**3 if self.limites_sup is not None: self.limites_sup[self.limites_sup == None] = +10**3 # BUCLE PARA ASIGNAR UN VALOR A CADA UNA DE LAS VARIABLES QUE DEFINEN LA # POSICIÓN # ---------------------------------------------------------------------- for i in np.arange(self.n_variables): # Para cada posición, se genera un valor aleatorio dentro del rango # permitido para esa variable. self.posicion[i] = random.uniform( self.limites_inf[i], self.limites_sup[i] ) # LA VELOCIDAD INICIAL DE LA PARTÍCULA ES 0 # ---------------------------------------------------------------------- self.velocidad = np.repeat(0, self.n_variables) # INFORMACIÓN DEL PROCESO (VERBOSE) # ---------------------------------------------------------------------- if verbose: print("Nueva partícula creada") print("----------------------") print("Posición: " + str(self.posicion)) print("Límites inferiores de cada variable: " \ + str(self.limites_inf)) print("Límites superiores de cada variable: " \ + str(self.limites_sup)) print("Velocidad: " + str(self.velocidad)) print("") def __repr__(self): """ Información que se muestra cuando se imprime un objeto partícula. """ texto = "Partícula" \ + "\n" \ + "---------" \ + "\n" \ + "Posición: " + str(self.posicion) \ + "\n" \ + "Velocidad: " + str(self.velocidad) \ + "\n" \ + "Mejor posicion: " + str(self.mejor_posicion) \ + "\n" \ + "Mejor valor: " + str(self.mejor_valor) \ + "\n" \ + "Límites inferiores de cada variable: " \ + str(self.limites_inf) \ + "\n" \ + "Límites superiores de cada variable: " \ + str(self.limites_sup) \ + "\n" return(texto)
[docs] def evaluar_particula(self, funcion_objetivo, optimizacion, verbose = False): """ Este método evalúa una partícula calculando el valor que toma la función objetivo en la posición en la que se encuentra. Además, compara si la nueva posición es mejor que las anteriores. Modifica los atributos valor, mejor_valor y mejor_posicion de la partícula. Parameters ---------- funcion_objetivo : `function` función que se quiere optimizar. optimizacion : {'maximizar', 'minimizar'} dependiendo de esto, el mejor valor histórico de la partícula será el mayor o el menor valor que ha tenido hasta el momento. verbose : `bool`, optional mostrar información del proceso por pantalla. (default is ``False``) Raises ------ raise Exception si el argumento `optimizacion` es distinto de 'maximizar' o 'minimizar'. Examples -------- Ejemplo evaluar partícula con una función objetivo. >>> part = Particula( n_variables = 3, limites_inf = [-1,2,0], limites_sup = [4,10,20], verbose = True ) >>> def funcion_objetivo(x_0, x_1, x_2): f= x_0**2 + x_1**2 + x_2**2 return(f) >>> part.evaluar_particula( funcion_objetivo = funcion_objetivo, optimizacion = "maximizar", verbose = True ) """ # COMPROBACIONES INICIALES: EXCEPTIONS Y WARNINGS # ---------------------------------------------------------------------- if not optimizacion in ["maximizar", "minimizar"]: raise Exception( "El argumento optimizacion debe ser: 'maximizar' o 'minimizar'" ) # EVALUACIÓN DE LA FUNCIÓN OBJETIVO EN LA POSICIÓN ACTUAL # ---------------------------------------------------------------------- self.valor = funcion_objetivo(*self.posicion) # MEJOR VALOR Y POSICIÓN # ---------------------------------------------------------------------- # Se compara el valor actual con el mejor valor histórico. La comparación # es distinta dependiendo de si se desea maximizar o minimizar. # Si no existe ningún valor histórico, se almacena el actual. Si ya # existe algún valor histórico se compara con el actual y, de ser mejor # este último, se sobrescribe. if self.mejor_valor is None: self.mejor_valor = np.copy(self.valor) self.mejor_posicion = np.copy(self.posicion) else: if optimizacion == "minimizar": if self.valor < self.mejor_valor: self.mejor_valor = np.copy(self.valor) self.mejor_posicion = np.copy(self.posicion) else: if self.valor > self.mejor_valor: self.mejor_valor = np.copy(self.valor) self.mejor_posicion = np.copy(self.posicion) # INFORMACIÓN DEL PROCESO (VERBOSE) # ---------------------------------------------------------------------- if verbose: print("La partícula ha sido evaluada") print("-----------------------------") print("Valor actual: " + str(self.valor)) print("")
[docs] def mover_particula(self, mejor_p_enjambre, inercia=0.8, peso_cognitivo=2, peso_social=2, verbose=False): """ Este método ejecuta el movimiento de una partícula, lo que implica actualizar su velocidad y posición. No se permite que la partícula salga de la zona de búsqueda acotada por los límites. Parameters ---------- mejor_p_enjambre : `np.narray` mejor posición de todo el enjambre. inercia : `float`, optional coeficiente de inercia. (default is 0.8) peso_cognitivo : `float`, optional coeficiente cognitivo. (default is 2) peso_social : `float`, optional coeficiente social. (default is 2) verbose : `bool`, optional mostrar información del proceso por pantalla. (default is ``False``) Examples -------- Ejemplo mover partícula. >>> part = Particula( n_variables = 3, limites_inf = [-1,2,0], limites_sup = [4,10,20], verbose = True ) >>> def funcion_objetivo(x_0, x_1, x_2): f= x_0**2 + x_1**2 + x_2**2 return(f) >>> part.evaluar_particula( funcion_objetivo = funcion_objetivo, optimizacion = "maximizar", verbose = True ) >>> part.mover_particula( mejor_p_enjambre = np.array([-1000,-1000,+1000]), inercia = 0.8, peso_cognitivo = 2, peso_social = 2, verbose = True ) """ # ACTUALIZACIÓN DE LA VELOCIDAD # ---------------------------------------------------------------------- componente_velocidad = inercia * self.velocidad r1 = np.random.uniform(low=0.0, high=1.0, size = len(self.velocidad)) r2 = np.random.uniform(low=0.0, high=1.0, size = len(self.velocidad)) componente_cognitivo = peso_cognitivo * r1 * (self.mejor_posicion \ - self.posicion) componente_social = peso_social * r2 * (mejor_p_enjambre \ - self.posicion) nueva_velocidad = componente_velocidad + componente_cognitivo \ + componente_social self.velocidad = np.copy(nueva_velocidad) # ACTUALIZACIÓN DE LA POSICIÓN # ---------------------------------------------------------------------- self.posicion = self.posicion + self.velocidad # COMPROBAR LÍMITES # ---------------------------------------------------------------------- # Se comprueba si algún valor de la nueva posición supera los límites # impuestos. En tal caso, se sobrescribe con el valor del límite # correspondiente y se reinicia a 0 la velocidad de la partícula en esa # componente. for i in np.arange(len(self.posicion)): if self.posicion[i] < self.limites_inf[i]: self.posicion[i] = self.limites_inf[i] self.velocidad[i] = 0 if self.posicion[i] > self.limites_sup[i]: self.posicion[i] = self.limites_sup[i] self.velocidad[i] = 0 # INFORMACIÓN DEL PROCESO (VERBOSE) # ---------------------------------------------------------------------- if verbose: print("La partícula se ha desplazado") print("-----------------------------") print("Nueva posición: " + str(self.posicion)) print("")