def _roulette_selection(self, n_agents, fitness): """Performs a roulette selection on the population. Args: n_agents (int): Number of agents allowed in the space. fitness (list): A fitness list of every agent. Returns: The selected indexes of the population """ # Calculates the number of selected individuals n_individuals = int(n_agents * self.p_selection) # Checks if `n_individuals` is an odd number if n_individuals % 2 != 0: # If it is, increase it by one n_individuals += 1 # Calculates the total fitness total_fitness = np.sum(fitness) # Calculates the probability of each fitness probs = [fit / total_fitness for fit in fitness] # Performs the selection process selected = d.generate_choice_distribution(n_agents, probs, n_individuals) return selected
def update(self, space: Space, function: Function) -> None: """Wraps Differential Evolution over all agents and variables (eq. 1-4). 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): # Randomly picks three distinct other agents, not including current one C = d.generate_choice_distribution(np.setdiff1d( range(0, len(space.agents)), i), size=3) # Mutates the current agent a = self._mutate_agent(agent, space.agents[C[0]], space.agents[C[1]], space.agents[C[2]]) # 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 _update(self, agents, function): """Method that wraps selection and mutation updates over all agents and variables (eq. 1-4). Args: agents (list): List of agents. function (Function): A Function object that will be used as the objective function. """ # Iterate through all agents for i, agent in enumerate(agents): # Randomly picks three distinct other agents, not including current one C = d.generate_choice_distribution(np.setdiff1d(range(0, len(agents)), i), size=3) # Mutates the current agent a = self._mutate_agent(agent, agents[C[0]], agents[C[1]], agents[C[2]]) # 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 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 _roulette_selection(self, fitness, a=0.1): """Performs a roulette selection on the population (eq. 8). Args: fitness (list): A fitness list of every agent. a (float): Selection regularizer. Returns: The selected index of the population. """ # Defines the minimum fitness of current generation min_fitness = np.min(fitness) # Re-arrange the list of fitness by inverting it (eq. 7) inv_fitness = [1 / (a + fit - min_fitness) for fit in fitness] # Calculates the total inverted fitness total_fitness = np.sum(inv_fitness) # Calculates the probability of each inverted fitness (eq. 8) probs = [fit / total_fitness for fit in inv_fitness] # Performs the selection process selected = d.generate_choice_distribution(len(probs), probs, 1) return selected[0]
def _update(self, agents, best_agent, function, sigma): """Method that wraps 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. sigma (list): Width between lower and upper bounds. """ # Calculates a list of fitness per agent fitness = [ 1 / (1 + agent.fit) if agent.fit >= 0 else 1 + np.abs(agent.fit) for agent in agents ] # Calculates the total fitness total_fitness = np.sum(fitness) # Calculates the probability of each agent's fitness probs = [fit / total_fitness for fit in fitness] # Iterate through all agents for agent in agents: # For every decision variable for j in range(agent.n_variables): # Selects a random individual based on its probability s = d.generate_choice_distribution(len(agents), probs, 1)[0] # Calculates the lambda factor lambda_k = self.alpha / (1 + probs[s]) # Updates the decision variable position agent.position[j] += lambda_k * ( (agents[s].position[j] + best_agent.position[j]) / 2 - agent.position[j]) # Generates an uniform random number r1 = r.generate_uniform_random_number() # If random number is smaller than probability of mutation if r1 < self.p_mutation: # Mutates the decision variable position agent.position[ j] += sigma[j] * r.generate_gaussian_random_number() # Check agent limits agent.clip_limits() # Calculates its fitness agent.fit = function(agent.position)
def update(self, space: Space, function: Function) -> None: """Wraps Satin Bowerbird Optimizer over all agents and variables (eq. 1-7). Args: space: Space containing agents and update-related information. function: A Function object that will be used as the objective function. """ # Calculates a list of fitness per agent fitness = [ 1 / (1 + agent.fit) if agent.fit >= 0 else 1 + np.abs(agent.fit) for agent in space.agents ] # Calculates the total fitness total_fitness = np.sum(fitness) # Calculates the probability of each agent's fitness probs = [fit / total_fitness for fit in fitness] # Iterates through all agents for agent in space.agents: # For every decision variable for j in range(agent.n_variables): # Selects a random individual based on its probability s = d.generate_choice_distribution(len(space.agents), probs, 1)[0] # Calculates the lambda factor lambda_k = self.alpha / (1 + probs[s]) # Updates the decision variable position agent.position[j] += lambda_k * ( (space.agents[s].position[j] + space.best_agent.position[j]) / 2 - agent.position[j] ) # Generates an uniform random number r1 = r.generate_uniform_random_number() # If random number is smaller than probability of mutation if r1 < self.p_mutation: # Mutates the decision variable position agent.position[j] += ( self.sigma[j] * r.generate_gaussian_random_number() ) # Checks agent's limits agent.clip_by_bound() # Calculates its fitness agent.fit = function(agent.position)
def _dark_zone(self, agents, best_agent, function, life, counter): """Performs the dark-zone update process. 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. life (np.array): An array holding each cell's current life. counter (np.array): An array holding each cell's copy counter. """ # Iterate through all agents for i, agent in enumerate(agents): # Generates the first random number, between 0 and 100 r1 = r.generate_uniform_random_number(0, 100) # If random number is smaller than cell's life if r1 < life[i]: # Increases it counter by one counter[i] += 1 # If it is not smaller else: # Resets the counter to one counter[i] = 1 # Generates the counting distribution and pick three cells C = d.generate_choice_distribution(len(agents), counter / np.sum(counter), size=3) # Mutates a new cell based on current and pre-picked cells a = self._mutate_cell(agent, agents[C[0]], agents[C[1]], agents[C[2]]) # 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) # Increases the life of cell by ten life[i] += 10
def _dark_zone(self, agents: List[Agent], function: Function) -> None: """Performs the dark-zone update process (alg. 1). Args: agents: List of agents. function: A Function object that will be used as the objective function. """ # Iterates through all agents for i, agent in enumerate(agents): # Generates the first random number, between 0 and 100 r1 = r.generate_uniform_random_number(0, 100) # If random number is smaller than cell's life if r1 < self.life[i]: # Increases it counter by one self.counter[i] += 1 # If it is not smaller else: # Resets the counter to one self.counter[i] = 1 # Generates the counting distribution and pick three cells C = d.generate_choice_distribution(len(agents), self.counter / np.sum(self.counter), size=3) # Mutates a new cell based on current and pre-picked cells a = self._mutate_cell(agent, agents[C[0]], agents[C[1]], agents[C[2]]) # 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) # Increases the life of cell by ten self.life[i] += 10
def _roulette_selection(self, n_agents: int, fitness: List[float]) -> List[int]: """Performs a roulette selection on the population (p. 8). Args: n_agents: Number of agents allowed in the space. fitness: A fitness list of every agent. Returns: (List[int]): The selected indexes of the population. """ # Calculates the number of selected individuals n_individuals = int(n_agents * self.p_selection) # Checks if `n_individuals` is an odd number if n_individuals % 2 != 0: # If it is, increase it by one n_individuals += 1 # Defines the maximum fitness of current generation max_fitness = np.max(fitness) # Re-arrange the list of fitness by inverting it # Note that we apply a trick due to it being designed for minimization # f'(x) = f_max - f(x) inv_fitness = [max_fitness - fit + c.EPSILON for fit in fitness] # Calculates the total inverted fitness total_fitness = np.sum(inv_fitness) # Calculates the probability of each inverted fitness probs = [fit / total_fitness for fit in inv_fitness] # Performs the selection process selected = d.generate_choice_distribution(n_agents, probs, n_individuals) return selected
import opytimizer.math.distribution as d # Generates a Bernoulli distribution b = d.generate_bernoulli_distribution(prob=0.5, size=10) print(b) # Generates a choice distribution c = d.generate_choice_distribution(n=10, probs=None, size=10) print(c) # Generates a Lévy distribution l = d.generate_levy_distribution(beta=0.5, size=10) print(l)
def test_generate_choice_distribution(): choice_array = distribution.generate_choice_distribution(n=10, probs=None, size=10) assert choice_array.shape == (10,)