




import argparse
import copy




def 		lowerCAmelCase_ (						lowerCamelCase ):
				__magic_name__						:						Tuple										={}

				with open(lowerCamelCase ) as f:
								for line in f:
												if line.split()[0] not in dict_of_neighbours:
																__magic_name__						:						Optional[Any]										=[]
																_list.append([line.split()[1], line.split()[2]] )
																__magic_name__						:						Dict										=_list
												else:
																dict_of_neighbours[line.split()[0]].append(
																    [line.split()[1], line.split()[2]] )
												if line.split()[1] not in dict_of_neighbours:
																__magic_name__						:						List[Any]										=[]
																_list.append([line.split()[0], line.split()[2]] )
																__magic_name__						:						Tuple										=_list
												else:
																dict_of_neighbours[line.split()[1]].append(
																    [line.split()[0], line.split()[2]] )

				return dict_of_neighbours




def 		lowerCAmelCase_ (						lowerCamelCase						,  lowerCamelCase ):

				with open(lowerCamelCase ) as f:
								__magic_name__						:						Optional[int]										=f.read(1 )
				__magic_name__						:						Any										=start_node

				__magic_name__						:						Union[str, Any]										=[]

				__magic_name__						:						Dict										=start_node

				__magic_name__						:						List[Any]										=0
				while visiting not in first_solution:
								__magic_name__						:						Dict										=10000
								for k in dict_of_neighbours[visiting]:
												if int(k[1] ) < int(lowerCamelCase ) and k[0] not in first_solution:
																__magic_name__						:						Tuple										=k[1]
																__magic_name__						:						str										=k[0]

								first_solution.append(lowerCamelCase )
								__magic_name__						:						Optional[Any]										=distance_of_first_solution + int(lowerCamelCase )
								__magic_name__						:						Tuple										=best_node

				first_solution.append(lowerCamelCase )

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

				__magic_name__						:						Union[str, Any]										=(
				    distance_of_first_solution
				    + int(dict_of_neighbours[first_solution[-2]][position][1] )
				    - 10000
				)
				return first_solution, distance_of_first_solution




def 		lowerCAmelCase_ (						lowerCamelCase						,  lowerCamelCase ):
				__magic_name__						:						Union[str, Any]										=[]

				for n in solution[1:-1]:
								__magic_name__						:						Union[str, Any]										=solution.index(lowerCamelCase )
								for kn in solution[1:-1]:
												__magic_name__						:						Union[str, Any]										=solution.index(lowerCamelCase )
												if n == kn:
																continue

												__magic_name__						:						str										=copy.deepcopy(lowerCamelCase )
												__magic_name__						:						List[str]										=kn
												__magic_name__						:						List[str]										=n

												__magic_name__						:						List[Any]										=0

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

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

				__magic_name__						:						List[str]										=len(neighborhood_of_solution[0] ) - 1

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




def 		lowerCAmelCase_ (						lowerCamelCase						,  lowerCamelCase						,  lowerCamelCase						,  lowerCamelCase						,  lowerCamelCase ):
				__magic_name__						:						List[str]										=1
				__magic_name__						:						List[str]										=first_solution
				__magic_name__						:						int										=[]
				__magic_name__						:						Dict										=distance_of_first_solution
				__magic_name__						:						Union[str, Any]										=solution

				while count <= iters:
								__magic_name__						:						Dict										=find_neighborhood(lowerCamelCase						,  lowerCamelCase )
								__magic_name__						:						Any										=0
								__magic_name__						:						Any										=neighborhood[index_of_best_solution]
								__magic_name__						:						Optional[Any]										=len(lowerCamelCase ) - 1

								__magic_name__						:						List[str]										=False
								while not found:
												__magic_name__						:						Any										=0
												while i < len(lowerCamelCase ):
																if best_solution[i] != solution[i]:
																				__magic_name__						:						Any										=best_solution[i]
																				__magic_name__						:						Optional[Any]										=solution[i]
																				break
																__magic_name__						:						int										=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] )
																__magic_name__						:						Optional[int]										=True
																__magic_name__						:						List[str]										=best_solution[:-1]
																__magic_name__						:						Optional[Any]										=neighborhood[index_of_best_solution][best_cost_index]
																if cost < best_cost:
																				__magic_name__						:						List[Any]										=cost
																				__magic_name__						:						List[Any]										=solution
												else:
																__magic_name__						:						Optional[Any]										=index_of_best_solution + 1
																__magic_name__						:						List[str]										=neighborhood[index_of_best_solution]

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

								__magic_name__						:						Optional[int]										=count + 1

				return best_solution_ever, best_cost




def 		lowerCAmelCase_ (						lowerCamelCase=None ):
				__magic_name__						:						int										=generate_neighbours(args.File )

				__magic_name__					,			__magic_name__						:						str										=generate_first_solution(
				    args.File						,  lowerCamelCase )

				__magic_name__					,			__magic_name__						:						List[Any]										=tabu_search(
				    lowerCamelCase						,  lowerCamelCase						,  lowerCamelCase						,  args.Iterations						,  args.Size						,  )

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


if __name__ == "__main__":
							UpperCAmelCase_		:					List[str]          =  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"""







def     UpperCAmelCase_					(				__a   :			int						):




			'''simple docstring'''



			_lowerCamelCase					:					Optional[Any]	       =    int(__a						)
			if decimal in (0, 1):  # Exit cases for the recursion
						return str(__a						)
			_lowerCamelCase       ,							_lowerCamelCase					:					Union[str, Any]	       =    divmod(__a      ,							2						)
			return binary_recursive(__a						) + str(__a						)

def     UpperCAmelCase_					(				__a   :			str						):




			'''simple docstring'''



			_lowerCamelCase					:					int	       =    str(__a						).strip()
			if not number:
						raise ValueError('No input value was provided'						)
			_lowerCamelCase					:					Tuple	       =    '-' if number.startswith('-'						) else ''
			_lowerCamelCase					:					List[Any]	       =    number.lstrip('-'						)
			if not number.isnumeric():
						raise ValueError('Input value is not an integer'						)
			return f"{negative}0b{binary_recursive(int(__a						)						)}"


if __name__ == "__main__":
	from doctest import testmod

	testmod()





