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 run(self): """Actually performs the construction heuristics followed by the SteadyStateGeneticAlgorithm.""" population = self.population while True: # Create a new solution p1 = population[population.select()].copy() # Methods to perform in this iteration methods: List[Method] = [] # Optionally crossover if random.random() < self.own_settings.mh_ssga_cross_prob: p2 = population[population.select()].copy() # Workaround for Method not allowing a second Solution as parameter def meth_cx(crossover, p2: Solution, p1: Solution, par: Any, res: Result): crossover(p1, p2) meth_cx_with_p2_bound = partial(meth_cx, self.meth_cx, p2) meth = Method("cx", meth_cx_with_p2_bound, None) methods.append(meth) # Mutation methods.append(self.meth_mu) # Optionally local search if self.meth_ls and random.random( ) < self.own_settings.mh_ssga_loc_prob: methods.append(self.meth_ls) res = self.perform_methods(methods, p1) if res.terminate: break # Replace in population worst = population.worst() population[worst].copy_from(p1) # Update best solution if p1.is_better(self.incumbent): self.incumbent = p1
def sa(self, sol: Solution): """Perform simulated annealing with geometric cooling on given solution.""" def sa_iteration(sol: Solution, _par, result): neighborhood_move, delta_obj = self.random_move_delta_eval(sol) acceptance = self.metropolis_criterion(sol, delta_obj) if acceptance: self.apply_neighborhood_move(sol, neighborhood_move) sol.obj_val = sol.obj_val + delta_obj result.changed = True if self.iter_cb is not None: self.iter_cb(self.iteration, sol, self.temperature, acceptance) sa_method = Method("sa", sa_iteration, 0) while True: for _ in range(self.equi_iter): t_start = time.process_time() obj_old = self.incumbent.obj() res = self.perform_method(sa_method, sol, delayed_success=True) self.delayed_success_update(sa_method, obj_old, t_start, sol) if res.terminate: return True self.cool_down()
def run_optimization(problem_name: str, instance_class, solution_class, default_inst_file: str = "inst.dat", own_settings: dict = None, embedded: bool = False, iter_cb: Callable = None, seed: int = 0) -> Solution: """Initialize and run optimization algorithm given by parameter alg on given problem instance. First, some general parameters for the algorithm to be applied, the instance file, and the methods to be applied are registered and the settings are parsed. Then the loggers are initialized, instance and solution objects are created and the chosen algorithm is performed. The resulting solution is finally returned. :param problem_name: name of the problem to be printed :param instance_class: class of the instance to be solved :param solution_class: concrete solution class to be used :param default_inst_file: default instance file to be loaded and solved :param own_settings: optional run-specific settings dictionary :param embedded: if set it is assumed that the call is embedded in a Notebook or other larger framework, and therefore, the parameters are assumed to be already registered and parsed :param iter_cb: optional callback function that is called each iteration by some of the algorithms :param seed: optional seed value for the random number generators; 0: random initialization """ if not embedded: add_general_arguments_and_parse_settings(default_inst_file, seed=seed) init_logger() logger = logging.getLogger("pymhlib") logger.info("pymhlib demo for solving %s", problem_name) logger.info(get_settings_as_str()) instance = instance_class(settings.inst_file) logger.info("%s instance read:\n%s", problem_name, str(instance)) solution = solution_class(instance) # solution.initialize(0) logger.info("Solution: %s, obj=%f\n", solution, solution.obj()) if settings.alg == 'gvns': alg = GVNS(solution, [ Method(f"ch{i}", solution_class.construct, i) for i in range(settings.meths_ch) ], [ Method(f"li{i}", solution_class.local_improve, i) for i in range(1, settings.meths_li + 1) ], [ Method(f"sh{i}", solution_class.shaking, i) for i in range(1, settings.meths_sh + 1) ], own_settings) elif settings.alg == 'alns': alg = ALNS(solution, [ Method(f"ch{i}", solution_class.construct, i) for i in range(settings.meths_ch) ], [ Method(f"de{i}", solution_class.destroy, i) for i in range(1, settings.meths_de + 1) ], [ Method(f"re{i}", solution_class.repair, i) for i in range(1, settings.meths_re + 1) ], own_settings) elif settings.alg == 'pbig': alg = PBIG(solution, [ Method(f"ch{i}", solution_class.construct, i) for i in range(settings.meths_ch) ], [ Method(f"li{i}", solution_class.local_improve, i) for i in range(1, settings.meths_li + 1) ] + [ Method(f"sh{i}", solution_class.shaking, i) for i in range(1, settings.meths_sh + 1) ], own_settings) elif settings.alg == 'par_alns': alg = ParallelALNS(solution, [ Method(f"ch{i}", solution_class.construct, i) for i in range(settings.meths_ch) ], [ Method(f"de{i}", solution_class.destroy, i) for i in range(1, settings.meths_de + 1) ], [ Method(f"re{i}", solution_class.repair, i) for i in range(1, settings.meths_re + 1) ], own_settings) elif settings.alg == 'ssga': alg = SteadyStateGeneticAlgorithm( solution, [ Method("ch{i}", solution_class.construct, i) for i in range(settings.meths_ch) ], solution_class.crossover, Method("mu", solution_class.shaking, 1), Method("ls", solution_class.local_improve, 1), own_settings) elif settings.alg == 'sa': alg = SA(solution, [ Method(f"ch{i}", solution_class.construct, i) for i in range(settings.meths_ch) ], solution_class.random_move_delta_eval, solution_class.apply_neighborhood_move, iter_cb, own_settings) else: raise ValueError( 'Invalid optimization algorithm selected (settings.alg): ', settings.alg) alg.run() logger.info("") alg.method_statistics() alg.main_results() return solution
def run_optimization(problem_name: str, Instance, Solution, default_inst_file: str, own_settings=None, embedded=False, iter_cb=None): """Run optimization algorithm given by parameter alg on given problem instance.""" if not embedded: parser = get_settings_parser() parser.add("--alg", type=str, default='gvns', help='optimization algorithm to be used ' '(gvns, alns, parallel_alns, ssga)') parser.add("--inst_file", type=str, default=default_inst_file, help='problem instance file') parser.add("--meths_ch", type=int, default=1, help='number of construction heuristics to be used') parser.add("--meths_li", type=int, default=1, help='number of local improvement methods to be used') parser.add("--meths_sh", type=int, default=5, help='number of shaking methods to be used') parser.add("--meths_de", type=int, default=3, help='number of destroy methods to be used') parser.add("--meths_re", type=int, default=3, help='number of repair methods to be used') # parser.set_defaults(seed=3) parse_settings() init_logger() logger = logging.getLogger("pymhlib") logger.info(f"pymhlib demo for solving {problem_name}") logger.info(get_settings_as_str()) instance = Instance(settings.inst_file) logger.info(f"{problem_name} instance read:\n" + str(instance)) solution = Solution(instance) # solution.initialize(0) logger.info(f"Solution: {solution}, obj={solution.obj()}\n") if settings.alg == 'gvns': alg = GVNS(solution, [Method(f"ch{i}", Solution.construct, i) for i in range(settings.meths_ch)], [Method(f"li{i}", Solution.local_improve, i) for i in range(1, settings.meths_li + 1)], [Method(f"sh{i}", Solution.shaking, i) for i in range(1, settings.meths_sh + 1)], own_settings) elif settings.alg == 'alns': alg = ALNS(solution, [Method(f"ch{i}", Solution.construct, i) for i in range(settings.meths_ch)], [Method(f"de{i}", Solution.destroy, i) for i in range(1, settings.meths_de + 1)], [Method(f"re{i}", Solution.repair, i) for i in range(1, settings.meths_re + 1)], own_settings) elif settings.alg == 'pbig': alg = PBIG(solution, [Method(f"ch{i}", Solution.construct, i) for i in range(settings.meths_ch)], [Method(f"li{i}", Solution.local_improve, i) for i in range(1, settings.meths_li + 1)] + [Method(f"sh{i}", Solution.shaking, i) for i in range(1, settings.meths_sh + 1)], own_settings) elif settings.alg == 'par_alns': alg = ParallelALNS(solution, [Method(f"ch{i}", Solution.construct, i) for i in range(settings.meths_ch)], [Method(f"de{i}", Solution.destroy, i) for i in range(1, settings.meths_de + 1)], [Method(f"re{i}", Solution.repair, i) for i in range(1, settings.meths_re + 1)], own_settings) elif settings.alg == 'ssga': alg = SteadyStateGeneticAlgorithm(solution, [Method(f"ch{i}", Solution.construct, i) for i in range(settings.meths_ch)], Solution.crossover, Method(f"mu", Solution.shaking, 1), Method(f"ls", Solution.local_improve, 1), own_settings) elif settings.alg == 'sa': alg = SA(solution, [Method(f"ch{i}", Solution.construct, i) for i in range(settings.meths_ch)], Solution.random_move_delta_eval, Solution.apply_neighborhood_move, iter_cb, own_settings) else: raise ValueError('Invalid optimization algorithm selected (settings.alg): ', settings.alg) alg.run() logger.info("") alg.method_statistics() alg.main_results()
def get_method(self, opt: Option, par=None): param = par if par != None else self.value if self.callback == None: return None return Method(f'{opt.name.lower()}{param if param != None else ""}', self.callback, param)