def random_ants(self, world, count, even=False): """Returns a list of :class:`Ant`\s distributed to the nodes of the world in a random fashion. Note that this does not ensure at least one :class:`Ant` begins at each node unless there are exactly as many :class:`Ant`\s as there are nodes. This method is used to create the :class:`Ant`\s before solving if *ant_count* is **not** ``0``. :param World world: the :class:`World` in which to create the ants. :param int count: the number of :class:`Ant`\s to create :param bool even: ``True`` if :func:`random.random` should avoid choosing the same starting node multiple times (default is ``False``) :return: the :class:`Ant`\s initialized to nodes in the :class:`World` :rtype: list """ ants = [] if even: starts = world.nodes n = len(starts) # Since the caller wants an even distribution, use a round-robin # method until the number of ants left to create is less than the # number of nodes. if count > n: for i in range(self.ant_count // n): ants.extend([ Ant(self.alpha, self.beta).initialize(world, start=starts[j]) for j in range(n) ]) # Now (without choosing the same node twice) choose the reamining # starts randomly. ants.extend([ Ant(self.alpha, self.beta).initialize(world, start=starts.pop( random.randrange(n - i))) for i in range(count % n) ]) else: start = 0 # Just pick random nodes. ants.extend([ Ant(self.alpha, self.beta).initialize(world, start=start) for i in range(count) ]) return ants
def set_params(self, solution_size=3, q0=0.1, alpha=0.9, beta=0.9, rho=0.05): # this is the same as __init__ self.__rho = rho self.__solution_size = solution_size new_sets_steps = list( permutations(list(range(1, self.__solution_size + 1)) * 2)) new_ants = [] for x in new_sets_steps: a = Ant(self.__solution_size) a.add_to_solution(x) new_ants.append(a) p = list( filter(lambda a: self.fitness_function(a) == MIN_FITNESS, new_ants)) new_sets_steps = [ant.last() for ant in p] self.__steps = [list(step) for step in new_sets_steps] self.__beta = beta self.__alpha = alpha self.__q0 = q0 self.__best_ant = None self.__colony_size = 0 self.__colony = [] self.__pheromone_matrices = [] # generate these matrices for _ in range(self.__solution_size * 2): self.__pheromone_matrices.append( [[1 for _ in range(self.__solution_size + 1)] for _ in range(self.__solution_size + 1)])
def epoch(self): if self.__graph.settings['dynamic'] and random( ) < self.__graph.settings['changeProb']: x, y = np.random.choice(self.__graph.nodes, size=2, replace=False) self.__graph[x][y] = self.__graph[y][x] = randint( self.__graph.settings['minCost'], self.__graph.settings['maxCost']) ants = [ Ant(self.__graph) for _ in range(self.__graph.settings['noAnts']) ] for _ in range(len(self.__graph) - 1): for ant in ants: ant.addMove() pheromons = [self.__graph.settings['Q'] / ant.fitness for ant in ants] for i in range(len(self.__graph)): for j in range(len(self.__graph)): self.__graph.trace[i][j] *= (1 - self.__graph.settings['decay'] ) # intensitatea urmei de feromon for index, ant in enumerate(ants): for i in range(len(ant.path) - 1): x = ant.path[i] y = ant.path[i + 1] self.__graph.trace[x][y] = pheromons[index] # furnica cu cel mai bun fitness return min([(ant.fitness, ant) for ant in ants], key=lambda pair: pair[0])[1]
def __init__(self, team_size, initializer, evaluation): self.__team_size = team_size self.__taboo = [] self.__solution = [] self.__loader = None self.__initial_states = [] self.__evaluation = sys.maxsize self.__evaluation_criterion = evaluation self.__ants = [Ant(initializer) for _ in range(team_size)]
def execute(self, graph: Graphic): best_cost = float('inf') best_solution = [] for it in range(self.__iterations): ants = [Ant(self, graph) for i in range(self.__ant_count)] for ant in ants: for i in range(graph.rank - 1): self.__select_next(ant) ant.total_cost += graph.matrix[ant.tabu[-1]][ant.tabu[0]] if ant.total_cost < best_cost: best_cost = ant.total_cost best_solution = [] + ant.tabu self.__update_pheromone_delta(ant) self.__update_pheromone(graph, ants) return best_solution, best_cost
def run(self): start_time_total = time.time() # maximum number of iterations start_iteration = 0 for iter in range(self.max_iter): # initialize ants ants = list(Ant(self.graph) for x in range(self.ants_num)) for k in range(self.ants_num): # visiting all customers while not ants[k].index_to_visit_empty(): next_index = self.select_next_index(ants[k]) # check if the condition is satisfied after joining the position, if not, select again if not ants[k].check_condition(next_index): next_index = self.select_next_index(ants[k]) if not ants[k].check_condition(next_index): next_index = 0 # update ant path ants[k].move_to_next_index(next_index) self.graph.local_update_pheromone(ants[k].current_index, next_index) # return to position 0 ants[k].move_to_next_index(0) self.graph.local_update_pheromone(ants[k].current_index, 0) # calculate the routes length of all ants paths_distance = np.array([ant.total_travel_distance for ant in ants]) # save the current best path best_index = np.argmin(paths_distance) if self.best_path is None or paths_distance[best_index] < self.best_path_distance: self.best_path = ants[int(best_index)].travel_path self.best_path_distance = paths_distance[best_index] self.best_vehicle_num = self.best_path.count(0) - 1 start_iteration = iter print('[iteration %d]: found better path, distance: %f' % (iter, self.best_path_distance)) # update pheromone table self.graph.global_update_pheromone(self.best_path, self.best_path_distance) given_iteration = 250 if iter - start_iteration > given_iteration: print('Cannot find better solution after %d iteration' % given_iteration) break print('Final best path dist is %f, number of vehicle is %d' % (self.best_path_distance, self.best_vehicle_num)) print('Running time: %0.3f seconds' % (time.time() - start_time_total)) print_graph(self.graph, self.best_path, self.best_path_distance, self.best_vehicle_num)
def round_robin_ants(self, world, count): """Returns a list of :class:`Ant`\s distributed to the nodes of the world in a round-robin fashion. Note that this does not ensure at least one :class:`Ant` begins at each node unless there are exactly as many :class:`Ant`\s as there are nodes. However, if *ant_count* is ``0`` then *ant_count* is set to the number of nodes in the :class:`World` and this method is used to create the :class:`Ant`\s before solving. :param World world: the :class:`World` in which to create the :class:`Ant`\s :param int count: the number of :class:`Ant`\s to create :return: the :class:`Ant`\s initialized to nodes in the :class:`World` :rtype: list """ starts = world.nodes n = len(starts) return [ Ant(self.alpha, self.beta).initialize(world, start=starts[i % n]) for i in range(count) ]
def epoch(self, colony_size): self.__colony_size = colony_size # create the colony self.__colony = [ Ant(self.__solution_size) for _ in range(self.__colony_size) ] for ant in self.__colony: ant.add_to_solution(deepcopy(choice(self.__steps))) # put the ants in random order for _ in range(self.__solution_size): for ant in self.__colony: self.add_move_to_ant(ant) # update the pheromone matrices for ant in self.__colony: self.update_pheromone_matrix(ant) # update the best ant if self.__best_ant: self.__best_ant = min(min(self.__colony, key=self.fitness_function), self.__best_ant, key=self.fitness_function) else: self.__best_ant = min(self.__colony, key=self.fitness_function)
def acs_vehicle(new_graph, vehicle_num, ants_num, q0, beta, global_path_queue, path_found_queue, stop_event): # vehicle_num is set to one less than the current best_path print('[acs_vehicle]: start, vehicle_num %d' % vehicle_num) global_best_path = None global_best_distance = None # Initialize path and distance using nearest_neighbor_heuristic algorithm current_path, current_path_distance, _ = new_graph.nearest_neighbor(max_vehicle_num=vehicle_num) # Find the unvisited nodes in the current path current_index_to_visit = list(range(new_graph.node_num)) for ind in set(current_path): current_index_to_visit.remove(ind) ants_pool = ThreadPoolExecutor(ants_num) ants_thread = [] ants = [] IN = np.zeros(new_graph.node_num) while True: print('[acs_vehicle]: new iteration') if stop_event.is_set(): print('[acs_vehicle]: receive stop event') return for k in range(ants_num): ant = Ant(new_graph, 0) thread = ants_pool.submit(MultipleAntColonySystem.new_active_ant, ant, vehicle_num, False, IN, q0, beta, stop_event) ants_thread.append(thread) ants.append(ant) # Here you can use the result method and wait for the thread to finish for thread in ants_thread: thread.result() for ant in ants: if stop_event.is_set(): print('[acs_vehicle]: receive stop event') return IN[ant.index_to_visit] = IN[ant.index_to_visit] + 1 # The path found by the ant is compared with the current_path, can you use the vehicle_num # vehicles to access more nodes if len(ant.index_to_visit) < len(current_index_to_visit): current_path = copy.deepcopy(ant.travel_path) current_index_to_visit = copy.deepcopy(ant.index_to_visit) current_path_distance = ant.total_travel_distance # And set IN to 0 IN = np.zeros(new_graph.node_num) # If this path is easy, it will be sent to macs_vrptw if ant.index_to_visit_empty(): print('[acs_vehicle]: found a feasible path, send path info to macs') path_found_queue.put(Path(ant.travel_path, ant.total_travel_distance)) # Update the pheromone in new_graph, global new_graph.global_update_pheromone(current_path, current_path_distance) if not global_path_queue.empty(): info = global_path_queue.get() while not global_path_queue.empty(): info = global_path_queue.get() print('[acs_vehicle]: receive global path info') global_best_path, global_best_distance, global_used_vehicle_num = info.get_path_info() new_graph.global_update_pheromone(global_best_path, global_best_distance) ants_thread.clear() for ant in ants: ant.clear() del ant ants.clear()
def acs_time(new_graph, vehicle_num, ants_num, q0, beta, global_path_queue, path_found_queue, stop_event): # You can use vehicle_num vehicles at most, that is, the path contains the most vehicle_num + 1 # depots to find the shortest path, vehicle_num is set to be consistent with the current best_path print('[acs_time]: start, vehicle_num %d' % vehicle_num) # initialize the pheromone matrix global_best_path = None global_best_distance = None ants_pool = ThreadPoolExecutor(ants_num) ants_thread = [] ants = [] while True: print('[acs_time]: new iteration') if stop_event.is_set(): print('[acs_time]: receive stop event') return for k in range(ants_num): ant = Ant(new_graph, 0) thread = ants_pool.submit(MultipleAntColonySystem.new_active_ant, ant, vehicle_num, True, np.zeros(new_graph.node_num), q0, beta, stop_event) ants_thread.append(thread) ants.append(ant) # Here you can use the result method and wait for the thread to finish for thread in ants_thread: thread.result() ant_best_travel_distance = None ant_best_path = None # Determine whether the path found by the ant is feasible and better than the global path for ant in ants: if stop_event.is_set(): print('[acs_time]: receive stop event') return # Get the current best path if not global_path_queue.empty(): info = global_path_queue.get() while not global_path_queue.empty(): info = global_path_queue.get() print('[acs_time]: receive global path info') global_best_path, global_best_distance, global_used_vehicle_num = info.get_path_info() # The shortest path calculated by the ant if ant.index_to_visit_empty() and ( ant_best_travel_distance is None or ant.total_travel_distance < ant_best_travel_distance): ant_best_travel_distance = ant.total_travel_distance ant_best_path = ant.travel_path # Perform global update of pheromone here new_graph.global_update_pheromone(global_best_path, global_best_distance) # Send the calculated current best path to macs if ant_best_travel_distance is not None and ant_best_travel_distance < global_best_distance: print('[acs_time]: ants\' local search found a improved feasible path, send path info to macs') path_found_queue.put(Path(ant_best_path, ant_best_travel_distance)) ants_thread.clear() for ant in ants: ant.clear() del ant ants.clear()