def _mutation(self, space): """Mutates a number of individuals pre-selected through a tournament procedure. Args: space (TreeSpace): A TreeSpace object. """ # Calculates a list of current trees' fitness fitness = [agent.fit for agent in space.agents] # Number of individuals to be mutated n_individuals = int(space.n_trees * self.p_mutation) # Gathers a list of selected individuals to be replaced selected = g.tournament_selection(fitness, n_individuals) # For every selected individual for s in selected: # Gathers individual number of nodes n_nodes = space.trees[s].n_nodes # Checks if the tree has more than one node if n_nodes > 1: # Prunes the amount of maximum nodes max_nodes = self._prune_nodes(n_nodes) # Mutatets the individual space.trees[s] = self._mutate(space, space.trees[s], max_nodes) # If there is only one node else: # Re-create it with a random tree space.trees[s] = space.grow(space.min_depth, space.max_depth)
def _reproduction(self, space): """Reproducts a number of individuals pre-selected through a tournament procedure. Args: space (TreeSpace): A TreeSpace object. """ # Calculates a list of current trees' fitness fitness = [agent.fit for agent in space.agents] # Number of individuals to be reproducted n_individuals = int(space.n_trees * self.p_reproduction) # Gathers a list of selected individuals to be replaced selected = g.tournament_selection(fitness, n_individuals) # For every selected individual for s in selected: # Gathers the worst individual index worst = np.argmax(fitness) # Replace the individual by performing a deep copy on selected tree space.trees[worst] = copy.deepcopy(space.trees[s]) # We also need to copy the agent space.agents[worst] = copy.deepcopy(space.agents[s]) # Replaces the worst individual fitness with a minimum value fitness[worst] = 0
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 _moving_safe_place(self, prides: List[Lion]) -> None: """Move prides to safe locations (s. 2.2.3). Args: prides: List of prides holding their corresponding lions. """ # Iterates through all prides for pride in prides: # Calculates the number of improved lions (eq. 7) n_improved = np.sum( [1 for agent in pride if agent.fit < agent.p_fit]) # Calculates the fitness of lions (eq. 8) fitnesses = [agent.fit for agent in pride] # Calculates the size of tournament (eq. 9) tournament_size = np.maximum(2, int(np.ceil(n_improved / 2))) # Iterates through all agents in pride for agent in pride: # If agent is female and belongs to group 0 if agent.group == 0 and agent.female: # Gathers the winning lion from tournament selection w = g.tournament_selection(fitnesses, 1, tournament_size)[0] # Calculates the distance between agent and winner distance = g.euclidean_distance(agent.position, pride[w].position) # Generates random numbers rand = r.generate_uniform_random_number() u = r.generate_uniform_random_number(-1, 1) theta = r.generate_uniform_random_number( -np.pi / 6, np.pi / 6) # Calculates both `R1` and `R2` vectors R1 = pride[w].position - agent.position R2 = np.random.randn(*R1.T.shape) R2 = R2.T - R2.dot(R1) * R1 / (np.linalg.norm(R1)**2 + c.EPSILON) # Updates agent's position (eq. 6) agent.position += (2 * distance * rand * R1 + u * np.tan(theta) * distance * R2)
def _crossover(self, space): """Crossover a number of individuals pre-selected through a tournament procedure. Args: space (TreeSpace): A TreeSpace object. agents (list): Current iteration agents. trees (list): Current iteration trees. """ # Calculates a list of current trees' fitness fitness = [agent.fit for agent in space.agents] # Number of individuals to be crossovered n_individuals = int(space.n_trees * self.p_crossover) # Checks if `n_individuals` is an odd number if n_individuals % 2 != 0: # If it is, increase it by one n_individuals += 1 # Gathers a list of selected individuals to be replaced selected = g.tournament_selection(fitness, n_individuals) # For every pair in selected individuals for s in g.pairwise(selected): # Calculates the amount of father nodes father_nodes = space.trees[s[0]].n_nodes # Calculate the amount of mother nodes mother_nodes = space.trees[s[1]].n_nodes # Checks if both trees have more than one node if (father_nodes > 1) and (mother_nodes > 1): # Prunning father nodes max_f_nodes = self._prune_nodes(father_nodes) # Prunning mother nodes max_m_nodes = self._prune_nodes(mother_nodes) # Apply the crossover operation space.trees[s[0]], space.trees[s[1]] = self._cross( space.trees[s[0]], space.trees[s[1]], max_f_nodes, max_m_nodes)
def test_tournament_selection(): fitness = [1, 2, 3, 4] selected = general.tournament_selection(fitness, 2) assert len(selected) == 2
import opytimizer.math.general as g # Creates a list for pairwising individuals = [1, 2, 3, 4] # Creates pairwise from list for pair in g.n_wise(individuals, 2): # Outputting pairs print(f"Pair: {pair}") # Performs a tournmanet selection over list selected = g.tournament_selection(individuals, 2) # Outputting selected individuals print(f"Selected: {selected}")