import argparse
import copy





def  __lowerCamelCase     (			UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   {}

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

							return dict_of_neighbours





def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






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

							snake_case_          =   []

							snake_case_          =   start_node

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

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

							first_solution.append(UpperCamelCase__				)

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

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





def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   []

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

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

																					snake_case_          =   0

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

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

							snake_case_          =   len(neighborhood_of_solution[0]				) - 1

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





def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__       ,							UpperCamelCase__       ,							UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   1
							snake_case_          =   first_solution
							snake_case_          =   []
							snake_case_          =   distance_of_first_solution
							snake_case_          =   solution

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

														snake_case_          =   False
														while not found:
																					snake_case_          =   0
																					while i < len(UpperCamelCase__				):
																												if best_solution[i] != solution[i]:
																																			snake_case_          =   best_solution[i]
																																			snake_case_          =   solution[i]
																																			break
																												snake_case_          =   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]				)
																												snake_case_          =   True
																												snake_case_          =   best_solution[:-1]
																												snake_case_          =   neighborhood[index_of_best_solution][best_cost_index]
																												if cost < best_cost:
																																			snake_case_          =   cost
																																			snake_case_          =   solution
																					else:
																												snake_case_          =   index_of_best_solution + 1
																												snake_case_          =   neighborhood[index_of_best_solution]

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

														snake_case_          =   count + 1

							return best_solution_ever, best_cost





def  __lowerCamelCase     (			UpperCamelCase__=None				):







							'''simple docstring'''






							snake_case_          =   generate_neighbours(args.File				)

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

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

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


if __name__ == "__main__":
					_UpperCAmelCase		:       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())







def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






							return int((input_a, input_a).count(0				) != 0				)





def  __lowerCamelCase     (			):







							'''simple docstring'''






							assert nand_gate(0       ,							0				) == 1
							assert nand_gate(0       ,							1				) == 1
							assert nand_gate(1       ,							0				) == 1
							assert nand_gate(1       ,							1				) == 0


if __name__ == "__main__":
					print(nand_gate(0, 0))
					print(nand_gate(0, 1))
					print(nand_gate(1, 0))
					print(nand_gate(1, 1))




