






'''simple docstring'''


import argparse
import copy







def 	__magic_name__( _A					):
						'''simple docstring'''





						UpperCamelCase__         = {}

						with open(_A					) as f:
												for line in f:
																		if line.split()[0] not in dict_of_neighbours:
																								UpperCamelCase__         = []
																								_list.append([line.split()[1], line.split()[2]]					)
																								UpperCamelCase__         = _list
																		else:
																								dict_of_neighbours[line.split()[0]].append(
																								    [line.split()[1], line.split()[2]]					)
																		if line.split()[1] not in dict_of_neighbours:
																								UpperCamelCase__         = []
																								_list.append([line.split()[0], line.split()[2]]					)
																								UpperCamelCase__         = _list
																		else:
																								dict_of_neighbours[line.split()[1]].append(
																								    [line.split()[0], line.split()[2]]					)

						return dict_of_neighbours







def 	__magic_name__( _A						,      _A					):
						'''simple docstring'''





						with open(_A					) as f:
												UpperCamelCase__         = f.read(1					)
						UpperCamelCase__         = start_node

						UpperCamelCase__         = []

						UpperCamelCase__         = start_node

						UpperCamelCase__         = 0
						while visiting not in first_solution:
												UpperCamelCase__         = 1_0000
												for k in dict_of_neighbours[visiting]:
																		if int(k[1]					) < int(_A					) and k[0] not in first_solution:
																								UpperCamelCase__         = k[1]
																								UpperCamelCase__         = k[0]

												first_solution.append(_A					)
												UpperCamelCase__         = distance_of_first_solution + int(_A					)
												UpperCamelCase__         = best_node

						first_solution.append(_A					)

						UpperCamelCase__         = 0
						for k in dict_of_neighbours[first_solution[-2]]:
												if k[0] == start_node:
																		break
												position += 1

						UpperCamelCase__         = (
						    distance_of_first_solution
						    + int(dict_of_neighbours[first_solution[-2]][position][1]					)
						    - 1_0000
						)
						return first_solution, distance_of_first_solution







def 	__magic_name__( _A						,      _A					):
						'''simple docstring'''





						UpperCamelCase__         = []

						for n in solution[1:-1]:
												UpperCamelCase__         = solution.index(_A					)
												for kn in solution[1:-1]:
																		UpperCamelCase__         = solution.index(_A					)
																		if n == kn:
																								continue

																		UpperCamelCase__         = copy.deepcopy(_A					)
																		UpperCamelCase__         = kn
																		UpperCamelCase__         = n

																		UpperCamelCase__         = 0

																		for k in _tmp[:-1]:
																								UpperCamelCase__         = _tmp[_tmp.index(_A					) + 1]
																								for i in dict_of_neighbours[k]:
																														if i[0] == next_node:
																																				UpperCamelCase__         = distance + int(i[1]					)
																		_tmp.append(_A					)

																		if _tmp not in neighborhood_of_solution:
																								neighborhood_of_solution.append(_tmp					)

						UpperCamelCase__         = len(neighborhood_of_solution[0]					) - 1

						neighborhood_of_solution.sort(key=lambda _A					: x[index_of_last_item_in_the_list]					)
						return neighborhood_of_solution







def 	__magic_name__( _A						,      _A						,      _A						,      _A						,      _A					):
						'''simple docstring'''





						UpperCamelCase__         = 1
						UpperCamelCase__         = first_solution
						UpperCamelCase__         = []
						UpperCamelCase__         = distance_of_first_solution
						UpperCamelCase__         = solution

						while count <= iters:
												UpperCamelCase__         = find_neighborhood(_A						,      _A					)
												UpperCamelCase__         = 0
												UpperCamelCase__         = neighborhood[index_of_best_solution]
												UpperCamelCase__         = len(_A					) - 1

												UpperCamelCase__         = False
												while not found:
																		UpperCamelCase__         = 0
																		while i < len(_A					):
																								if best_solution[i] != solution[i]:
																														UpperCamelCase__         = best_solution[i]
																														UpperCamelCase__         = solution[i]
																														break
																								UpperCamelCase__         = i + 1

																		if [first_exchange_node, second_exchange_node] not in tabu_list and [
																		    second_exchange_node,
																		    first_exchange_node,
																		] not in tabu_list:
																								tabu_list.append([first_exchange_node, second_exchange_node]					)
																								UpperCamelCase__         = True
																								UpperCamelCase__         = best_solution[:-1]
																								UpperCamelCase__         = neighborhood[index_of_best_solution][best_cost_index]
																								if cost < best_cost:
																														UpperCamelCase__         = cost
																														UpperCamelCase__         = solution
																		else:
																								UpperCamelCase__         = index_of_best_solution + 1
																								UpperCamelCase__         = neighborhood[index_of_best_solution]

												if len(_A					) >= size:
																		tabu_list.pop(0					)

												UpperCamelCase__         = count + 1

						return best_solution_ever, best_cost







def 	__magic_name__( _A=None					):
						'''simple docstring'''





						UpperCamelCase__         = generate_neighbours(args.File					)

						UpperCamelCase__    ,   UpperCamelCase__         = generate_first_solution(
						    args.File						,      _A					)

						UpperCamelCase__    ,   UpperCamelCase__         = tabu_search(
						    _A						,      _A						,      _A						,      args.Iterations						,      args.Size						,      )

						print(f"Best solution: {best_sol}, with total distance: {best_cost}."					)


if __name__ == "__main__":
					lowerCamelCase_				: Dict    	=							argparse.ArgumentParser(description='''Tabu Search''')
					parser.add_argument(
					    '''-f''',
					    '''--File''',
					    type=str,
					    help='''Path to the file containing the data''',
					    required=True,
					)
					parser.add_argument(
					    '''-i''',
					    '''--Iterations''',
					    type=int,
					    help='''How many iterations the algorithm should perform''',
					    required=True,
					)
					parser.add_argument(
					    '''-s''', '''--Size''', type=int, help='''Size of the tabu list''', required=True
					)

					# Pass the arguments to main method
					main(parser.parse_args())








'''simple docstring'''


import logging
import os
from logging import (
    CRITICAL,  # NOQA
    DEBUG,  # NOQA
    ERROR,  # NOQA
    FATAL,  # NOQA
    INFO,  # NOQA
    NOTSET,  # NOQA
    WARN,  # NOQA
    WARNING,  # NOQA
)
from typing import Optional

from tqdm import auto as tqdm_lib


lowerCamelCase_				: Any    	=							{
    '''debug''': logging.DEBUG,
    '''info''': logging.INFO,
    '''warning''': logging.WARNING,
    '''error''': logging.ERROR,
    '''critical''': logging.CRITICAL,
}

lowerCamelCase_				: Optional[int]    	=							logging.WARNING







def 	__magic_name__( ):
						'''simple docstring'''





						UpperCamelCase__         = os.getenv("""DATASETS_VERBOSITY"""						,      _A					)
						if env_level_str:
												if env_level_str in log_levels:
																		return log_levels[env_level_str]
												else:
																		logging.getLogger().warning(
																		    f"Unknown option DATASETS_VERBOSITY={env_level_str}, "
																		    f"has to be one of: { ', '.join(log_levels.keys()					) }"					)
						return _default_log_level







def 	__magic_name__( ):
						'''simple docstring'''





						return __name__.split("""."""					)[0]







def 	__magic_name__( ):
						'''simple docstring'''





						return logging.getLogger(_get_library_name()					)







def 	__magic_name__( ):
						'''simple docstring'''





						UpperCamelCase__         = _get_library_root_logger()
						library_root_logger.setLevel(_get_default_logging_level()					)







def 	__magic_name__( ):
						'''simple docstring'''





						UpperCamelCase__         = _get_library_root_logger()
						library_root_logger.setLevel(logging.NOTSET					)







def 	__magic_name__( _A = None					):
						'''simple docstring'''





						if name is None:
												UpperCamelCase__         = _get_library_name()
						return logging.getLogger(_A					)







def 	__magic_name__( ):
						'''simple docstring'''





						return _get_library_root_logger().getEffectiveLevel()







def 	__magic_name__( _A					):
						'''simple docstring'''





						_get_library_root_logger().setLevel(_A					)







def 	__magic_name__( ):
						'''simple docstring'''





						return set_verbosity(_A					)







def 	__magic_name__( ):
						'''simple docstring'''





						return set_verbosity(_A					)







def 	__magic_name__( ):
						'''simple docstring'''





						return set_verbosity(_A					)







def 	__magic_name__( ):
						'''simple docstring'''





						return set_verbosity(_A					)







def 	__magic_name__( ):
						'''simple docstring'''





						UpperCamelCase__         = False







def 	__magic_name__( ):
						'''simple docstring'''





						UpperCamelCase__         = True


# Configure the library root logger at the module level (singleton-like)
_configure_library_root_logger()
class    _SCREAMING_SNAKE_CASE							:


			'''simple docstring'''





			def __init__(   self							:						int ,      *lowercase							:						Any ,      **lowercase							:						int			)							->    List[Any]:  # pylint: disable=unused-argument

									'''simple docstring'''







									UpperCamelCase__         = args[0] if args else None






			def __iter__(   self							:						str			)							->    List[str]:

									'''simple docstring'''







									return iter(self._iterator			)






			def __getattr__(   self							:						Optional[int] ,      lowercase							:						Tuple			)							->    int:

									'''simple docstring'''







									def empty_fn(*lowercase							:						List[Any] ,      **lowercase							:						Dict			):  # pylint: disable=unused-argument
															return

									return empty_fn






			def __enter__(   self							:						Dict			)							->    Tuple:

									'''simple docstring'''







									return self







			def __exit__(   self							:						Tuple ,      lowercase							:						Optional[Any] ,      lowercase							:						Any ,      lowercase							:						int			)							->    Any:

									'''simple docstring'''







									return
lowerCamelCase_				: str    	=							True
class    _SCREAMING_SNAKE_CASE							:


			'''simple docstring'''





			def __call__(   self							:						List[Any] ,      *lowercase							:						str ,      lowercase							:						Optional[int]=False ,      **lowercase							:						Optional[int]			)							->    Optional[int]:

									'''simple docstring'''







									if _tqdm_active and not disable:
															return tqdm_lib.tqdm(*lowercase ,      **lowercase			)
									else:
															return EmptyTqdm(*lowercase ,      **lowercase			)






			def 				A      (   self							:						Optional[Any] ,      *lowercase							:						Tuple ,      **lowercase							:						Any			)							->    Any:

									'''simple docstring'''







									UpperCamelCase__         = None
									if _tqdm_active:
															return tqdm_lib.tqdm.set_lock(*lowercase ,      **lowercase			)







			def 				A      (   self							:						Optional[Any]			)							->    Optional[Any]:

									'''simple docstring'''







									if _tqdm_active:
															return tqdm_lib.tqdm.get_lock()
lowerCamelCase_				: int    	=							_tqdm_cls()







def 	__magic_name__( ):
						'''simple docstring'''





						global _tqdm_active
						return bool(_tqdm_active					)







def 	__magic_name__( ):
						'''simple docstring'''





						global _tqdm_active
						UpperCamelCase__         = True







def 	__magic_name__( ):
						'''simple docstring'''





						global _tqdm_active
						UpperCamelCase__         = False
