def _transition_packs(self, agents, n_c): """Transits coyotes between packs (Eq. 4). Args: agents (list): List of agents. n_c (int): Number of coyotes per pack. """ # Calculates the eviction probability p_e = 0.005 * len(agents) # Generates a uniform random number r1 = r.generate_uniform_random_number() # If random number is smaller than eviction probability if r1 < p_e: # Gathers two random packs p1 = r.generate_integer_random_number(high=self.n_p) p2 = r.generate_integer_random_number(high=self.n_p) # Gathers two random coyotes c1 = r.generate_integer_random_number(high=n_c) c2 = r.generate_integer_random_number(high=n_c) # Calculates their indexes i = n_c * p1 + c1 j = n_c * p2 + c2 # Performs a swap betweeh them agents[i], agents[j] = copy.deepcopy(agents[j]), copy.deepcopy( agents[i])
def _mutation(self, alpha): """Performs the mutation over an offspring (s. 3.4). Args: alpha (Agent): Offspring to be mutated. Returns: The mutated offspring. """ # Checks if the number of variables is bigger than one if alpha.n_variables > 1: # Samples a random integer r1 = r.generate_integer_random_number(0, alpha.n_variables) # Samples the second integer r2 = r.generate_integer_random_number(0, alpha.n_variables, exclude_value=r1) # Swaps the randomly selected variables alpha.position[r1], alpha.position[r2] = alpha.position[ r2], alpha.position[r1] return alpha
def update(self, space, function): """Wraps Symbiotic Organisms Search over all agents and variables. Args: space (Space): Space containing agents and update-related information. function (Function): A Function object that will be used as the objective function. """ # Iterates through all agents for i, agent in enumerate(space.agents): # Generates a random integer for mutualism and performs it j = r.generate_integer_random_number(0, len(space.agents), exclude_value=i) self._mutualism(agent, space.agents[j], space.best_agent, function) # Re-generates a random integer for commensalism and performs it j = r.generate_integer_random_number(0, len(space.agents), exclude_value=i) self._commensalism(agent, space.agents[j], space.best_agent, function) # Re-generates a random integer for parasitism and performs it j = r.generate_integer_random_number(0, len(space.agents), exclude_value=i) self._parasitism(agent, space.agents[j], function)
def _update(self, agents, function, n_c): """Method that wraps Coyote Optimization Algorithm over all agents and variables. Args: agents (list): List of agents. function (Function): A Function object that will be used as the objective function. n_c (int): Number of agents per pack. """ # Iterates through all packs for i in range(self.n_p): # Gets the agents for the specified pack pack_agents = self._get_agents_from_pack(agents, i, n_c) # Gathers the alpha coyote (Eq. 5) alpha = pack_agents[0] # Computes the cultural tendency (Eq. 6) tendency = np.median(np.array( [agent.position for agent in pack_agents]), axis=0) # Iterates through all coyotes in the pack for agent in pack_agents: # Makes a deepcopy of current coyote a = copy.deepcopy(agent) # Generates two random integers cr1 = r.generate_integer_random_number(high=len(pack_agents)) cr2 = r.generate_integer_random_number(high=len(pack_agents)) # Calculates the alpha and pack influences lambda_1 = alpha.position - pack_agents[cr1].position lambda_2 = tendency - pack_agents[cr2].position # Generates two random uniform numbers r1 = r.generate_uniform_random_number() r2 = r.generate_uniform_random_number() # Updates the social condition (Eq. 12) a.position += r1 * lambda_1 + r2 * lambda_2 # Checks the agent's limits a.clip_limits() # Evaluates the agent (Eq. 13) a.fit = function(a.position) # If the new potision is better than current agent's position (Eq. 14) if a.fit < agent.fit: # Replaces the current agent's position agent.position = copy.deepcopy(a.position) # Also replaces its fitness agent.fit = copy.deepcopy(a.fit) # Performs transition between packs (Eq. 4) self._transition_packs(agents, n_c)
def test_generate_integer_random_number(): integer_array = random.generate_integer_random_number(0, 1, None, 5) assert integer_array.shape == (5, ) integer_array = random.generate_integer_random_number(0, 10, 1, 5) assert integer_array.shape == (5, )
def _update(self, agents, function, iteration, n_iterations): """Method that wraps Artificial Butterfly Optimization over all agents and variables. Args: agents (list): List of agents. function (Function): A Function object that will be used as the objective function. iteration (int): Current iteration. n_iterations (int): Maximum number of iterations. """ # Sorting agents agents.sort(key=lambda x: x.fit) # Calculates the number of sunspot butterflies n_sunspots = int(self.sunspot_ratio * len(agents)) # Iterates through all sunspot butterflies for agent in agents[:n_sunspots]: # Generates the index for a random sunspot butterfly k = r.generate_integer_random_number(0, len(agents)) # Performs a flight mode using sunspot butterflies (eq. 1) agent.position, agent.fit, _ = self._flight_mode(agent, agents[k], function) # Iterates through all canopy butterflies for agent in agents[n_sunspots:]: # Generates the index for a random canopy butterfly k = r.generate_integer_random_number(0, len(agents) - n_sunspots) # Performs a flight mode using canopy butterflies (eq. 1) agent.position, agent.fit, is_better = self._flight_mode(agent, agents[k], function) # If there was not fitness replacement if not is_better: # Generates the index for a random butterfly k = r.generate_integer_random_number(0, len(agents)) # Generates random uniform number r1 = r.generate_uniform_random_number() # Calculates `D` (eq. 4) D = np.fabs(2 * r1 * agents[k].position - agent.position) # Generates another random uniform number r2 = r.generate_uniform_random_number() # Linearly decreases `a` a = (self.a - self.a * (iteration / n_iterations)) # Updates the agent's position (eq. 3) agent.position = agents[k].position - 2 * a * r2 - a * D # Clips its limits agent.clip_limits() # Re-calculates its fitness agent.fit = function(agent.position)
def _crossover(self, agents: List[Agent], trial_agents: List[Agent]) -> None: """Performs the crossover operator. Args: agents: List of agents. trial_agents: List of trial agents. """ # Defines the number of agents and variables n_agents = len(agents) n_variables = agents[0].n_variables # Creates a crossover map cross_map = np.ones((n_agents, n_variables)) # Generates the `a` and `b` random uniform numbers a = r.generate_uniform_random_number() b = r.generate_uniform_random_number() # If `a` is smaller than `b` if a < b: # Iterates through all agents for i in range(n_agents): # Generates a uniform random number r1 = r.generate_uniform_random_number() # Calculates the number of non-crosses non_crosses = int(self.mix_rate * r1 * n_variables) # Iterates through the number of non-crosses for _ in range(non_crosses): # Generates a random decision variable index u = r.generate_integer_random_number(high=n_variables) # Turn off the crossing on this specific point cross_map[i][u] = 0 # If `a` is bigger than `b` else: # Iterates through all agents for i in range(n_agents): # Generates a random decision variable index j = r.generate_integer_random_number(high=n_variables) # Turn off the crossing on this specific point cross_map[i][j] = 0 # Iterates through all agents for i in range(n_agents): # Iterates through all decision variables for j in range(n_variables): # If it is supposed to cross according to the map if cross_map[i][j]: # Makes a deep copy on such position trial_agents[i].position[j] = copy.deepcopy( agents[i].position[j])
def update(self, space: Space, function: Function) -> None: """Wraps Coyote Optimization Algorithm over all agents and variables. Args: space: Space containing agents and update-related information. function: A Function object that will be used as the objective function. """ # Iterates through all packs for i in range(self.n_p): # Gets the agents for the specified pack pack_agents = self._get_agents_from_pack(space.agents, i) # Gathers the alpha coyote (eq. 5) alpha = pack_agents[0] # Computes the cultural tendency (eq. 6) tendency = np.median(np.array( [agent.position for agent in pack_agents]), axis=0) # Iterates through all coyotes in the pack for agent in pack_agents: # Makes a deep copy of current coyote a = copy.deepcopy(agent) # Generates two random integers cr1 = r.generate_integer_random_number(high=len(pack_agents)) cr2 = r.generate_integer_random_number(high=len(pack_agents)) # Calculates the alpha and pack influences lambda_1 = alpha.position - pack_agents[cr1].position lambda_2 = tendency - pack_agents[cr2].position # Generates two random uniform numbers r1 = r.generate_uniform_random_number() r2 = r.generate_uniform_random_number() # Updates the social condition (eq. 12) a.position += r1 * lambda_1 + r2 * lambda_2 # Checks the agent's limits a.clip_by_bound() # Evaluates the agent (eq. 13) a.fit = function(a.position) # If the new potision is better than current agent's position (eq. 14) if a.fit < agent.fit: # Replaces the current agent's position and fitness agent.position = copy.deepcopy(a.position) agent.fit = copy.deepcopy(a.fit) # Performs transition between packs (eq. 4) self._transition_packs(space.agents)
def _update(self, agents, best_agent, function): """Method that wraps global and local pollination updates over all agents and variables. Args: agents (list): List of agents. best_agent (Agent): Global best agent. function (Function): A Function object that will be used as the objective function. """ # Iterate through all agents for agent in agents: # Creates a temporary agent a = copy.deepcopy(agent) # Generating an uniform random number r1 = r.generate_uniform_random_number() # Check if generated random number is bigger than probability if r1 > self.p: # Update a temporary position according to global pollination a.position = self._global_pollination(agent.position, best_agent.position) else: # Generates an uniform random number epsilon = r.generate_uniform_random_number() # Generates an index for flower k k = r.generate_integer_random_number(0, len(agents)) # Generates an index for flower l l = r.generate_integer_random_number(0, len(agents), exclude_value=k) # Update a temporary position according to local pollination a.position = self._local_pollination(agent.position, agents[k].position, agents[l].position, epsilon) # Check agent limits a.clip_limits() # Calculates the fitness for the temporary position a.fit = function(a.position) # If new fitness is better than agent's fitness if a.fit < agent.fit: # Copy its position to the agent agent.position = copy.deepcopy(a.position) # And also copy its fitness agent.fit = copy.deepcopy(a.fit)
def update(self, space: Space, function: Function) -> None: """Wraps Flower Pollination Algorithm over all agents and variables. Args: space: Space containing agents and update-related information. function: A Function object that will be used as the objective function. """ # Iterates through all agents for agent in space.agents: # Creates a temporary agent a = copy.deepcopy(agent) # Generates an uniform random number r1 = r.generate_uniform_random_number() # Check if generated random number is bigger than probability if r1 > self.p: # Updates a temporary position according to global pollination a.position = self._global_pollination( agent.position, space.best_agent.position) else: # Generates an uniform random number epsilon = r.generate_uniform_random_number() # Generates an index for flower `k` and flower `l` k = r.generate_integer_random_number(0, len(space.agents)) l = r.generate_integer_random_number(0, len(space.agents), exclude_value=k) # Updates a temporary position according to local pollination a.position = self._local_pollination( agent.position, space.agents[k].position, space.agents[l].position, epsilon, ) # Checks agent's limits a.clip_by_bound() # Calculates the fitness for the temporary position a.fit = function(a.position) # If new fitness is better than agent's fitness if a.fit < agent.fit: # Copies its position and fitness to the agent agent.position = copy.deepcopy(a.position) agent.fit = copy.deepcopy(a.fit)
def _parasitism_phase( self, space: Space, n_crows: int, n_cuckoos: int, iteration: int, n_iterations: int, ): """Performs the parasitism phase using the current number of cuckoos. Args: space: Space containing agents and update-related information. n_crows: Number of crows. n_cuckoos: Number of cuckoos. iteration: Current iteration. n_iterations: Maximum number of iterations. """ # Gathers the cuckoos cuckoos = space.agents[n_crows:n_crows + n_cuckoos] # Calculates a list of cuckoos' fitness fitness = [cuckoo.fit for cuckoo in cuckoos] # Calculates the probability of selection p = iteration / n_iterations # Iterates through all cuckoos for cuckoo in cuckoos: # Selects a cuckoo through tournament selection s = g.tournament_selection(fitness, 1)[0] # Selects two random agents from the space i = r.generate_integer_random_number(high=space.n_agents) j = r.generate_integer_random_number(high=space.n_agents, exclude_value=i) # Creates a bernoulli distribution to preserve or not variables (eq. 12) k = d.generate_bernoulli_distribution(1 - p, cuckoo.n_variables) k = np.expand_dims(k, -1) # Calculates the gaussian-based step distribution (eq. 11) rand = r.generate_uniform_random_number() S_g = (space.agents[i].position - space.agents[j].position) * rand # Updates the cuckoo's position and clips its limits (eq. 10) cuckoo.position = space.agents[s].position + S_g * k cuckoo.clip_by_bound()
def update(self, space, function): """Wraps Wind Driven Optimization over all agents and variables. Args: space (Space): Space containing agents and update-related information. function (Function): A function object. """ # Iterates through all agents for i, agent in enumerate(space.agents): # Generates a random index based on the number of agents index = r.generate_integer_random_number(0, len(space.agents)) # Updates velocity (eq. 15) self.velocity[i] = (1 - self.alpha) * self.velocity[i] - self.g * agent.position + \ (self.RT * np.abs(1 / (index + 1) - 1) * (space.best_agent.position - agent.position)) + \ (self.c * self.velocity[index] / (index + 1)) # Clips the velocity values between [-v_max, v_max] self.velocity = np.clip(self.velocity, -self.v_max, self.v_max) # Updates agent's position (eq. 16) agent.position += self.velocity[i] # Checks agent limits agent.clip_by_bound() # Evaluates agent agent.fit = function(agent.position)
def _update(self, agents, memory): """Method that wraps the Crow Search Algorithm over all agents and variables. Args: agents (list): List of agents. memory (np.array): Array of memories. """ # Iterates through every agent for agent in agents: # Generates uniform random numbers r1 = r.generate_uniform_random_number() r2 = r.generate_uniform_random_number() # Generates a random integer (e.g. selects the crow) j = r.generate_integer_random_number(high=len(agents)) # Checks if first random number is greater than awareness probability if r1 >= self.AP: # Updates agent's position (Eq. 2) agent.position += r2 * self.fl * (memory[j] - agent.position) # If random number is smaller than probability else: # Generate a random position for j, (lb, ub) in enumerate(zip(agent.lb, agent.ub)): # For each decision variable, we generate uniform random numbers agent.position[j] = r.generate_uniform_random_number(lb, ub, size=agent.n_dimensions)
def _send_onlooker(self, agents: List[Agent], function: Function) -> None: """Sends onlooker bees to select new food sources (eq. 2.1). Args: agents: List of agents. function: A function object. """ # Calculates the fitness somatory total = sum(agent.fit for agent in agents) # Defines food sources' counter k = 0 # While counter is less than the amount of food sources while k < len(agents): # We iterate through every agent for i, agent in enumerate(agents): # Creates a random uniform number r1 = r.generate_uniform_random_number() # Calculates the food source's probability probs = (agent.fit / (total + c.EPSILON)) + 0.1 # If the random number is smaller than food source's probability if r1 < probs: # We need to increment the counter k += 1 # Gathers a random source to be used source = r.generate_integer_random_number(0, len(agents)) # Evaluate its location self._evaluate_location(agent, agents[source], function, i)
def _nesting_phase(self, space: Space, n_crows: int): """Performs the nesting phase using the current number of crows. Args: space: Space containing agents and update-related information. n_crows: Number of crows. """ # Gathers the crows crows = space.agents[:n_crows] # Iterates through all crows for i, crow in enumerate(crows): # Generates a random index idx = r.generate_integer_random_number(high=space.n_agents, exclude_value=i) # Calculates the step from Lévy distribution (eq. 7) step = d.generate_levy_distribution(size=crow.n_variables) step = np.expand_dims(step, axis=1) # Updates the crow's position and clips its bounds (eq. 6 and 8) crow.position = 0.01 * step * (space.agents[idx].position - crow.position) crow.clip_by_bound()
def _update(self, agents, function): """Method that wraps the update pipeline over all agents and variables. Args: agents (list): List of agents. function (Function): A function object. """ # Calculates a random index i = r.generate_integer_random_number(0, len(agents)) # Generates a new harmony agent = self._generate_new_harmony(agents[i]) # Checking agent limits agent.clip_limits() # Calculates the new harmony fitness agent.fit = function(agent.position) # Sorting agents agents.sort(key=lambda x: x.fit) # If newly generated agent fitness is better if agent.fit < agents[-1].fit: # Updates the corresponding agent's position agents[-1].position = copy.deepcopy(agent.position) # And its fitness as well agents[-1].fit = copy.deepcopy(agent.fit)
def _parasitism(self, agent_i, agent_j, function): """Performs the parasitism operation. Args: agent_i (Agent): Selected `i` agent. agent_j (Agent): Selected `j` agent. function (Function): A Function object that will be used as the objective function. """ # Creates a temporary parasite agent p = copy.deepcopy(agent_i) # Generates a integer random number r1 = r.generate_integer_random_number(0, agent_i.n_variables) # Updates its position on selected variable with a uniform random number p.position[r1] = r.generate_uniform_random_number(p.lb[r1], p.ub[r1]) # Checks its limits p.clip_limits() # Evaluates its position p.fit = function(p.position) # If the new potision is better than agent's `j` position if p.fit < agent_j.fit: # Replaces the agent's `j` position agent_j.position = copy.deepcopy(p.position) # Also replaces its fitness agent_j.fit = copy.deepcopy(p.fit)
def _crossover(self, agents, idx): """Performs the crossover between selected agent and a randomly agent (eq. 21). Args: agents (list): List of agents. idx (int): Selected agent. Returns: An agent after suffering a crossover operator. """ # Makes a deepcopy of an agent a = copy.deepcopy(agents[idx]) # Samples a random integer m = r.generate_integer_random_number(0, len(agents), exclude_value=idx) # Calculates the current crossover probability Cr = self.Cr * ((agents[idx].fit - agents[0].fit) / (agents[-1].fit - agents[0].fit + c.EPSILON)) # Iterates through all variables for j in range(a.n_variables): # Generating a uniform random number r1 = r.generate_uniform_random_number() # If sampled uniform number if smaller than crossover probability if r1 < Cr: # Gathers the position from the selected agent a.position[j] = copy.deepcopy(agents[m].position[j]) return a
def update(self, space, function, iteration, n_iterations): """Wraps Equilibrium Optimizer over all agents and variables. Args: space (Space): Space containing agents and update-related information. function (Function): A Function object that will be used as the objective function. iteration (int): Current iteration. n_iterations (int): Maximum number of iterations. """ # Calculates the equilibrium and average concentrations self._calculate_equilibrium(space.agents) C_avg = self._average_concentration(function) # Makes a pool of both concentrations and their average (eq. 7) C_pool = self.C + [C_avg] # Calculates the time (eq. 9) t = (1 - iteration / n_iterations)**(self.a2 * iteration / n_iterations) # Iterates through all agents for agent in space.agents: # Generates a integer between [0, 5) to select the concentration i = rnd.generate_integer_random_number(0, 5) # Generates two uniform random vectors (eq. 11) r = rnd.generate_uniform_random_number(size=(agent.n_variables, agent.n_dimensions)) lambd = rnd.generate_uniform_random_number( size=(agent.n_variables, agent.n_dimensions)) # Calculates the exponential term (eq. 11) F = self.a1 * np.sign(r - 0.5) * (np.exp(-lambd * t) - 1) # Generates two uniform random numbers r1 = rnd.generate_uniform_random_number() r2 = rnd.generate_uniform_random_number() # If `r2` is bigger than generation probability (eq. 15) if r2 >= self.GP: # Defines generation control parameter as 0.5 * r1 GCP = 0.5 * r1 # If `r2` is smaller than generation probability else: # Defines generation control parameter as zero GCP = 0 # Calculates the initial generation value (eq. 14) G_0 = GCP * (C_pool[i].position - lambd * agent.position) # Calculates the generation value (eq. 13) G = G_0 * F # Updates agent's position (eq. 16) agent.position = C_pool[i].position + ( agent.position - C_pool[i].position) * F + (G / (lambd * self.V)) * (1 - F)
def _update(self, agents, best_agent, function, height, length): """Method that wraps Water Wave Optimization over all agents and variables. Args: agents (list): List of agents. best_agent (Agent): Global best agent. function (Function): A function object. height (np.array): Array of wave heights. length (np.array): Array of wave lengths. """ # Iterates through all agents for i, agent in enumerate(agents): # Propagates a wave into a new temporary one (eq. 6) wave = self._propagate_wave(agent, function, length[i]) # Checks if propagated wave is better than current one if wave.fit < agent.fit: # Also checks if propagated wave is better than global one if wave.fit < best_agent.fit: # Replaces the best agent with propagated wave best_agent.position = copy.deepcopy(wave.position) best_agent.fit = copy.deepcopy(wave.fit) # Generates a `k` number of breaks k = r.generate_integer_random_number(1, self.k_max + 1) # Iterates through every possible break for j in range(k): # Breaks the propagated wave (eq. 10) broken_wave = self._break_wave(wave, function, j) # Checks if broken wave is better than global one if broken_wave.fit < best_agent.fit: # Replaces the best agent with broken wave best_agent.position = copy.deepcopy( broken_wave.position) best_agent.fit = copy.deepcopy(broken_wave.fit) # Replaces current agent's with propagated wave agent.position = copy.deepcopy(wave.position) agent.fit = copy.deepcopy(wave.fit) # Sets its height to maximum height height[i] = self.h_max # If propagated wave is not better than current agent else: # Decreases its height by one height[i] -= 1 # If its height reaches zero if height[i] == 0: # Refracts the wave and generates a new height and wave length (eq. 8-9) height[i], length[i] = self._refract_wave( agent, best_agent, function, length[i]) # Updates the wave length for all agents (eq. 7) self._update_wave_length(agents, length)
def _mutate_agent(self, agent, alpha, beta, gamma): """Mutates a new agent based on pre-picked distinct agents (eq. 4). Args: agent (Agent): Current agent. alpha (Agent): 1st picked agent. beta (Agent): 2nd picked agent. gamma (Agent): 3rd picked agent. Returns: A mutated agent. """ # Makes a deep copy of agent a = copy.deepcopy(agent) # Generates a random index for further comparison R = r.generate_integer_random_number(0, agent.n_variables) # For every decision variable for j in range(a.n_variables): # Generates a uniform random number r1 = r.generate_uniform_random_number() # If random number is smaller than crossover or `j` equals to the sampled index if r1 < self.CR or j == R: # Updates the mutated agent position a.position[j] = alpha.position[j] + self.F * (beta.position[j] - gamma.position[j]) return a
def _update(self, agents, best_agent, function, velocity): """Method that wraps velocity and position updates over all agents and variables. Args: agents (list): List of agents. best_agent (Agent): Global best agent. function (Function): A function object. velocity (np.array): Array of current velocities. """ # Iterate through all agents for i, agent in enumerate(agents): # Generates a random index based on the number of agents index = r.generate_integer_random_number(0, len(agents)) # Updating velocity velocity[i] = self._update_velocity(agent.position, best_agent.position, velocity[i], velocity[index], i + 1) # Clips the velocity values between (-v_max, v_max) velocity = np.clip(velocity, -self.v_max, self.v_max) # Updating agent's position agent.position = self._update_position(agent.position, velocity[i]) # Checks agent limits agent.clip_limits() # Evaluates agent agent.fit = function(agent.position)
def update(self, space: Space) -> None: """Wraps Crow Search Algorithm over all agents and variables. Args: space: Space containing agents and update-related information. """ # Iterates through every agent for agent in space.agents: # Generates uniform random numbers r1 = r.generate_uniform_random_number() r2 = r.generate_uniform_random_number() # Generates a random integer (e.g. selects the crow) j = r.generate_integer_random_number(high=len(space.agents)) # Checks if first random number is greater than awareness probability if r1 >= self.AP: # Updates agent's position (eq. 2) agent.position += r2 * self.fl * (self.memory[j] - agent.position) # If random number is smaller than probability else: # Fills agent with new random positions agent.fill_with_uniform()
def update(self, space: Space, function: Function) -> None: """Wraps EElectro-Search Algorithm over all agents and variables. Args: space: Space containing agents and update-related information. function: A Function object that will be used as the objective function. """ # Iterates through all agents for i, agent in enumerate(space.agents): # Makes a deep copy of current agent a = copy.deepcopy(agent) # Creates a list of electrons electrons = [copy.deepcopy(agent) for _ in range(self.n_electrons)] # Iterates through all electrons for electron in electrons: # Generates a random number and the energy level r1 = r.generate_uniform_random_number() n = r.generate_integer_random_number(2, 6) # Updates the electron's position (eq. 3) electron.position += (2 * r1 - 1) * (1 - 1 / n**2) / self.D[i] # Clips its bounds electron.clip_by_bound() # Re-evaluates the new position electron.fit = function(electron.position) # Sorts the electrons electrons.sort(key=lambda x: x.fit) # Generates both Rydberg constant and acceleration coefficient # Original implementation is missing up an informative description Re = r.generate_uniform_random_number() Ac = r.generate_uniform_random_number() # Updates the Orbital radius (eq. 4) self.D[i] = ( electrons[0].position - space.best_agent.position ) + Re * (1 / space.best_agent.position**2 - 1 / a.position**2) # Updates the temporary agent's position (eq. 5) a.position += Ac * self.D[i] # Checks agent's limits a.clip_by_bound() # Calculates the fitness for the temporary position a.fit = function(a.position) # If new fitness is better than agent's fitness if a.fit < agent.fit: # Copies its position and fitness to the agent agent.position = copy.deepcopy(a.position) agent.fit = copy.deepcopy(a.fit)
def _generate_new_harmony(self, agents: List[Agent]) -> Agent: """It generates a new harmony. Args: agents: List of agents. Returns: (Agent): A new agent (harmony) based on music generation process. """ # Mimics an agent position a = copy.deepcopy(agents[0]) # For every decision variable for j, (lb, ub) in enumerate(zip(a.lb, a.ub)): # Generates an uniform random number r1 = r.generate_uniform_random_number() # Using the harmony memory if r1 <= self.HMCR: # Generates a random index k = r.generate_integer_random_number(0, len(agents)) # Replaces the position with agent `k` a.position[j] = agents[k].position[j] # Generates a new uniform random number r2 = r.generate_uniform_random_number() # Checks if it needs a pitch adjusting if r2 <= self.PAR: # Generates a random index z = r.generate_integer_random_number(0, a.n_variables) # Updates harmony position a.position[j] = agents[0].position[z] # If harmony memory is not used else: # Generate a uniform random number a.position[j] = r.generate_uniform_random_number( lb, ub, size=a.n_dimensions ) return a
def update(self, space: Space, function: Function) -> None: """Wraps Water Wave Optimization over all agents and variables. Args: space: Space containing agents and update-related information. function: A function object. """ # Iterates through all agents for i, agent in enumerate(space.agents): # Propagates a wave into a new temporary one (eq. 6) wave = self._propagate_wave(agent, function, i) # Checks if propagated wave is better than current one if wave.fit < agent.fit: # Also checks if propagated wave is better than global one if wave.fit < space.best_agent.fit: # Replaces the best agent with propagated wave space.best_agent.position = copy.deepcopy(wave.position) space.best_agent.fit = copy.deepcopy(wave.fit) # Generates a `k` number of breaks k = r.generate_integer_random_number(1, self.k_max + 1) # Iterates through every possible break for j in range(k): # Breaks the propagated wave (eq. 10) broken_wave = self._break_wave(wave, function, j) # Checks if broken wave is better than global one if broken_wave.fit < space.best_agent.fit: # Replaces the best agent with broken wave space.best_agent.position = copy.deepcopy( broken_wave.position) space.best_agent.fit = copy.deepcopy( broken_wave.fit) # Replaces current agent's with propagated wave agent.position = copy.deepcopy(wave.position) agent.fit = copy.deepcopy(wave.fit) # Sets its height to maximum height self.height[i] = self.h_max # If propagated wave is not better than current agent else: # Decreases its height by one self.height[i] -= 1 # If its height reaches zero if self.height[i] == 0: # Refracts the wave and generates a new height and wave length (eq. 8-9) self.height[i], self.length[i] = self._refract_wave( agent, space.best_agent, function, i) # Updates the wave length for all agents (eq. 7) self._update_wave_length(space.agents)
def update(self, space: Space, function: Function) -> None: """Wraps Evolutionary Programming over all agents and variables. Args: space: Space containing agents and update-related information. function: A Function object that will be used as the objective function. """ # Calculates the number of agents n_agents = len(space.agents) # Creates a list for the produced children children = [] # Iterates through all agents for i, agent in enumerate(space.agents): # Mutates a parent and generates a new child a = self._mutate_parent(agent, i, function) # Updates the strategy self._update_strategy(i, agent.lb, agent.ub) # Appends the mutated agent to the children children.append(a) # Joins both populations space.agents += children # Number of individuals to be selected n_individuals = int(n_agents * self.bout_size) # Creates an empty array of wins wins = np.zeros(len(space.agents)) # Iterates through all agents in the new population for i, agent in enumerate(space.agents): # Iterate through all tournament individuals for _ in range(n_individuals): # Gathers a random index index = r.generate_integer_random_number(0, len(space.agents)) # If current agent's fitness is smaller than selected one if agent.fit < space.agents[index].fit: # Increases its winning by one wins[i] += 1 # Sorts agents list based on its winnings space.agents = [ agents for _, agents in sorted( zip(wins, space.agents), key=lambda pair: pair[0], reverse=True ) ] # Gathers the best `n_agents` space.agents = space.agents[:n_agents]
def kmeans( x: np.ndarray, n_clusters: Optional[int] = 1, max_iterations: Optional[int] = 100, tol: Optional[float] = 1e-4, ) -> np.ndarray: """Performs the K-Means clustering over the input data. Args: x: Input array with a shape equal to (n_samples, n_variables, n_dimensions). n_clusters: Number of clusters. max_iterations: Maximum number of clustering iterations. tol: Tolerance value to stop the clustering. Returns: (np.ndarray): An array holding the assigned cluster per input sample. """ # Gathers the corresponding dimensions n_samples, n_variables, n_dimensions = x.shape[0], x.shape[1], x.shape[2] # Creates an array of centroids and labels centroids = np.zeros((n_clusters, n_variables, n_dimensions)) labels = np.zeros(n_samples) for i in range(n_clusters): # Chooses a random sample to compose the centroid idx = r.generate_integer_random_number(0, n_samples) centroids[i] = x[idx] for _ in range(max_iterations): # Calculates the euclidean distance between samples and each centroid dists = np.squeeze(np.array([np.linalg.norm(x - c, axis=1) for c in centroids])) # Gathers the minimum distance as the cluster that conquers the sample updated_labels = np.squeeze(np.array(np.argmin(dists, axis=0))) # Calculates the difference ratio between old and new labels ratio = np.sum(labels != updated_labels) / n_samples if ratio <= tol: break # Updates the old labels with the new ones labels = updated_labels for i in range(n_clusters): # Gathers the samples that belongs to current centroid centroid_samples = x[labels == i] # If there are samples that belongs to the centroid if centroid_samples.shape[0] > 0: # Updates the centroid position centroids[i] = np.mean(centroid_samples, axis=0) return labels
def _update(self, agents, n_agents, function, strategy): """Method that wraps evolution over all agents and variables. Args: agents (list): List of agents. n_agents (int): Number of possible agents in the space. function (Function): A Function object that will be used as the objective function. strategy (np.array): An array of strategies. Returns: A new population with more fitted individuals. """ # Creating a list for the produced children children = [] # Iterate through all agents for i, agent in enumerate(agents): # Mutates a parent and generates a new child a = self._mutate_parent(agent, function, strategy[i]) # Updates the strategy strategy[i] = self._update_strategy(strategy[i], agent.lb, agent.ub) # Appends the mutated agent to the children children.append(a) # Joins both populations agents += children # Number of individuals to be selected n_individuals = int(n_agents * self.bout_size) # Creates an empty array of wins wins = np.zeros(len(agents)) # Iterate through all agents in the new population for i, agent in enumerate(agents): # Iterate through all tournament individuals for _ in range(n_individuals): # Gathers a random index index = r.generate_integer_random_number(0, len(agents)) # If current agent's fitness is smaller than selected one if agent.fit < agents[index].fit: # Increases its winning by one wins[i] += 1 # Sorts the agents list based on its winnings agents = [ agents for _, agents in sorted( zip(wins, agents), key=lambda pair: pair[0], reverse=True) ] return agents[:n_agents]
def _update(self, agents, best_agent, fragrance): """Method that wraps global and local pollination updates over all agents and variables. Args: agents (list): List of agents. best_agent (Agent): Global best agent. fragrance (np.array): Array of fragrances. """ # Iterates through all agents for i, agent in enumerate(agents): # Calculates fragrance for current agent (eq. 1) fragrance[i] = self.c * agent.fit**self.a # Iterates through all agents for i, agent in enumerate(agents): # Generates a uniform random number r1 = r.generate_uniform_random_number() # If random number is smaller than switch probability if r1 < self.p: # Moves current agent towards the best one (eq. 2) agent.position = self._best_movement(agent.position, best_agent.position, fragrance[i], r1) # If random number is bigger than switch probability else: # Generates a `j` index j = r.generate_integer_random_number(0, len(agents)) # Generates a `k` index k = r.generate_integer_random_number(0, len(agents), exclude_value=j) # Moves current agent using a local movement (eq. 3) agent.position = self._local_movement(agent.position, agents[j].position, agents[k].position, fragrance[i], r1)