def _update_particles(self): """ Update the velocities and positions for all particles. This does not update the fitness for each particle. """ # Random values between zero and one. One random value per particle. rand_g = tools.rand_uniform(size=self.num_particles) # Update velocity for all particles using numpy operations. # For an explanation of this formula, see the research papers referenced above. # Note that self.best is the swarm's best-known position aka. global-best. self.velocity = (self.omega * self.velocity.T \ + self.phi_g * rand_g * (self.best - self.particle).T).T # Fix de-normalized floating point values which can make the execution very slow. self.velocity = tools.denormalize_trunc(self.velocity) # Bound velocity. self.velocity = tools.bound(self.velocity, self.velocity_lower_bound, self.velocity_upper_bound) # Update particle positions in the search-space by adding the velocity. self.particle = self.particle + self.velocity # Bound particle position to search-space. self.particle = tools.bound(self.particle, self.problem.lower_bound, self.problem.upper_bound)
def _new_agents(self): """ Calculate a new population of agents using the DE method. The fitness is not calculated in this function. """ # Convenience variables. population = self.population # 2-d array with the population of agents. num_agents = self.num_agents # Number of agents in population. dim = self.problem.dim # Search-space dimensionality. differential_weight = self.differential_weight # Control parameter for DE. crossover_probability = self.crossover_probability # Control parameter for DE. # Create a new population of agents. for i in range(num_agents): # This loop only processes a single agent in each iteration. # It might be possible to make a faster implementation using Numpy # to process all agents simultaneously. However, this # implementation is simpler and easier to understand, and the # greatest runtime usage is typically in the fitness function. # Pick random and distinct indices for agents in the population. a, b, c, k = tools.rand_choice(num_agents, size=4, replace=False) # Indices a, b, c, k are all different from each other. # Now ensure that indices a, b, c are also different from i. # Simply check if an index equals i and then replace it with k, # which is different from i, a, b, c. if i == a: a = k elif i == b: b = k elif i == c: c = k assert i != a != b != c # Original position in the search-space for the agent to be updated. original = population[i, :] # Calculate crossover of randomly selected agents from the population. crossover = population[a, :] + differential_weight * (population[b, :] - population[c, :]) # Create a new agent (i.e. position) in the search-space from the crossover. # The crossover probability decides whether to use the crossover or # the agent's original position in the search-space. new_agent = np.where(tools.rand_uniform(dim) < crossover_probability, crossover, original) # Ensure at least one element of the agent's new position is from the crossover. rand_index = tools.rand_int(lower=0, upper=dim) new_agent[rand_index] = crossover[rand_index] # Bound the agent's new position to the search-space boundaries. new_agent = tools.bound(x=new_agent, lower=self.problem.lower_bound, upper=self.problem.upper_bound) # Assign the agent's new position to the temporary population so the # fitness can be calculated in another function. self.new_population[i, :] = new_agent