


import argparse
import copy




def     UpperCamelCase    (      _a		)					->							Optional[Any]:
     '''simple docstring'''





     lowercase_       :int     =       {}

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

     return dict_of_neighbours




def     UpperCamelCase    (      _a       ,		_a		)					->							Dict:
     '''simple docstring'''





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

     lowercase_       :Union[str, Any]     =       []

     lowercase_       :List[Any]     =       start_node

     lowercase_       :Optional[Any]     =       0
     while visiting not in first_solution:
          lowercase_       :Optional[int]     =       1_0_0_0_0
          for k in dict_of_neighbours[visiting]:
               if int(k[1]		) < int(_a		) and k[0] not in first_solution:
                    lowercase_       :List[Any]     =       k[1]
                    lowercase_       :Tuple     =       k[0]

          first_solution.append(_a		)
          lowercase_       :Optional[int]     =       distance_of_first_solution + int(_a		)
          lowercase_       :List[Any]     =       best_node

     first_solution.append(_a		)

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

     lowercase_       :List[Any]     =       (
         distance_of_first_solution
         + int(dict_of_neighbours[first_solution[-2]][position][1]		)
         - 1_0_0_0_0
     )
     return first_solution, distance_of_first_solution




def     UpperCamelCase    (      _a       ,		_a		)					->							List[Any]:
     '''simple docstring'''





     lowercase_       :int     =       []

     for n in solution[1:-1]:
          lowercase_       :Any     =       solution.index(_a		)
          for kn in solution[1:-1]:
               lowercase_       :List[str]     =       solution.index(_a		)
               if n == kn:
                    continue

               lowercase_       :Optional[Any]     =       copy.deepcopy(_a		)
               lowercase_       :Optional[int]     =       kn
               lowercase_       :Optional[int]     =       n

               lowercase_       :Dict     =       0

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

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

     lowercase_       :Union[str, Any]     =       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     UpperCamelCase    (      _a       ,		_a       ,		_a       ,		_a       ,		_a		)					->							Tuple:
     '''simple docstring'''





     lowercase_       :Any     =       1
     lowercase_       :Dict     =       first_solution
     lowercase_       :List[Any]     =       []
     lowercase_       :Any     =       distance_of_first_solution
     lowercase_       :Dict     =       solution

     while count <= iters:
          lowercase_       :Any     =       find_neighborhood(_a       ,		_a		)
          lowercase_       :Optional[Any]     =       0
          lowercase_       :Optional[int]     =       neighborhood[index_of_best_solution]
          lowercase_       :List[Any]     =       len(_a		) - 1

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

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

          lowercase_       :str     =       count + 1

     return best_solution_ever, best_cost




def     UpperCamelCase    (      _a=None		)					->							List[str]:
     '''simple docstring'''





     lowercase_       :Dict     =       generate_neighbours(args.File		)

     lowercase_    ,      lowercase_       :str     =       generate_first_solution(
         args.File       ,		_a		)

     lowercase_    ,      lowercase_       :Union[str, Any]     =       tabu_search(
         _a       ,		_a       ,		_a       ,		args.Iterations       ,		args.Size       ,		)

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


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





import math

SCREAMING_SNAKE_CASE       :		List[str]         =				10
SCREAMING_SNAKE_CASE       :		Dict         =				7
SCREAMING_SNAKE_CASE       :		int         =				BALLS_PER_COLOUR * NUM_COLOURS




def     UpperCamelCase    (      _a = 2_0		)					->							str:
     '''simple docstring'''





     lowercase_       :List[str]     =       math.comb(_a       ,		_a		)
     lowercase_       :Tuple     =       math.comb(NUM_BALLS - BALLS_PER_COLOUR       ,		_a		)

     lowercase_       :Dict     =       NUM_COLOURS * (1 - missing_colour / total)

     return f"{result:.9f}"


if __name__ == "__main__":
   print(solution(20))

