





'''simple docstring'''


import inspect

import jax
import jax.lax as lax
import jax.numpy as jnp

from ..utils import add_start_docstrings
from ..utils.logging import get_logger


lowerCAmelCase					:     Dict												=get_logger(__name__)


lowerCAmelCase					:     List[str]												=r"\n    Args:\n        input_ids (`jnp.ndarray` of shape `(batch_size, sequence_length)`):\n            Indices of input sequence tokens in the vocabulary.\n\n            Indices can be obtained using [`PreTrainedTokenizer`]. See [`PreTrainedTokenizer.encode`] and\n            [`PreTrainedTokenizer.__call__`] for details.\n\n            [What are input IDs?](../glossary#input-ids)\n        scores (`jnp.ndarray` of shape `(batch_size, config.vocab_size)`):\n            Prediction scores of a language modeling head. These can be logits for each vocabulary when not using beam\n            search or log softmax for each vocabulary token when using beam search\n        kwargs (`Dict[str, Any]`, *optional*):\n            Additional logits processor specific kwargs.\n\n    Return:\n        `jnp.ndarray` of shape `(batch_size, config.vocab_size)`: The processed prediction scores.\n\n"
class       a_   :





     @add_start_docstrings(SCREAMING_SNAKE_CASE__						)
     def __call__( self		:					int	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray						):





        """simple docstring"""




        raise NotImplementedError(
            F'{self.__class__} is an abstract class. Only classes inheriting this class can be called.'						)







class       a_   :





     @add_start_docstrings(SCREAMING_SNAKE_CASE__						)
     def __call__( self		:					Optional[Any]	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray						):





        """simple docstring"""




        raise NotImplementedError(
            F'{self.__class__} is an abstract class. Only classes inheriting this class can be called.'						)







class       a_   (				__lowercase							):





     @add_start_docstrings(SCREAMING_SNAKE_CASE__						)
     def __call__( self		:					Union[str, Any]	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int	,      **lowercase		:					Union[str, Any]						):





        """simple docstring"""




        for processor in self:
           lowercase_			:Optional[int]    			= inspect.signature(processor.__call__						).parameters
           if len(SCREAMING_SNAKE_CASE__						) > 3:
              if not all(arg in kwargs for arg in list(function_args.keys()						)[2:]						):
                 raise ValueError(
                     F'Make sure that all the required parameters: {list(function_args.keys()						)} for '
                     F'{processor.__class__} are passed to the logits processor.'						)
              lowercase_			:int    			= processor(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__	,      **SCREAMING_SNAKE_CASE__						)
           else:
              lowercase_			:str    			= processor(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					int	,      lowercase		:					float						):





        """simple docstring"""




        if not isinstance(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						) or not (temperature > 0):
           raise ValueError(F'`temperature` has to be a strictly positive float, but is {temperature}'						)

        lowercase_			:int    			= temperature







     def __call__( self		:					List[str]	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:Optional[int]    			= scores / self.temperature
        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					Tuple	,      lowercase		:					float	,      lowercase		:					float = -float("Inf"						)	,      lowercase		:					int = 1						):





        """simple docstring"""




        if not isinstance(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						) or (top_p < 0 or top_p > 1.0):
           raise ValueError(F'`top_p` has to be a float > 0 and < 1, but is {top_p}'						)
        if not isinstance(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						) or (min_tokens_to_keep < 1):
           raise ValueError(F'`min_tokens_to_keep` has to be a positive integer, but is {min_tokens_to_keep}'						)

        lowercase_			:Optional[int]    			= top_p
        lowercase_			:List[Any]    			= filter_value
        lowercase_			:Union[str, Any]    			= min_tokens_to_keep







     def __call__( self		:					Tuple	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			,							lowercase_			:Optional[Any]    			= lax.top_k(SCREAMING_SNAKE_CASE__	,      scores.shape[-1]						)

        lowercase_			:List[Any]    			= jnp.full_like(SCREAMING_SNAKE_CASE__	,      self.filter_value						)
        lowercase_			:List[str]    			= jax.nn.softmax(SCREAMING_SNAKE_CASE__	,      axis=-1						).cumsum(axis=-1						)
        lowercase_			:Any    			= cumulative_probs < self.top_p

        # include the token that is higher than top_p as well
        lowercase_			:List[Any]    			= jnp.roll(SCREAMING_SNAKE_CASE__	,      1						)
        score_mask |= score_mask.at[:, 0].set(SCREAMING_SNAKE_CASE__						)

        # min tokens to keep
        lowercase_			:Any    			= score_mask.at[:, : self.min_tokens_to_keep].set(SCREAMING_SNAKE_CASE__						)

        lowercase_			:Optional[Any]    			= jnp.where(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
        lowercase_			:List[Any]    			= jax.lax.sort_key_val(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)[-1]

        return next_scores







class       a_   (				__lowercase							):





     def __init__( self		:					Optional[Any]	,      lowercase		:					int	,      lowercase		:					float = -float("Inf"						)	,      lowercase		:					int = 1						):





        """simple docstring"""




        if not isinstance(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						) or top_k <= 0:
           raise ValueError(F'`top_k` has to be a strictly positive integer, but is {top_k}'						)

        lowercase_			:Union[str, Any]    			= max(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
        lowercase_			:List[Any]    			= filter_value







     def __call__( self		:					Optional[Any]	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			,							lowercase_			:Union[str, Any]    			= scores.shape
        lowercase_			:List[Any]    			= jnp.full(batch_size * vocab_size	,      self.filter_value						)

        lowercase_			:Dict    			= min(self.top_k	,      scores.shape[-1]						)  # Safety check
        lowercase_			,							lowercase_			:List[str]    			= lax.top_k(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
        lowercase_			:Dict    			= jnp.broadcast_to((jnp.arange(SCREAMING_SNAKE_CASE__						) * vocab_size)[:, None]	,      (batch_size, topk)						).flatten()
        lowercase_			:List[Any]    			= topk_scores.flatten()
        lowercase_			:Tuple    			= topk_indices.flatten() + shift

        lowercase_			:str    			= next_scores_flat.at[topk_indices_flat].set(SCREAMING_SNAKE_CASE__						)
        lowercase_			:Any    			= next_scores_flat.reshape(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
        return next_scores







class       a_   (				__lowercase							):





     def __init__( self		:					Any	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:Optional[Any]    			= bos_token_id







     def __call__( self		:					Dict	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:Optional[Any]    			= jnp.full(scores.shape	,      -float("inf"						)						)

        lowercase_			:Any    			= 1 - jnp.bool_(cur_len - 1						)

        lowercase_			:Any    			= jnp.where(SCREAMING_SNAKE_CASE__	,      new_scores.at[:, self.bos_token_id].set(0						)	,      SCREAMING_SNAKE_CASE__						)

        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					Optional[Any]	,      lowercase		:					int	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:List[str]    			= max_length
        lowercase_			:Any    			= eos_token_id







     def __call__( self		:					List[str]	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:List[Any]    			= jnp.full(scores.shape	,      -float("inf"						)						)

        lowercase_			:Any    			= 1 - jnp.bool_(cur_len - self.max_length + 1						)

        lowercase_			:str    			= jnp.where(SCREAMING_SNAKE_CASE__	,      new_scores.at[:, self.eos_token_id].set(0						)	,      SCREAMING_SNAKE_CASE__						)

        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					str	,      lowercase		:					int	,      lowercase		:					int						):





        """simple docstring"""




        if not isinstance(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						) or min_length < 0:
           raise ValueError(F'`min_length` has to be a positive integer, but is {min_length}'						)

        if not isinstance(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						) or eos_token_id < 0:
           raise ValueError(F'`eos_token_id` has to be a positive integer, but is {eos_token_id}'						)

        lowercase_			:Optional[int]    			= min_length
        lowercase_			:List[Any]    			= eos_token_id







     def __call__( self		:					int	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:Tuple    			= 1 - jnp.clip(cur_len - self.min_length	,      0	,      1						)

        lowercase_			:Optional[int]    			= jnp.where(SCREAMING_SNAKE_CASE__	,      scores.at[:, self.eos_token_id].set(-float("inf"						)						)	,      SCREAMING_SNAKE_CASE__						)

        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					Any	,      lowercase		:					List[str]	,      lowercase		:					List[str]						):





        """simple docstring"""




        lowercase_			:Optional[int]    			= list(SCREAMING_SNAKE_CASE__						)
        lowercase_			:int    			= begin_index







     def __call__( self		:					Optional[Any]	,      lowercase		:					str	,      lowercase		:					int	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:str    			= 1 - jnp.bool_(cur_len - self.begin_index						)

        lowercase_			:Optional[Any]    			= jnp.where(SCREAMING_SNAKE_CASE__	,      scores.at[:, self.begin_suppress_tokens].set(-float("inf"						)						)	,      SCREAMING_SNAKE_CASE__						)

        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					Any	,      lowercase		:					list						):





        """simple docstring"""




        lowercase_			:Any    			= list(SCREAMING_SNAKE_CASE__						)







     def __call__( self		:					Dict	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:Tuple    			= scores.at[..., self.suppress_tokens].set(-float("inf"						)						)

        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					Tuple	,      lowercase		:					Tuple						):





        """simple docstring"""




        lowercase_			:Tuple    			= dict(SCREAMING_SNAKE_CASE__						)
        # Converts the dictionary of format {index: token} containing the tokens to be forced to an array, where the
        # index of the array corresponds to the index of the token to be forced, for XLA compatibility.
        # Indexes without forced tokens will have a negative value.
        lowercase_			:Optional[Any]    			= jnp.ones((max(force_token_map.keys()						) + 1)	,      dtype=jnp.intaa						) * -1
        for index, token in force_token_map.items():
           if token is not None:
              lowercase_			:Optional[Any]    			= force_token_array.at[index].set(SCREAMING_SNAKE_CASE__						)
        lowercase_			:Tuple    			= jnp.intaa(SCREAMING_SNAKE_CASE__						)







     def __call__( self		:					int	,      lowercase		:					jnp.ndarray	,      lowercase		:					jnp.ndarray	,      lowercase		:					int						):





        """simple docstring"""




        def _force_token(lowercase		:					Optional[int]						):
           lowercase_			:Optional[int]    			= scores.shape[0]
           lowercase_			:List[Any]    			= self.force_token_array[generation_idx]

           lowercase_			:str    			= jnp.ones_like(SCREAMING_SNAKE_CASE__	,      dtype=scores.dtype						) * -float("inf"						)
           lowercase_			:List[str]    			= jnp.zeros((batch_size, 1)	,      dtype=scores.dtype						)
           lowercase_			:Any    			= lax.dynamic_update_slice(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__	,      (0, current_token)						)
           return new_scores

        lowercase_			:str    			= lax.cond(
            cur_len >= self.force_token_array.shape[0]	,      lambda: scores	,      lambda: lax.cond(
                self.force_token_array[cur_len] >= 0	,      lambda: _force_token(SCREAMING_SNAKE_CASE__						)	,      lambda: scores	,      )	,      )
        return scores







class       a_   (				__lowercase							):





     def __init__( self		:					Union[str, Any]	,      lowercase		:					Optional[Any]	,      lowercase		:					int	,      lowercase		:					int						):





        """simple docstring"""




        lowercase_			:Optional[Any]    			= generate_config.eos_token_id
        lowercase_			:int    			= generate_config.no_timestamps_token_id
        lowercase_			:List[str]    			= generate_config.no_timestamps_token_id + 1

        lowercase_			:List[Any]    			= decoder_input_length + 1

        if generate_config.is_multilingual:
           # room for language token and task token
           self.begin_index += 2
        if hasattr(SCREAMING_SNAKE_CASE__	,      "max_initial_timestamp_index"						):
           lowercase_			:Optional[int]    			= generate_config.max_initial_timestamp_index
        else:
           lowercase_			:Optional[int]    			= model_config.vocab_size
        if self.max_initial_timestamp_index is None:
           lowercase_			:str    			= model_config.vocab_size







     def __call__( self		:					List[str]	,      lowercase		:					List[str]	,      lowercase		:					List[Any]	,      lowercase		:					List[Any]						):





        """simple docstring"""




        lowercase_			:Dict    			= scores.at[:, self.no_timestamps_token_id].set(-float("inf"						)						)

        def handle_pairs(lowercase		:					Union[str, Any]	,      lowercase		:					Tuple						):
           lowercase_			:Tuple    			= jnp.where((cur_len - self.begin_index) >= 1	,      SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
           lowercase_			:Optional[int]    			= jnp.where(
               input_ids_k[cur_len - 1] >= self.timestamp_begin	,      True and last_was_timestamp	,      SCREAMING_SNAKE_CASE__	,      )

           lowercase_			:Dict    			= jnp.where((cur_len - self.begin_index) < 2	,      SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
           lowercase_			:str    			= jnp.where(
               input_ids_k[cur_len - 2] >= self.timestamp_begin	,      SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__	,      )

           return jnp.where(
               SCREAMING_SNAKE_CASE__	,      jnp.where(
                   penultimate_was_timestamp > 0	,      scores_k.at[self.timestamp_begin :].set(-float("inf"						)						)	,      scores_k.at[: self.eos_token_id].set(-float("inf"						)						)	,      )	,      SCREAMING_SNAKE_CASE__	,      )

        lowercase_			:List[str]    			= jax.vmap(SCREAMING_SNAKE_CASE__						)(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)

        lowercase_			:int    			= jnp.where(cur_len == self.begin_index	,      SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)
        lowercase_			:str    			= jnp.where(
            self.max_initial_timestamp_index is not None	,      True and apply_max_initial_timestamp	,      SCREAMING_SNAKE_CASE__	,      )

        lowercase_			:Optional[int]    			= self.timestamp_begin + self.max_initial_timestamp_index

        lowercase_			:Any    			= jnp.where(
            SCREAMING_SNAKE_CASE__	,      scores.at[:, last_allowed + 1 :].set(-float("inf"						)						)	,      SCREAMING_SNAKE_CASE__	,      )

        # if sum of probability over timestamps is above any other token, sample timestamp
        lowercase_			:Optional[Any]    			= jax.nn.log_softmax(SCREAMING_SNAKE_CASE__	,      axis=-1						)

        def handle_cumulative_probs(lowercase		:					Dict	,      lowercase		:					str						):
           lowercase_			:Optional[int]    			= jax.nn.logsumexp(logprobs_k[self.timestamp_begin :]	,      axis=-1						)
           lowercase_			:str    			= jnp.max(logprobs_k[: self.timestamp_begin]						)
           return jnp.where(
               timestamp_logprob > max_text_token_logprob	,      scores_k.at[: self.timestamp_begin].set(-float("inf"						)						)	,      SCREAMING_SNAKE_CASE__	,      )

        lowercase_			:List[Any]    			= jax.vmap(SCREAMING_SNAKE_CASE__						)(SCREAMING_SNAKE_CASE__	,      SCREAMING_SNAKE_CASE__						)

        return scores




from __future__ import annotations

from sys import maxsize
from typing import Generic, TypeVar

SCREAMING_SNAKE_CASE__   :			List[Any]												=    TypeVar("T")




def  __magic_name__ (   __lowerCAmelCase	:						int							)			->   int:
				return (position - 1) // 2




def  __magic_name__ (   __lowerCAmelCase	:						int							)			->   int:
				return (2 * position) + 1




def  __magic_name__ (   __lowerCAmelCase	:						int							)			->   int:
				return (2 * position) + 2

class    lowerCAmelCase__     (	Generic[T]			):






		def __init__(		self		:							List[str]  )     ->							None:
						__lowerCamelCase    					=	[]
						__lowerCamelCase    					=	{}
						__lowerCamelCase    					=	0






		def __len__(		self		:							Optional[int]  )     ->							int:
						return self.elements






		def __repr__(		self		:							Optional[int]  )     ->							str:
						return str(self.heap  )






		def  __A       (		self		:							Union[str, Any]  )     ->							bool:
						# Check if the priority queue is empty
						return self.elements == 0






		def  __A       (		self		:							str							,			SCREAMING_SNAKE_CASE__		:							T							,			SCREAMING_SNAKE_CASE__		:							int  )     ->							None:
						# Add an element with given priority to the queue
						self.heap.append((elem, weight)  )
						__lowerCamelCase    					=	self.elements
						self.elements += 1
						self._bubble_up(SCREAMING_SNAKE_CASE__  )






		def  __A       (		self		:							Any  )     ->							T:
						# Remove and return the element with lowest weight (highest priority)
						if self.elements > 1:
										self._swap_nodes(0							,			self.elements - 1  )
						__lowerCamelCase					,    __lowerCamelCase    					=	self.heap.pop()
						del self.position_map[elem]
						self.elements -= 1
						if self.elements > 0:
										__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[0]
										self._bubble_down(SCREAMING_SNAKE_CASE__  )
						return elem






		def  __A       (		self		:							Dict							,			SCREAMING_SNAKE_CASE__		:							T							,			SCREAMING_SNAKE_CASE__		:							int  )     ->							None:
						# Update the weight of the given key
						__lowerCamelCase    					=	self.position_map[elem]
						__lowerCamelCase    					=	(elem, weight)
						if position > 0:
										__lowerCamelCase    					=	get_parent_position(SCREAMING_SNAKE_CASE__  )
										__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[parent_position]
										if parent_weight > weight:
														self._bubble_up(SCREAMING_SNAKE_CASE__  )
										else:
														self._bubble_down(SCREAMING_SNAKE_CASE__  )
						else:
										self._bubble_down(SCREAMING_SNAKE_CASE__  )






		def  __A       (		self		:							Optional[int]							,			SCREAMING_SNAKE_CASE__		:							T  )     ->							None:
						# Place a node at the proper position (upward movement) [to be used internally
						# only]
						__lowerCamelCase    					=	self.position_map[elem]
						if curr_pos == 0:
										return None
						__lowerCamelCase    					=	get_parent_position(SCREAMING_SNAKE_CASE__  )
						__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[curr_pos]
						__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[parent_position]
						if parent_weight > weight:
										self._swap_nodes(SCREAMING_SNAKE_CASE__							,			SCREAMING_SNAKE_CASE__  )
										return self._bubble_up(SCREAMING_SNAKE_CASE__  )
						return None






		def  __A       (		self		:							Optional[int]							,			SCREAMING_SNAKE_CASE__		:							T  )     ->							None:
						# Place a node at the proper position (downward movement) [to be used
						# internally only]
						__lowerCamelCase    					=	self.position_map[elem]
						__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[curr_pos]
						__lowerCamelCase    					=	get_child_left_position(SCREAMING_SNAKE_CASE__  )
						__lowerCamelCase    					=	get_child_right_position(SCREAMING_SNAKE_CASE__  )
						if child_left_position < self.elements and child_right_position < self.elements:
										__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[child_left_position]
										__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[child_right_position]
										if child_right_weight < child_left_weight and child_right_weight < weight:
														self._swap_nodes(SCREAMING_SNAKE_CASE__							,			SCREAMING_SNAKE_CASE__  )
														return self._bubble_down(SCREAMING_SNAKE_CASE__  )
						if child_left_position < self.elements:
										__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[child_left_position]
										if child_left_weight < weight:
														self._swap_nodes(SCREAMING_SNAKE_CASE__							,			SCREAMING_SNAKE_CASE__  )
														return self._bubble_down(SCREAMING_SNAKE_CASE__  )
						else:
										return None
						if child_right_position < self.elements:
										__lowerCamelCase					,    __lowerCamelCase    					=	self.heap[child_right_position]
										if child_right_weight < weight:
														self._swap_nodes(SCREAMING_SNAKE_CASE__							,			SCREAMING_SNAKE_CASE__  )
														return self._bubble_down(SCREAMING_SNAKE_CASE__  )
						return None







		def  __A       (		self		:							List[Any]							,			SCREAMING_SNAKE_CASE__		:							int							,			SCREAMING_SNAKE_CASE__		:							int  )     ->							None:
						# Swap the nodes at the given positions
						__lowerCamelCase    					=	self.heap[nodea_pos][0]
						__lowerCamelCase    					=	self.heap[nodea_pos][0]
						__lowerCamelCase					,    __lowerCamelCase    					=	(
						    self.heap[nodea_pos],
						    self.heap[nodea_pos],
						)
						__lowerCamelCase    					=	nodea_pos
						__lowerCamelCase    					=	nodea_pos





class    lowerCAmelCase__     (	Generic[T]			):






		def __init__(		self		:							Tuple  )     ->							None:
						__lowerCamelCase    					=	{}
						__lowerCamelCase    					=	0






		def __repr__(		self		:							Optional[int]  )     ->							str:
						return str(self.connections  )






		def __len__(		self		:							List[str]  )     ->							int:
						return self.nodes






		def  __A       (		self		:							List[str]							,			SCREAMING_SNAKE_CASE__		:							T  )     ->							None:
						# Add a node in the graph if it is not in the graph
						if node not in self.connections:
										__lowerCamelCase    					=	{}
										self.nodes += 1







		def  __A       (		self		:							Dict							,			SCREAMING_SNAKE_CASE__		:							T							,			SCREAMING_SNAKE_CASE__		:							T							,			SCREAMING_SNAKE_CASE__		:							int  )     ->							None:
						# Add an edge between 2 nodes in the graph
						self.add_node(SCREAMING_SNAKE_CASE__  )
						self.add_node(SCREAMING_SNAKE_CASE__  )
						__lowerCamelCase    					=	weight
						__lowerCamelCase    					=	weight





def  __magic_name__ (   __lowerCAmelCase	:						GraphUndirectedWeighted[T]		,  )			->   tuple[dict[T, int], dict[T, T | None]]:
				__lowerCamelCase    					=	{node: maxsize for node in graph.connections}
				__lowerCamelCase    					=	{node: None for node in graph.connections}

				__lowerCamelCase    					=	MinPriorityQueue()
				for node, weight in dist.items():
								priority_queue.push(__lowerCAmelCase		,  __lowerCAmelCase							)

				if priority_queue.is_empty():
								return dist, parent

				# initialization
				__lowerCamelCase    					=	priority_queue.extract_min()
				__lowerCamelCase    					=	0
				for neighbour in graph.connections[node]:
								if dist[neighbour] > dist[node] + graph.connections[node][neighbour]:
												__lowerCamelCase    					=	dist[node] + graph.connections[node][neighbour]
												priority_queue.update_key(__lowerCAmelCase		,  dist[neighbour]							)
												__lowerCamelCase    					=	node

    # running prim's algorithm
				while not priority_queue.is_empty():
								__lowerCamelCase    					=	priority_queue.extract_min()
								for neighbour in graph.connections[node]:
												if dist[neighbour] > dist[node] + graph.connections[node][neighbour]:
																__lowerCamelCase    					=	dist[node] + graph.connections[node][neighbour]
																priority_queue.update_key(__lowerCAmelCase		,  dist[neighbour]							)
																__lowerCamelCase    					=	node
				return dist, parent



