def alns(self, sol: Solution): """Perform adaptive large neighborhood search (ALNS) on given solution.""" self.next_segment = self.iteration + self.own_settings.mh_alns_segment_size sol_incumbent = sol.copy() sol_new = sol.copy() while True: destroy, repair = self.select_method_pair() res = self.perform_method_pair(destroy, repair, sol_new) self.update_after_destroy_and_repair_performed( destroy, repair, sol_new, sol_incumbent, sol) if res.terminate: sol.copy_from(sol_incumbent) return self.update_operator_weights()
def gvns(self, sol: Solution): """Perform general variable neighborhood search (GVNS) to given solution.""" sol2 = sol.copy() if self.vnd(sol2) or not self.meths_sh: return use_vnd = bool(self.meths_li) while True: for m in self.next_method(self.meths_sh, repeat=True): t_start = time.process_time() res = self.perform_method(m, sol2, delayed_success=use_vnd) terminate = res.terminate if not terminate and use_vnd: terminate = self.vnd(sol2) self.delayed_success_update(m, sol.obj(), t_start, sol2) if sol2.is_better(sol): sol.copy_from(sol2) if terminate or res.terminate: return break else: if terminate or res.terminate: return sol2.copy_from(sol) else: break
def ts(self, sol: Solution): while True: # use of multiple different methods for restricted neighborhood search is possible, # but usually only one is used for m in self.next_method(self.meths_rli, repeat=True): sol_old = sol.copy() def ts_iteration(sol: Solution, _par, result): for ta in self.tabu_list.tabu_list: self.step_logger.info(f'TA: {ta}') m.func(sol, m.par, None, self.tabu_list, self.incumbent) ts_method = Method(m.name, ts_iteration, m.par) t_start = time.process_time() res = self.perform_method(ts_method, sol, delayed_success=True) self.update_tabu_list(sol, sol_old) self.delayed_success_update(m, sol.obj(), t_start, sol_old) for ta in self.tabu_list.tabu_list: self.step_logger.info(f'TA: {ta}') if res.terminate: return
def __new__(cls, sol: Solution, meths_ch: List[Method], own_settings: dict = None): """Create population of mh_pop_size solutions using the list of construction heuristics if given. If sol is None or no constructors are given, the population is initialized empty. sol itself is just used as template for obtaining further solutions. """ own_settings = OwnSettings(own_settings) if own_settings else settings size = own_settings.mh_pop_size obj = super(Population, cls).__new__(cls, size, Solution) obj.own_settings = own_settings if sol is not None and meths_ch: # cycle through construction heuristics to generate population # perform all construction heuristics, take best solution meths_cycle = cycle(meths_ch) idx = 0 while idx < size: m = next(meths_cycle) sol = sol.copy() res = Result() m.func(sol, m.par, res) if own_settings.mh_pop_dupelim and obj.duplicates_of( sol) != []: continue # do not add this duplicate obj[idx] = sol if res.terminate: break idx += 1 return obj
def alns(self, sol: Solution): """Perform adaptive large neighborhood search (ALNS) on given solution.""" self.next_segment = self.iteration + self.own_settings.mh_alns_segment_size sol_incumbent = sol.copy() sol_new = sol.copy() operators = self.operators_generator(sol_new) worker_seed = 0 if settings.mh_workers > 1 else settings.seed with mp.Pool(processes=settings.mh_workers, initializer=self.process_init, initargs=(settings, worker_seed)) as worker_pool: result_iter = worker_pool.imap_unordered( self.perform_method_pair_in_worker, operators) for result in result_iter: # print("Result:", result) destroy, repair, sol_result, res, obj_old, t_destroy, t_repair = result sol_new.copy_from(sol_result) self.update_stats_for_method_pair(destroy, repair, sol, res, obj_old, t_destroy, t_repair) self.update_after_destroy_and_repair_performed( destroy, repair, sol_new, sol_incumbent, sol) if res.terminate: sol.copy_from(sol_incumbent) return self.update_operator_weights()
def vnd(self, sol: Solution) -> bool: """Perform variable neighborhood descent (VND) on given solution. :returns: true if a global termination condition is fulfilled, else False. """ sol2 = sol.copy() while True: for m in self.next_method(self.meths_li): res = self.perform_method(m, sol2) if sol2.is_better(sol): sol.copy_from(sol2) if res.terminate: return True break if res.terminate: return True if res.changed: sol2.copy_from(sol) else: # local optimum reached return False