def optimize(self, iterations=10, swap=2, **kwargs) -> Tuple[float, np.ndarray]: """ Запуск метаэвристики табу поиска Алгоритм запоминает все локальные минимумы, и, если попадает в одно из них, перезапускает поиск iterations: количество возможных перезапусков swap: сколько раз ломать тур за итерацию. Если тур не улучшится, на следующей итерации ломается он же return: лучшая длина тура, лучший тур """ if self.collector is not None: self.collector.update({'length': self.length, 'gain': 0}) while iterations > 0: self.opt.meta_heuristic_optimize(self.data, self.collector) _length, _tour = self.best_tour() if self.length > _length: self.length, self.tour = _length, _tour # если найден другой хороший оптимум, обновляем текущий assert round(get_length(self.tour, self.matrix), 2) == round(self.length, 2), \ f'{get_length(self.tour, self.matrix)} != {self.length}' logging.info(f'{iterations} : {_length} : {self.length}') mix(self.tour, swap) # а вот ломается текущий сохраненный self.length = get_length(self.tour, self.matrix) self.opt.length, self.opt.tour = self.length, self.tour.copy( ) # улучшается только копия iterations -= 1 self.length, self.tour = self.best_tour() logging.info(f'tabu search done, best length: {self.length}') return self.length, self.tour
def worker(opt: AbcOpt, conn: Connection, iterations: int, swap: int): """ Локальный поиск под управлением Поиска с запретами Табу обновляется раз в итерацию, в основном процессе хранится весь табу opt: эвристика conn: для передачи данных iterations: количество возможных перезапусков swap: сколько раз ломать тур за итерацию """ best_length, best_tour = opt.length, opt.tour.copy() length, tour = opt.length, opt.tour try: while iterations > 0: _length, _tour = opt.optimize() if best_length > _length: best_length, best_tour = _length, _tour.copy() assert round(get_length(best_tour, opt.matrix), 2) == round(best_length, 2), \ f'{get_length(best_tour, opt.matrix)} != {best_length}' conn.send(opt.solutions) solutions = conn.recv() mix(tour, swap) length = get_length(tour, opt.matrix) opt.length, opt.tour, opt.solutions = length, tour, solutions iterations -= 1 except Exception as exc: print(f'Exception: {exc}') conn.send(set()) conn.send(best_length) conn.send(best_tour)
def test_lk_opt_full_bridge(generate_metric_tsp): length, tour, matrix = generate_metric_tsp lk_opt = LKOpt(length, tour, matrix, bridge=(1, True)) opt_length, opt_tour = lk_opt.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_lk_opt_simple(generate_metric_tsp): length, tour, matrix = generate_metric_tsp lk_opt = LKOpt(length, tour, matrix, dlb=False) opt_length, opt_tour = lk_opt.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_three_opt(generate_metric_tsp): length, tour, matrix = generate_metric_tsp three_opt = ThreeOpt(length, tour, matrix) opt_length, opt_tour = three_opt.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_tabu_proc_search(generate_metric_tsp): length, tour, matrix = generate_metric_tsp lkh_search = TabuProcSearch('two_opt', matrix) opt_length, opt_tour = lkh_search.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_lkh_search_with_two_opt_init(generate_metric_tsp): length, tour, matrix = generate_metric_tsp lkh_search = LKHSearch(matrix, two_opt=True) opt_length, opt_tour = lkh_search.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_lkh_search_helsgaun(generate_metric_tsp): length, tour, matrix = generate_metric_tsp lkh_search = LKHSearch(matrix, init='helsgaun') opt_length, opt_tour = lkh_search.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_tabu_search_with_collect(generate_metric_tsp): length, tour, matrix = generate_metric_tsp tabu_search = TabuSearch('two_opt', matrix, collect=True) opt_length, opt_tour = tabu_search.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_tabu_search_lkh_opt(generate_metric_tsp): length, tour, matrix = generate_metric_tsp tabu_search = TabuSearch('lkh_opt', matrix) opt_length, opt_tour = tabu_search.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_lkh_opt_non_seq(generate_metric_tsp): length, tour, matrix = generate_metric_tsp lkh_opt = LKHOpt(length, tour, matrix, bridge=True, non_seq=True) opt_length, opt_tour = lkh_opt.optimize() assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def optimize(self, iterations=10, **kwargs) -> Tuple[float, np.ndarray]: """ Запуск метаэвристики Multi trial LKH iterations: количество возможных перезапусков return: лучшая длина тура, лучший тур """ if self.collector is not None: self.collector.update({'length': self.length, 'gain': 0}) while iterations > 0: self.opt.meta_heuristic_optimize(self.data, self.collector) _length, _tour = self.best_tour() if self.length > _length: self.length, self.tour = _length, _tour # если найден другой хороший оптимум, обновляем текущий self.opt.best_solution = get_set(self.tour) assert round(get_length(self.tour, self.matrix), 2) == round(self.length, 2), \ f'{get_length(self.tour, self.matrix)} != {self.length}' logging.info(f'{iterations} : {_length} : {self.length}') if self.initial == 'helsgaun' or self.initial == 'fast_helsgaun': self.opt.length, self.opt.tour = _initialization[self.initial]( self.opt.alpha, self.matrix, self.opt.best_solution, self.opt.candidates, self.opt.excess) else: self.opt.length, self.opt.tour = _initialization[self.initial](self.matrix) assert round(get_length(self.opt.tour, self.matrix), 2) == round(self.opt.length, 2), \ f'{get_length(self.opt.tour, self.matrix)} != {self.opt.length}' iterations -= 1 self.length, self.tour = self.best_tour() logging.info(f'multi trial lkh done, best length: {self.length}') return self.length, self.tour
def meta_heuristic_optimize( self, tabu_list: TabuSet, collector: Optional[Collector]) -> Tuple[float, np.ndarray]: """ Запуск локального поиска под управление некоторой метаэвристики tabu_list: проверенные ранее маршруты collector: структура для сбора данных о локальном поиске return: длина, список городов """ gain, self.tabu_list, self.collector = 1, tabu_list, collector self.solutions = self.tabu_list.data while gain > 0: gain = self.improve() if gain > 1.e-10: if not self.tabu_list.append(self.length, self.tour): break logging.info(self.length) assert round(get_length(self.tour, self.matrix), 2) == round(self.length, 2), \ f'{get_length(self.tour, self.matrix)} != {self.length}' return self.length, self.tour
def optimize(self) -> Tuple[float, np.ndarray]: """ Запуск локального поиска return: длина, список городов """ gain, iteration = 1, 0 logging.info(f'start : {self.length}') while gain > 0: gain = self.improve() if gain > 0: logging.info(f'{iteration} : {self.length}') iteration += 1 h = generate_hash(self.tour) if h in self.solutions: break else: self.solutions.add(h) assert round(get_length(self.tour, self.matrix), 2) == round(self.length, 2), \ f'{get_length(self.tour, self.matrix)} != {self.length}' return self.length, self.tour
def test_fast_three_opt(generate_metric_tsp): length, tour, matrix = generate_metric_tsp opt_length, opt_tour = ThreeOpt.just_improve(length, tour, matrix) assert opt_length < length, 'optimized' assert round(get_length(opt_tour, matrix), 2) == round(opt_length, 2), 'generated wrong tour'
def test_greedy_with_two_opt(): tsp = generator(size) matrix = adjacency_matrix(tsp) length, tour = two_opt(matrix) assert round(get_length(tour, matrix), 2) == round(length, 2), 'generated wrong tour'