def compute_position(self, swarm, bounds=None, bh=BoundaryHandler(strategy="random")): """Update the position matrix This method updates the position matrix given the current position and the velocity. If bounded, it waives updating the position. Parameters ---------- swarm : pyswarms.backend.swarms.Swarm a Swarm instance bounds : tuple of :code:`np.ndarray` or list (default is :code:`None`) a tuple of size 2 where the first entry is the minimum bound while the second entry is the maximum bound. Each array must be of shape :code:`(dimensions,)`. bh : pyswarms.backend.handlers.BoundaryHandler a BoundaryHandler instance Returns ------- numpy.ndarray New position-matrix """ temp_position = swarm.position.copy() temp_position += swarm.velocity if bounds is not None: temp_position = bh(temp_position, bounds) temp_position[:, swarm.discrete_index:] = np.rint( temp_position[:, swarm.discrete_index:]) position = temp_position return position
def test_return_values(self, swarm, bounds, bh_strat): """Test if method gives the expected shape and range""" bh = BoundaryHandler(strategy=bh_strat) p = P.compute_position(swarm, bounds, bh) assert p.shape == swarm.velocity.shape if bounds is not None: assert (bounds[0] <= p).all() and (bounds[1] >= p).all()
def test_bound_handling(bounds, positions_inbound, positions_out_of_bound, strategy): bh = BoundaryHandler(strategy=strategy) # Test if it doesn't handle inbound positions inbound_handled = bh(positions_inbound, bounds) assert inbound_handled.all() == positions_inbound.all() # Test if all particles are handled to a position inside the boundaries outbound_handled = bh(positions_out_of_bound, bounds) lower_than_bound = outbound_handled >= bounds[0] greater_than_bound = outbound_handled <= bounds[1] assert lower_than_bound.all() assert greater_than_bound.all()
def differential_evolution(n_dims, evolutions, f, args, bounds, original_time): population = 20 pbar = tqdm(range(evolutions), position=1) discrete_index = 1 #initialization positions = generate_position(population, n_dims, bounds, discrete_index) # original point positions[0][1] = 0 positions[0][0] = original_time position_history = [] position_history.append(positions[:, 1:]) bh = BoundaryHandler(strategy="nearest") costs, aux = f(positions, **args) # Compute current cost mutation_candidates = [[idx for idx in range(population) if idx != i] for i in range(population)] mutation_candidates = np.array(mutation_candidates) for e in range(evolutions): # evaluation trial_pop = [] #mutation for i in range(population): mutation_candidate = np.random.choice(mutation_candidates[i], 3, replace=False) a, b, c = positions[mutation_candidate] mutation_factor = 0.8 mutant = a + mutation_factor * (b - c) #recombination crossp = 0.7 cross_points = np.random.rand(n_dims) < crossp trial = np.where(cross_points, mutant, positions[i]) trial_pop.append(trial) trial_pop = np.array(trial_pop) # round and bound population trial_pop[:, discrete_index:] = np.rint(trial_pop[:, discrete_index:]) trial_pop = bh(trial_pop, bounds) #evaluation trial_costs, trial_aux = f(trial_pop, **args) mask_cost = trial_costs < costs mask_pos = np.expand_dims(mask_cost, axis=1) # update new positons Apply masks positions = np.where(~mask_pos, positions, trial_pop) costs = np.where(~mask_cost, costs, trial_costs) aux = np.where(~mask_pos, aux, trial_aux) position_history.append(positions[:, 1:]) post_fix = "c: {:.4f}".format(np.min(costs)) pbar.set_postfix_str(post_fix) pbar.update(1) #find best index when there may be multiple best costs best_indices = np.where(costs == costs.min()) if len(best_indices) == 1: best_index = best_indices[0] else: tmp_pos = positions[best_indices] min_ind = np.argmin(tmp_pos[:, 1]) best_index = best_indices[min_ind] best_index = np.argmin(costs) best_cost = costs[best_index] best_position = positions[best_index] best_aux = aux[best_index] std = np.std(positions, axis=0) return best_cost, best_position, best_aux, std, position_history
def optimize(options, n_dims, iterations, f, args, bounds, original_time, clamp=None, mutate_prob=-1): topology = Traffic() pos_history = [] n_particles = 20 # de params mutation_factor = 0.8 crossp = 0.7 mutation_candidates = [[idx for idx in range(n_particles) if idx != i] for i in range(n_particles)] mutation_candidates = np.array(mutation_candidates) swarm = create_swarm(n_particles=n_particles, dimensions=n_dims, options=options, bounds=bounds, discrete_index=1) # set first particle to have original time and no craft packet swarm.position[0][1] = 0 swarm.position[0][0] = original_time # swarm.position[1]=[1502269093.015671,100.000000,211.000000] # swarm.position[1]=np.array([1502269073.367330,18.000000,192.000000]) # swarm.best_pos=np.array([0,0,0]) pbar = tqdm(range(iterations), position=1) # file=open("tmp_pso.txt","a") for i in pbar: # pos_history.append(np.vstack((swarm.position[:,1:],np.expand_dims(swarm.best_pos[1:], axis=0)))) # Part 1: Update personal best swarm.current_cost, swarm.current_aux = f( swarm.position, **args, verbose=False) # Compute current cost # file.write("{}".format(i)+"\n") # file.write(pprint.pformat(swarm.current_cost)+"\n") # file.write(pprint.pformat(swarm.position)+"\n") if i == 0: swarm.pbest_cost, swarm.pbest_aux = swarm.current_cost, swarm.current_aux swarm.best_cost, swarm.best_aux = swarm.current_cost, swarm.current_aux swarm.best_pos = swarm.position swarm.pbest_iter = np.zeros((n_particles, )) # swarm.pbest_cost, swarm.pbest_aux= f(swarm.pbest_pos, **args) # Compute personal best pos # print(swarm.pbest_cost) # binomially mutate if np.random.rand() < mutate_prob: tmp_pos = swarm.position swarm.trial_pos = topology.mutate_swarm(swarm, mutation_factor, crossp, mutation_candidates, bounds) swarm.trial_cost, swarm.trial_aux = f(swarm.trial_pos, **args) # print("tc",swarm.trial_cost) # print("ta",swarm.trial_aux) # print("tp",swarm.trial_pos) swarm.position, swarm.current_cost, swarm.current_aux = topology.compute_mbest( swarm) # print("-"*50) swarm.pbest_pos, swarm.pbest_cost, swarm.pbest_aux, swarm.pbest_iter = topology.compute_pbest( swarm, i) # Update and store # Part 2: Update global best # Note that gbest computation is dependent on your topology # if np.min(swarm.pbest_cost) < swarm.best_cost: # best index is global minimum, others are best in the neighbourhood swarm.best_pos, swarm.best_cost, swarm.best_aux, swarm.best_index = topology.compute_gbest_local( swarm, 2, 4) # best_iter=i # file.write(pprint.pformat(swarm.best_pos)+"\n") # Part 3: Update position and velocity matrices # Note that position and velocity updates are dependent on your topology swarm.velocity = topology.compute_velocity(swarm, bounds=bounds, clamp=clamp, iter=i) if np.random.rand() < 0.5: strat = "random" else: strat = "nearest" swarm.position = topology.compute_position( swarm, bounds=bounds, bh=BoundaryHandler(strategy=strat)) # print(swarm.position) # file.write(pprint.pformat(swarm.velocity)+"\n") # # file.write("-"*100+"\n") # post_fix="c: {:.4f}, n: {:.0f}".format(swarm.best_cost, np.trunc(swarm.best_pos[1])) # if n_dims==3: # post_fix+=", p: {:.0f}".format(swarm.best_pos[2]) post_fix = "c: {:.4f}".format(swarm.best_cost[swarm.best_index]) pbar.set_postfix_str(post_fix) norm_pos = np.copy(swarm.position) norm_pos[:, 0] = norm_pos[:, 0] - bounds[0][0] norm_best = np.copy(swarm.best_pos) norm_best[:, 0] = norm_best[:, 0] - bounds[0][0] pos_history.append(np.vstack((norm_pos, norm_best))) # if i-best_iter>10: # print("early stopping") # break # print("best config found in {} iterations".format(best_iter)) std = np.std(swarm.position, axis=0) # print("best conf", swarm.best_cost[swarm.best_index], swarm.best_pos[swarm.best_index], swarm.best_aux[swarm.best_index]) # print(swarm.best_cost) # # bc=np.argmin(swarm.best_cost) # swarm.best_pos=swarm.best_pos[bc] # swarm.best_aux=swarm.best_aux[bc] # print(swarm.position) return swarm.best_cost[swarm.best_index], swarm.best_pos[ swarm.best_index], swarm.best_aux[swarm.best_index], std, pos_history
def test_intermediate_strategy( bounds, positions_inbound, positions_out_of_bound ): bh = BoundaryHandler(strategy="intermediate")
def test_random_strategy(bounds, positions_inbound, positions_out_of_bound): bh = BoundaryHandler(strategy="random")
def test_shrink_strategy(bounds, positions_inbound, positions_out_of_bound): bh = BoundaryHandler(strategy="shrink")
def test_reflective_strategy( bounds, positions_inbound, positions_out_of_bound ): bh = BoundaryHandler(strategy="reflective") pass
def test_nearest_strategy(bounds, positions_inbound, positions_out_of_bound): bh = BoundaryHandler(strategy="nearest")
def test_periodic_strategy(bounds, positions_inbound, positions_out_of_bound): bh = BoundaryHandler(strategy="periodic")
def __init__( self, n_particles, dimensions, options, bounds=None, bh_strategy="periodic", velocity_clamp=None, vh_strategy="unmodified", center=1.00, ftol=-np.inf, init_pos=None, ): """ A custom optimizer modified from pyswarms.single.global_best https://github.com/ljvmiranda921/pyswarms/blob/master/pyswarms/single/global_best.py Attributes ---------- n_particles : int number of particles in the swarm. dimensions : int number of dimensions in the space. options : dict with keys :code:`{'c1', 'c2', 'w'}` a dictionary containing the parameters for the specific optimization technique. * c1 : float cognitive parameter * c2 : float social parameter * w : float inertia parameter bounds : tuple of numpy.ndarray, optional a tuple of size 2 where the first entry is the minimum bound while the second entry is the maximum bound. Each array must be of shape :code:`(dimensions,)`. bh_strategy : str a strategy for the handling of out-of-bounds particles. velocity_clamp : tuple, optional a tuple of size 2 where the first entry is the minimum velocity and the second entry is the maximum velocity. It sets the limits for velocity clamping. vh_strategy : str a strategy for the handling of the velocity of out-of-bounds particles. center : list (default is :code:`None`) an array of size :code:`dimensions` ftol : float relative error in objective_func(best_pos) acceptable for convergence. Default is :code:`-np.inf` init_pos : numpy.ndarray, optional option to explicitly set the particles' initial positions. Set to :code:`None` if you wish to generate the particles randomly. """ super(PSOoptimizer, self).__init__( n_particles=n_particles, dimensions=dimensions, options=options, bounds=bounds, velocity_clamp=velocity_clamp, center=center, ftol=ftol, init_pos=init_pos, ) # Initialize logger self.rep = Reporter(logger=logging.getLogger(__name__)) # Initialize the resettable attributes self.reset() # Initialize the topology self.top = Star() self.bh = BoundaryHandler(strategy=bh_strategy) self.vh = VelocityHandler(strategy=vh_strategy) self.name = __name__ # Populate memory of the handlers self.bh.memory = self.swarm.position self.vh.memory = self.swarm.position self.swarm.pbest_cost = np.full(self.swarm_size[0], np.inf) # Set reached requirement self.reached_requirement = 0
def mutate_swarm(self, swarm, mutation_factor, crossp, mutation_candidates,bounds, bh=BoundaryHandler(strategy="nearest")): # evaluation trial_pop=[] positions=swarm.position n_particles=swarm.position.shape[0] n_dims=swarm.position.shape[1] #mutation for i in range(n_particles): mutation_candidate=np.random.choice(mutation_candidates[i], 3, replace=False) a,b,c=positions[mutation_candidate] mutation_factor=0.8 mutant=a+mutation_factor*(b-c) #recombination crossp=0.7 cross_points = np.random.rand(n_dims) < crossp trial = np.where(cross_points, mutant, positions[i]) trial_pop.append(trial) trial_pop=np.array(trial_pop) # round and bound population trial_pop = bh(trial_pop, bounds) trial_pop[:, :swarm.discrete_index] = np.around(trial_pop[:, :swarm.discrete_index],decimals=6) trial_pop[:,swarm.discrete_index:]=np.rint(trial_pop[:,swarm.discrete_index:]) return trial_pop
def __init__( self, n_particles, dimensions_discrete, options, bounds, bh_strategy="periodic", init_pos=None, velocity_clamp=None, vh_strategy="unmodified", ftol=-np.inf, ftol_iter=1, ): """Initialize the swarm Attributes ---------- n_particles : int number of particles in the swarm. dimensions_discrete : int number of discrete dimensions of the search space. options : dict with keys :code:`{'c1', 'c2', 'w', 'k', 'p'}` a dictionary containing the parameters for the specific optimization technique * c1 : float cognitive parameter * c2 : float social parameter * w : float inertia parameter * k : int number of neighbors to be considered. Must be a positive integer less than :code:`n_particles` * p: int {1,2} the Minkowski p-norm to use. 1 is the sum-of-absolute values (or L1 distance) while 2 is the Euclidean (or L2) distance. bounds : tuple of numpy.ndarray a tuple of size 2 where the first entry is the minimum bound while the second entry is the maximum bound. Each array must be of shape :code:`(dimensions,)`. init_pos : numpy.ndarray, optional option to explicitly set the particles' initial positions. Set to :code:`None` if you wish to generate the particles randomly. velocity_clamp : tuple, optional a tuple of size 2 where the first entry is the minimum velocity and the second entry is the maximum velocity. It sets the limits for velocity clamping. vh_strategy : String a strategy for the handling of the velocity of out-of-bounds particles. Only the "unmodified" and the "adjust" strategies are allowed. ftol : float relative error in objective_func(best_pos) acceptable for convergence ftol_iter : int number of iterations over which the relative error in objective_func(best_pos) is acceptable for convergence. Default is :code:`1` """ # Initialize logger self.rep = Reporter(logger=logging.getLogger(__name__)) # Assign k-neighbors and p-value as attributes self.k, self.p = options["k"], options["p"] self.dimensions_discrete = dimensions_discrete self.bits, self.bounds = self.discretePSO_to_binaryPSO( dimensions_discrete, bounds) # Initialize parent class super(BinaryPSO, self).__init__( n_particles=n_particles, dimensions=sum(self.bits), binary=True, options=options, init_pos=init_pos, velocity_clamp=velocity_clamp, ftol=ftol, ftol_iter=ftol_iter, ) # self.bounds = bounds # Initialize the resettable attributes self.reset() # Initialize the topology self.top = Ring(static=False) self.vh = VelocityHandler(strategy=vh_strategy) self.bh = BoundaryHandler(strategy=bh_strategy) self.name = __name__
def test_input_swarm(self, swarm, bh_strat): """Test if method raises AttributeError with wrong swarm""" bh = BoundaryHandler(strategy=bh_strat) with pytest.raises(AttributeError): P.compute_position(swarm, bounds=([-5, -5], [5, 5]), bh=bh)