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 update(self, space: Space, function: Function) -> None: """Wraps Evolution Strategies 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 = [] # Iterate through all children for i in range(self.n_children): # Mutates a parent and generates a new child a = self._mutate_parent(space.agents[i], i, function) # Updates the strategy self._update_strategy(i) # Appends the mutated agent to the children children.append(a) # Joins both populations, sorts agents and gathers best `n_agents` space.agents += children space.agents.sort(key=lambda x: x.fit) space.agents = space.agents[:n_agents]
def update(self, space: Space, function: Function) -> None: """Wraps Forest 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. """ # Performs the local seeding self._local_seeding(space, function) # Limits the population candidate = self._population_limiting(space) # Performs the global seeding self._global_seeding(space, function, candidate) # Sorts agents and their corresponding ages space.agents, self.age = map( list, zip(*sorted(zip(space.agents, self.age), key=lambda x: x[0].fit))) # Sets the best tree's age to zero self.age[0] = 0
def update(self, space: Space, function: Function) -> None: """Wraps Artificial Flora 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. """ # Sorts the agents space.agents.sort(key=lambda x: x.fit) # Creates a list of new agents new_agents = [] # Iterates thorugh all agents for i, agent in enumerate(space.agents): # Iterates through amount of branches for _ in range(self.m): # Makes a copy of current agent a = copy.deepcopy(agent) # Generates random numbers r1 = r.generate_uniform_random_number() r2 = r.generate_uniform_random_number() r3 = r.generate_uniform_random_number() # Calculates the new distance (eq. 1) distance = (self.g_distance[i] * r1 * self.c1 + self.p_distance[i] * r2 * self.c2) # Generates a random gaussian number D = r.generate_gaussian_random_number( 0, distance, (space.n_variables, space.n_dimensions)) # Updates offspring's position (eq. 5) a.position += D # Clips its limits a.clip_by_bound() # Evaluates its fitness a.fit = function(a.position) # Calculates the probability of selection (eq. 6) p = np.fabs(np.sqrt(a.fit / space.agents[-1].fit)) * self.Q # If random number is smaller than probability of selection if r3 < p: # Appends the offsprings new_agents.append(a) # Updates both grandparent and parent distances (eq. 2 and 3) self.g_distance[i] = self.p_distance[i] self.p_distance[i] = np.std(agent.position - a.position) # Randomly selects the agents idx = d.generate_choice_distribution(len(new_agents), None, space.n_agents) space.agents = [new_agents[i] for i in idx]
def update(self, space: Space, iteration: int, n_iterations: int) -> None: """Wraps Thermal Exchange Optimization over all agents and variables. Args: space: Space containing agents and update-related information. iteration: Current iteration. n_iterations: Maximum number of iterations. """ # Sorts agents space.agents.sort(key=lambda x: x.fit) # Updates the thermal memory and cuts it to maximum allowed size self.TM.append(copy.deepcopy(space.agents[0])) self.TM = self.TM[-self.n_TM :] # Replaces the worst agents with the thermal memory and re-sorts the agents space.agents = space.agents[: -len(self.TM)] + self.TM space.agents.sort(key=lambda x: x.fit) # Calculates the time (eq. 9) time = iteration / n_iterations # Iterates through all environmental-based agents for env in self.environment: # Updates the environment's position (eq. 10) r1 = r.generate_uniform_random_number() env.position = 1 - (self.c1 + self.c2 * (1 - time)) * r1 * env.position # Iterates through both populations' agents for agent, env in zip(space.agents, self.environment): # Calculates the agent's beta value (eq. 8) beta = agent.fit / space.agents[-1].fit # Updates the agent's position (eq. 11) agent.position = env.position + (agent.position - env.position) * np.exp( -beta * time ) # Generates a random number r1 = r.generate_uniform_random_number() # If random number is smaller than `pro` if r1 < self.pro: # Selects a random dimension idx = r.generate_integer_random_number(high=agent.n_variables) # Resets its position (eq. 12) r2 = r.generate_uniform_random_number() agent.position[idx] = agent.lb[idx] + r2 * ( agent.ub[idx] - agent.lb[idx] )
def _population_limiting(self, space: Space) -> List[Agent]: """Limits the population by removing old trees. Args: space: A Space object containing meta-information. Returns: (List[Agent]): A list of candidate trees that were removed from the forest. """ # List of candidate trees candidate = [] # Iterates through all agents for i, _ in enumerate(space.agents): # Checks whether current agent has exceed its life time if self.age[i] > self.life_time: # Removes the tree and its corresponding age from forest agent = space.agents.pop(i) self.age.pop(i) # Adds the removed agent to the candidate list candidate.append(agent) # Sorts agents and their corresponding ages space.agents, self.age = map( list, zip(*sorted(zip(space.agents, self.age), key=lambda x: x[0].fit))) # If the population exceeds the forest limits if len(space.agents) > self.area_limit: # Adds extra trees to the candidate list candidate += space.agents[self.area_limit:] # Removes the extra trees and their corresponding ages from forest space.agents = space.agents[:self.area_limit] self.age = self.age[:self.area_limit] return candidate
def update(self, space: Space, function: Function, iteration: int, n_iterations: int) -> None: """Wraps Invasive Weed Optimization 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. iteration: Current iteration. n_iterations: Maximum number of iterations. """ # Calculates the current Spatial Dispersal self._spatial_dispersal(iteration, n_iterations) # Calculates the number of agents and creates list of offsprings n_agents = len(space.agents) offsprings = [] # Sorts agents space.agents.sort(key=lambda x: x.fit) # Iterates through all agents for agent in space.agents: # Calculates the seeding ratio based on its fitness ratio = (agent.fit - space.agents[-1].fit) / ( space.agents[0].fit - space.agents[-1].fit + c.EPSILON) # Calculates the number of produced seeds n_seeds = int(self.min_seeds + (self.max_seeds - self.min_seeds) * ratio) # For every seed for _ in range(n_seeds): # Reproduces and flowers the seed into a new agent a = self._produce_offspring(agent, function) # Appends the agent to the offsprings offsprings.append(a) # Joins both populations, sorts and gathers best `n_agents` space.agents += offsprings space.agents.sort(key=lambda x: x.fit) space.agents = space.agents[:n_agents]
def compile(self, space: Space) -> None: """Compiles additional information that is used by this optimizer. Args: space: A Space object containing meta-information. """ # Replaces the current agents with a derived Lion structure space.agents = [ Lion( agent.n_variables, agent.n_dimensions, agent.lb, agent.ub, agent.position, agent.fit, ) for agent in space.agents ] # Calculates the number of nomad lions and their genders n_nomad = int(self.N * space.n_agents) nomad_gender = d.generate_bernoulli_distribution(1 - self.S, n_nomad) # Iterates through all possible nomads for i, agent in enumerate(space.agents[:n_nomad]): # Toggles to `True` the nomad property agent.nomad = True # Defines the gender according to Bernoulli distribution agent.female = bool(nomad_gender[i]) # Calculates the gender of pride lions pride_gender = d.generate_bernoulli_distribution( self.S, space.n_agents - n_nomad) # Iterates through all possible prides for i, agent in enumerate(space.agents[n_nomad:]): # Defines the gender according to Bernoulli distribution agent.female = bool(pride_gender[i]) # Allocates to the corresponding pride agent.pride = i % self.P
def update(self, space: Space, function: Function) -> None: """Wraps Genetic 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. """ # Creates a list to hold the new population new_agents = [] # Retrieves the number of agents n_agents = len(space.agents) # Calculates a list of fitness from every agent fitness = [agent.fit + c.EPSILON for agent in space.agents] # Selects the parents selected = self._roulette_selection(n_agents, fitness) # For every pair of selected parents for s in g.n_wise(selected): # Performs the crossover and mutation alpha, beta = self._crossover(space.agents[s[0]], space.agents[s[1]]) alpha, beta = self._mutation(alpha, beta) # Checking `alpha` and `beta` limits alpha.clip_by_bound() beta.clip_by_bound() # Calculates new fitness for `alpha` and `beta` alpha.fit = function(alpha.position) beta.fit = function(beta.position) # Appends the mutated agents to the children new_agents.extend([alpha, beta]) # Joins both populations, sort agents and gathers best `n_agents` space.agents += new_agents space.agents.sort(key=lambda x: x.fit) space.agents = space.agents[:n_agents]
def update(self, space: Space, function: Function) -> None: """Wraps Black Widow Optimization 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. """ # Retrieves the number of agents n_agents = len(space.agents) n_variables = space.n_variables # Calculates the number agents that reproduces, are cannibals and mutates n_reproduct = int(n_agents * self.pp) n_cannibals = int(n_agents * self.cr) n_mutate = int(n_agents * self.pm) # Sorts agents space.agents.sort(key=lambda x: x.fit) # Selecting the best solutions and saving in auxiliary population agents1 = copy.deepcopy(space.agents[:n_reproduct]) # Creates an empty auxiliary population agents2 = [] # For every possible reproducting agent for _ in range(0, n_reproduct): # Sampling random uniform integers as indexes idx = r.generate_uniform_random_number(0, n_agents, size=2) # Making a deepcopy of father and mother father, mother = copy.deepcopy(space.agents[int( idx[0])]), copy.deepcopy(space.agents[int(idx[1])]) # Creates an empty list of auxiliary agents new_agents = [] # For every possible pair of variables for _ in range(0, int(n_variables / 2)): # Procreates parents into two new offsprings y1, y2 = self._procreating(father, mother) # Checks `y1` and `y2` limits y1.clip_by_bound() y2.clip_by_bound() # Calculates new fitness for `y1` and `y2` y1.fit = function(y1.position) y2.fit = function(y2.position) # Appends the mother and mutated agents to the new population new_agents.extend([mother, y1, y2]) # Sorts new population new_agents.sort(key=lambda x: x.fit) # Extending auxiliary population with the number of cannibals (s. 3.3) agents2.extend(new_agents[:n_cannibals]) # For every possible mutating agent for _ in range(0, n_mutate): # Sampling a random integer as index idx = int(r.generate_uniform_random_number(0, n_reproduct)) # Performs the mutation alpha = self._mutation(agents1[idx]) # Checks `alpha` limits alpha.clip_by_bound() # Calculates new fitness for `alpha` alpha.fit = function(alpha.position) # Appends the mutated agent to the auxiliary population agents2.extend([alpha]) # Joins both populations, sorts them and retrieves `n_agents` space.agents += agents2 space.agents.sort(key=lambda x: x.fit) space.agents = space.agents[:n_agents]