
import math
import sys

class 		lowercase_							:

 def __init__(   self  ):




        """simple docstring"""


        UpperCamelCase_											=							0
        UpperCamelCase_											=							[]
        UpperCamelCase_											=							{}  # To store the pos of node in array

 def lowerCamelCase_					(   self  ):




        """simple docstring"""


        return self.cur_size == 0

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        UpperCamelCase_											=							self.left(__UpperCamelCase  )
        UpperCamelCase_											=							self.right(__UpperCamelCase  )
        if lc < self.cur_size and self.array(__UpperCamelCase  )[0] < self.array(__UpperCamelCase  )[0]:
               UpperCamelCase_											=							lc
        else:
               UpperCamelCase_											=							idx
        if rc < self.cur_size and self.array(__UpperCamelCase  )[0] < self.array(__UpperCamelCase  )[0]:
               UpperCamelCase_											=							rc
        if smallest != idx:
               self.swap(__UpperCamelCase  ,						__UpperCamelCase  )
               self.min_heapify(__UpperCamelCase  )

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        UpperCamelCase_											=							self.cur_size
        self.cur_size += 1
        self.array.append((sys.maxsize, tup[1])  )
        self.decrease_key((sys.maxsize, tup[1])  ,						tup[0]  )

 def lowerCamelCase_					(   self  ):




        """simple docstring"""


        UpperCamelCase_											=							self.array[0][1]
        UpperCamelCase_											=							self.array[self.cur_size - 1]
        self.cur_size -= 1
        self.min_heapify(1  )
        del self.pos[min_node]
        return min_node

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        return 2 * i + 1

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        return 2 * i + 2

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        return math.floor(i / 2  )

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ,						__UpperCamelCase  ):




        """simple docstring"""


        UpperCamelCase_											=							j
        UpperCamelCase_											=							i
        UpperCamelCase_											=							self.array[i]
        UpperCamelCase_											=							self.array[j]
        UpperCamelCase_											=							temp

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ,						__UpperCamelCase  ):




        """simple docstring"""


        UpperCamelCase_											=							self.pos[tup[1]]
        # assuming the new_d is atmost old_d
        UpperCamelCase_											=							(new_d, tup[1])
        while idx > 0 and self.array[self.par(__UpperCamelCase  )][0] > self.array[idx][0]:
               self.swap(__UpperCamelCase  ,						self.par(__UpperCamelCase  )  )
               UpperCamelCase_											=							self.par(__UpperCamelCase  )



class 		lowercase_							:

 def __init__(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        UpperCamelCase_											=							{}  # To store graph: u -> (v,w)
        UpperCamelCase_											=							num  # Number of nodes in graph
        # To store the distance from source vertex
        UpperCamelCase_											=							[0] * self.num_nodes
        UpperCamelCase_											=							[-1] * self.num_nodes  # To store the path

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ,						__UpperCamelCase  ,						__UpperCamelCase  ):




        """simple docstring"""


        if u in self.adjList:
               self.adjList[u].append((v, w)  )
        else:
               UpperCamelCase_											=							[(v, w)]

        # Assuming undirected graph
        if v in self.adjList:
               self.adjList[v].append((u, w)  )
        else:
               UpperCamelCase_											=							[(u, w)]

 def lowerCamelCase_					(   self  ):




        """simple docstring"""


        for u in self.adjList:
               print(__UpperCamelCase  ,						"""->"""  ,						""" -> """.join(str(f'''{v}({w})'''  ) for v, w in self.adjList[u]  )  )

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        UpperCamelCase_											=							[-1] * self.num_nodes
        # src is the source node
        UpperCamelCase_											=							0
        UpperCamelCase_											=							PriorityQueue()
        q.insert((0, src)  )  # (dist from src, node)
        for u in self.adjList:
               if u != src:
                      UpperCamelCase_											=							sys.maxsize  # Infinity
                      UpperCamelCase_											=							-1

        while not q.is_empty():
               UpperCamelCase_											=							q.extract_min()  # Returns node with the min dist from source
               # Update the distance of all the neighbours of u and
               # if their prev dist was INFINITY then push them in Q
               for v, w in self.adjList[u]:
                      UpperCamelCase_											=							self.dist[u] + w
                      if self.dist[v] > new_dist:
                             if self.dist[v] == sys.maxsize:
                                    q.insert((new_dist, v)  )
                             else:
                                    q.decrease_key((self.dist[v], v)  ,						__UpperCamelCase  )
                             UpperCamelCase_											=							new_dist
                             UpperCamelCase_											=							u

        # Show the shortest distances from src
        self.show_distances(__UpperCamelCase  )

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ):




        """simple docstring"""


        print(f'''Distance from node: {src}'''  )
        for u in range(self.num_nodes  ):
               print(f'''Node {u} has distance: {self.dist[u]}'''  )

 def lowerCamelCase_					(   self  ,						__UpperCamelCase  ,						__UpperCamelCase  ):




        """simple docstring"""


        UpperCamelCase_											=							[]
        UpperCamelCase_											=							0
        UpperCamelCase_											=							dest
        # Backtracking from dest to src
        while self.par[temp] != -1:
               path.append(__UpperCamelCase  )
               if temp != src:
                      for v, w in self.adjList[temp]:
                             if v == self.par[temp]:
                                    cost += w
                                    break
               UpperCamelCase_											=							self.par[temp]
        path.append(__UpperCamelCase  )
        path.reverse()

        print(f'''----Path to reach {dest} from {src}----'''  )
        for u in path:
               print(f'''{u}'''  ,						end=""" """  )
               if u != dest:
                      print("""-> """  ,						end=""""""  )

        print("""\nTotal cost of path: """  ,						__UpperCamelCase  )


if __name__ == "__main__":
      _A							=       Graph(9)
      graph.add_edge(0, 1, 4)
      graph.add_edge(0, 7, 8)
      graph.add_edge(1, 2, 8)
      graph.add_edge(1, 7, 11)
      graph.add_edge(2, 3, 7)
      graph.add_edge(2, 8, 2)
      graph.add_edge(2, 5, 4)
      graph.add_edge(3, 4, 9)
      graph.add_edge(3, 5, 14)
      graph.add_edge(4, 5, 10)
      graph.add_edge(5, 6, 2)
      graph.add_edge(6, 7, 1)
      graph.add_edge(6, 8, 6)
      graph.add_edge(7, 8, 7)
      graph.show_graph()
      graph.dijkstra(0)
      graph.show_path(0, 4)

# OUTPUT
# 0 -> 1(4) -> 7(8)
# 1 -> 0(4) -> 2(8) -> 7(11)
# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7)
# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4)
# 3 -> 2(7) -> 4(9) -> 5(14)
# 8 -> 2(2) -> 6(6) -> 7(7)
# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2)
# 4 -> 3(9) -> 5(10)
# 6 -> 5(2) -> 7(1) -> 8(6)
# Distance from node: 0
# Node 0 has distance: 0
# Node 1 has distance: 4
# Node 2 has distance: 12
# Node 3 has distance: 19
# Node 4 has distance: 21
# Node 5 has distance: 11
# Node 6 has distance: 9
# Node 7 has distance: 8
# Node 8 has distance: 14
# ----Path to reach 4 from 0----
# 0 -> 7 -> 6 -> 5 -> 4
# Total cost of path:  21





import argparse
import os


_A							=       {
    '''pytorch''': {
        '''1.13''': {
            '''torch''': '''1.13.1''',
            '''torchvision''': '''0.14.1''',
            '''torchaudio''': '''0.13.1''',
            '''python''': 3.9,
            '''cuda''': '''cu116''',
            '''install''': (
                '''python3 -m pip install --no-cache-dir -U torch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1'''
                ''' --extra-index-url https://download.pytorch.org/whl/cu116'''
            ),
            '''base_image''': '''nvidia/cuda:11.6.2-cudnn8-devel-ubuntu20.04''',
        },
        '''1.12''': {
            '''torch''': '''1.12.1''',
            '''torchvision''': '''0.13.1''',
            '''torchaudio''': '''0.12.1''',
            '''python''': 3.9,
            '''cuda''': '''cu113''',
            '''install''': (
                '''python3 -m pip install --no-cache-dir -U torch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1'''
                ''' --extra-index-url https://download.pytorch.org/whl/cu113'''
            ),
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''1.11''': {
            '''torch''': '''1.11.0''',
            '''torchvision''': '''0.12.0''',
            '''torchaudio''': '''0.11.0''',
            '''python''': 3.9,
            '''cuda''': '''cu113''',
            '''install''': (
                '''python3 -m pip install --no-cache-dir -U torch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0'''
                ''' --extra-index-url https://download.pytorch.org/whl/cu113'''
            ),
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''1.10''': {
            '''torch''': '''1.10.2''',
            '''torchvision''': '''0.11.3''',
            '''torchaudio''': '''0.10.2''',
            '''python''': 3.9,
            '''cuda''': '''cu113''',
            '''install''': (
                '''python3 -m pip install --no-cache-dir -U torch==1.10.2 torchvision==0.11.3 torchaudio==0.10.2'''
                ''' --extra-index-url https://download.pytorch.org/whl/cu113'''
            ),
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        # torchaudio < 0.10 has no CUDA-enabled binary distributions
        '''1.9''': {
            '''torch''': '''1.9.1''',
            '''torchvision''': '''0.10.1''',
            '''torchaudio''': '''0.9.1''',
            '''python''': 3.9,
            '''cuda''': '''cu111''',
            '''install''': (
                '''python3 -m pip install --no-cache-dir -U torch==1.9.1 torchvision==0.10.1 torchaudio==0.9.1'''
                ''' --extra-index-url https://download.pytorch.org/whl/cu111'''
            ),
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
    },
    '''tensorflow''': {
        '''2.11''': {
            '''tensorflow''': '''2.11.1''',
            '''install''': '''python3 -m pip install --no-cache-dir -U tensorflow==2.11.1''',
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''2.10''': {
            '''tensorflow''': '''2.10.1''',
            '''install''': '''python3 -m pip install --no-cache-dir -U tensorflow==2.10.1''',
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''2.9''': {
            '''tensorflow''': '''2.9.3''',
            '''install''': '''python3 -m pip install --no-cache-dir -U tensorflow==2.9.3''',
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''2.8''': {
            '''tensorflow''': '''2.8.2''',
            '''install''': '''python3 -m pip install --no-cache-dir -U tensorflow==2.8.2''',
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''2.7''': {
            '''tensorflow''': '''2.7.3''',
            '''install''': '''python3 -m pip install --no-cache-dir -U tensorflow==2.7.3''',
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''2.6''': {
            '''tensorflow''': '''2.6.5''',
            '''install''': '''python3 -m pip install --no-cache-dir -U tensorflow==2.6.5''',
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
        '''2.5''': {
            '''tensorflow''': '''2.5.3''',
            '''install''': '''python3 -m pip install --no-cache-dir -U tensorflow==2.5.3''',
            '''base_image''': '''nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04''',
        },
    },
}


if __name__ == "__main__":
      _A							=       argparse.ArgumentParser('''Choose the framework and version to install''')
      parser.add_argument(
          '''--framework''', help='''The framework to install. Should be `torch` or `tensorflow`''', type=str, required=True
      )
      parser.add_argument('''--version''', help='''The version of the framework to install.''', type=str, required=True)
      _A							=       parser.parse_args()

      _A							=       past_versions_testing[args.framework][args.version]

      os.system(F'''echo "export INSTALL_CMD=\'{info['install']}\'" >> ~/.profile''')
      print(F'''echo "export INSTALL_CMD=\'{info['install']}\'" >> ~/.profile''')

      _A							=       ''''''
      if args.framework == "pytorch":
            _A							=       info['''cuda''']
      os.system(F'''echo \"export CUDA=\'{cuda}\'\" >> ~/.profile''')
      print(F'''echo \"export CUDA=\'{cuda}\'\" >> ~/.profile''')



