

import inspect
from typing import Callable, List, Optional, Set, Tuple, Union

import torch
from packaging import version
from safetensors.torch import storage_ptr, storage_size
from torch import nn

from .utils import logging


__UpperCAmelCase      = [nn.LayerNorm]

__UpperCAmelCase      = logging.get_logger(__name__)

__UpperCAmelCase      = version.parse(version.parse(torch.__version__).base_version)

__UpperCAmelCase      = parsed_torch_version_base >= version.parse("""2.0""")
__UpperCAmelCase      = parsed_torch_version_base >= version.parse("""1.12""")
__UpperCAmelCase      = parsed_torch_version_base >= version.parse("""1.11""")
__UpperCAmelCase      = parsed_torch_version_base < version.parse("""1.11""")





def 	snake_case_      (__A     :						int					,   __A     :						Dict					,   __A     :						str					,   __A     :						List[str]					,   self     :						Any     )			->	Any:
   from torch import _softmax_backward_data

   if is_torch_less_than_1_11:
      return _softmax_backward_data(__A					,   __A					,   parent.dim					,   self     )
   else:
      return _softmax_backward_data(__A					,   __A					,   parent.dim					,   self.dtype     )





def 	snake_case_      (__A     :						nn.Linear					,   __A     :						torch.LongTensor					,   __A     :						int = 0     )			->	nn.Linear:
   __lowerCAmelCase  :			str					    =						index.to(layer.weight.device     )
   __lowerCAmelCase  :			Tuple					    =						layer.weight.index_select(__A					,   __A     ).clone().detach()
   if layer.bias is not None:
      if dim == 1:
         __lowerCAmelCase  :			str					    =						layer.bias.clone().detach()
      else:
         __lowerCAmelCase  :			Any					    =						layer.bias[index].clone().detach()
   __lowerCAmelCase  :			Optional[Any]					    =						list(layer.weight.size()     )
   __lowerCAmelCase  :			int					    =						len(__A     )
   __lowerCAmelCase  :			Optional[int]					    =						nn.Linear(new_size[1]					,   new_size[0]					,   bias=layer.bias is not None     ).to(layer.weight.device     )
   __lowerCAmelCase  :			Optional[int]					    =						False
   new_layer.weight.copy_(W.contiguous()     )
   __lowerCAmelCase  :			List[str]					    =						True
   if layer.bias is not None:
      __lowerCAmelCase  :			Any					    =						False
      new_layer.bias.copy_(b.contiguous()     )
      __lowerCAmelCase  :			Dict					    =						True
   return new_layer



class SCREAMING_SNAKE_CASE	(  nn.Module ):
  """simple docstring"""






  def __init__(			self :    str       ,							lowerCAmelCase :    Tuple       ,							lowerCAmelCase :    Optional[int]    )							->	List[str]:






     """simple docstring"""







     super().__init__()
     __lowerCAmelCase  :			Any					    =						nf
     __lowerCAmelCase  :			List[str]					    =						nn.Parameter(torch.empty(lowerCAmelCase       ,							lowerCAmelCase    )    )
     __lowerCAmelCase  :			Optional[Any]					    =						nn.Parameter(torch.zeros(lowerCAmelCase    )    )
     nn.init.normal_(self.weight       ,							std=0.02    )







  def        SCREAMING_SNAKE_CASE    (			self :    int       ,							lowerCAmelCase :    str    )							->	List[str]:






     """simple docstring"""







     __lowerCAmelCase  :			Optional[Any]					    =						x.size()[:-1] + (self.nf,)
     __lowerCAmelCase  :			Dict					    =						torch.addmm(self.bias       ,							x.view(-1       ,							x.size(-1    )    )       ,							self.weight    )
     __lowerCAmelCase  :			str					    =						x.view(lowerCAmelCase    )
     return x






def 	snake_case_      (__A     :						ConvaD					,   __A     :						torch.LongTensor					,   __A     :						int = 1     )			->	ConvaD:
   __lowerCAmelCase  :			List[str]					    =						index.to(layer.weight.device     )
   __lowerCAmelCase  :			Optional[Any]					    =						layer.weight.index_select(__A					,   __A     ).clone().detach()
   if dim == 0:
      __lowerCAmelCase  :			Any					    =						layer.bias.clone().detach()
   else:
      __lowerCAmelCase  :			int					    =						layer.bias[index].clone().detach()
   __lowerCAmelCase  :			Any					    =						list(layer.weight.size()     )
   __lowerCAmelCase  :			List[str]					    =						len(__A     )
   __lowerCAmelCase  :			Any					    =						ConvaD(new_size[1]					,   new_size[0]     ).to(layer.weight.device     )
   __lowerCAmelCase  :			List[str]					    =						False
   new_layer.weight.copy_(W.contiguous()     )
   __lowerCAmelCase  :			List[Any]					    =						True
   __lowerCAmelCase  :			Dict					    =						False
   new_layer.bias.copy_(b.contiguous()     )
   __lowerCAmelCase  :			Union[str, Any]					    =						True
   return new_layer





def 	snake_case_      (__A     :						Union[nn.Linear, ConvaD]					,   __A     :						torch.LongTensor					,   __A     :						Optional[int] = None     )			->	Union[nn.Linear, ConvaD]:
   if isinstance(__A					,   nn.Linear     ):
      return prune_linear_layer(__A					,   __A					,   dim=0 if dim is None else dim     )
   elif isinstance(__A					,   __A     ):
      return prune_convad_layer(__A					,   __A					,   dim=1 if dim is None else dim     )
   else:
      raise ValueError(f'''Can\'t prune layer of class {layer.__class__}'''     )





def 	snake_case_      (__A     :						Callable[..., torch.Tensor]					,   __A     :						int					,   __A     :						int					,   *__A     :						str     )			->	torch.Tensor:
   assert len(__A     ) > 0, f'''{input_tensors} has to be a tuple/list of tensors'''

   # inspect.signature exist since python 3.5 and is a python method -> no problem with backward compatibility
   __lowerCAmelCase  :			Any					    =						len(inspect.signature(__A     ).parameters     )
   if num_args_in_forward_chunk_fn != len(__A     ):
      raise ValueError(
          f'''forward_chunk_fn expects {num_args_in_forward_chunk_fn} arguments, but only {len(__A     )} input '''
          """tensors are given"""     )

   if chunk_size > 0:
      __lowerCAmelCase  :			str					    =						input_tensors[0].shape[chunk_dim]
      for input_tensor in input_tensors:
         if input_tensor.shape[chunk_dim] != tensor_shape:
            raise ValueError(
                f'''All input tenors have to be of the same shape: {tensor_shape}, '''
                f'''found shape {input_tensor.shape[chunk_dim]}'''     )

      if input_tensors[0].shape[chunk_dim] % chunk_size != 0:
         raise ValueError(
             f'''The dimension to be chunked {input_tensors[0].shape[chunk_dim]} has to be a multiple of the chunk '''
             f'''size {chunk_size}'''     )

      __lowerCAmelCase  :			Optional[int]					    =						input_tensors[0].shape[chunk_dim] // chunk_size

      # chunk input tensor into tuples
      __lowerCAmelCase  :			List[Any]					    =						tuple(input_tensor.chunk(__A					,   dim=__A     ) for input_tensor in input_tensors     )
      # apply forward fn to every tuple
      __lowerCAmelCase  :			str					    =						tuple(forward_fn(*__A     ) for input_tensors_chunk in zip(*__A     )     )
      # concatenate output at same dimension
      return torch.cat(__A					,   dim=__A     )

   return forward_fn(*__A     )





def 	snake_case_      (__A     :						List[int]					,   __A     :						int					,   __A     :						int					,   __A     :						Set[int]     )			->	Tuple[Set[int], torch.LongTensor]:
   __lowerCAmelCase  :			Any					    =						torch.ones(__A					,   __A     )
   __lowerCAmelCase  :			Dict					    =						set(__A     ) - already_pruned_heads  # Convert to set and remove already pruned heads
   for head in heads:
      # Compute how many pruned heads are before the head and move the index accordingly
      __lowerCAmelCase  :			Optional[Any]					    =						head - sum(1 if h < head else 0 for h in already_pruned_heads     )
      __lowerCAmelCase  :			List[str]					    =						0
   __lowerCAmelCase  :			Union[str, Any]					    =						mask.view(-1     ).contiguous().eq(1     )
   __lowerCAmelCase  :			torch.LongTensor					    =						torch.arange(len(__A     )     )[mask].long()
   return heads, index





def 	snake_case_      (*__A     :						Union[torch.Tensor, List[torch.Tensor]]					,   __A     :						Optional[str] = None     )			->	Tuple[torch.Tensor, ...]:
   return torch.meshgrid(*__A					,   indexing=__A     )





def 	snake_case_      (__A     :						torch.Tensor     )			->	Tuple[torch.device, int, int]:
   return tensor.device, storage_ptr(__A     ), storage_size(__A     )





from __future__ import annotations

import os



class SCREAMING_SNAKE_CASE	:
  """simple docstring"""






  lowerCamelCase    :			Union[str, Any]						      =(
      "High card",
      "One pair",
      "Two pairs",
      "Three of a kind",
      "Straight",
      "Flush",
      "Full house",
      "Four of a kind",
      "Straight flush",
      "Royal flush",
  )

  lowerCamelCase    :			Dict						      =(
      "",  # placeholder as tuples are zero-indexed
      "One",
      "Two",
      "Three",
      "Four",
      "Five",
      "Six",
      "Seven",
      "Eight",
      "Nine",
      "Ten",
      "Jack",
      "Queen",
      "King",
      "Ace",
  )







  def __init__(			self :    Tuple       ,							lowerCAmelCase :    str    )							->	None:






     """simple docstring"""







     if not isinstance(lowerCAmelCase       ,							lowerCAmelCase    ):
        __lowerCAmelCase  :			Tuple					    =						f'''Hand should be of type \'str\': {hand!r}'''
        raise TypeError(lowerCAmelCase    )
     # split removes duplicate whitespaces so no need of strip
     if len(hand.split(""" """    )    ) != 5:
        __lowerCAmelCase  :			Any					    =						f'''Hand should contain only 5 cards: {hand!r}'''
        raise ValueError(lowerCAmelCase    )
     __lowerCAmelCase  :			int					    =						hand
     __lowerCAmelCase  :			Any					    =						0
     __lowerCAmelCase  :			str					    =						0
     __lowerCAmelCase    ,__lowerCAmelCase  :			List[str]					    =						self._internal_state()
     __lowerCAmelCase  :			int					    =						self._get_hand_type()
     __lowerCAmelCase  :			Any					    =						self._card_values[0]







  @property
  def        SCREAMING_SNAKE_CASE    (			self :    Union[str, Any]    )							->	Optional[int]:






     """simple docstring"""







     return self._hand







  def        SCREAMING_SNAKE_CASE    (			self :    Dict       ,							lowerCAmelCase :    PokerHand    )							->	str:






     """simple docstring"""







     if self._hand_type > other._hand_type:
        return "Win"
     elif self._hand_type < other._hand_type:
        return "Loss"
     elif self._first_pair == other._first_pair:
        if self._second_pair == other._second_pair:
           return self._compare_cards(lowerCAmelCase    )
        else:
           return "Win" if self._second_pair > other._second_pair else "Loss"
     return "Win" if self._first_pair > other._first_pair else "Loss"







  def        SCREAMING_SNAKE_CASE    (			self :    int    )							->	str:






     """simple docstring"""







     __lowerCAmelCase  :			Optional[int]					    =						PokerHand._HAND_NAME[self._hand_type - 14]
     __lowerCAmelCase  :			str					    =						PokerHand._CARD_NAME[self._high_card]
     __lowerCAmelCase  :			Optional[Any]					    =						PokerHand._CARD_NAME[self._first_pair]
     __lowerCAmelCase  :			Any					    =						PokerHand._CARD_NAME[self._second_pair]
     if self._hand_type in [22, 19, 18]:
        return name + f''', {high}-high'''
     elif self._hand_type in [21, 17, 15]:
        return name + f''', {paira}s'''
     elif self._hand_type in [20, 16]:
        __lowerCAmelCase  :			List[str]					    =						"""over""" if self._hand_type == 20 else """and"""
        return name + f''', {paira}s {join} {paira}s'''
     elif self._hand_type == 23:
        return name
     else:
        return name + f''', {high}'''







  def        SCREAMING_SNAKE_CASE    (			self :    Dict       ,							lowerCAmelCase :    PokerHand    )							->	str:






     """simple docstring"""







     for index, card_value in enumerate(self._card_values    ):
        if card_value != other._card_values[index]:
           return "Win" if card_value > other._card_values[index] else "Loss"
     return "Tie"







  def        SCREAMING_SNAKE_CASE    (			self :    Optional[int]    )							->	int:






     """simple docstring"""







     if self._is_flush():
        if self._is_five_high_straight() or self._is_straight():
           return 23 if sum(self._card_values    ) == 60 else 22
        return 19
     elif self._is_five_high_straight() or self._is_straight():
        return 18
     return 14 + self._is_same_kind()







  def        SCREAMING_SNAKE_CASE    (			self :    List[Any]    )							->	bool:






     """simple docstring"""







     return len(self._card_suit    ) == 1







  def        SCREAMING_SNAKE_CASE    (			self :    List[str]    )							->	bool:






     """simple docstring"""







     if sorted(self._card_values    ) == [2, 3, 4, 5, 14]:
        if self._card_values[0] == 14:
           # Remember, our list is sorted in reverse order
           __lowerCAmelCase  :			Optional[Any]					    =						self._card_values.pop(0    )
           self._card_values.append(lowerCAmelCase    )
        return True
     return False







  def        SCREAMING_SNAKE_CASE    (			self :    List[str]    )							->	bool:






     """simple docstring"""







     for i in range(4    ):
        if self._card_values[i] - self._card_values[i + 1] != 1:
           return False
     return True







  def        SCREAMING_SNAKE_CASE    (			self :    Optional[int]    )							->	int:






     """simple docstring"""







     __lowerCAmelCase  :			str					    =						0
     for i in range(4    ):
        # Compare two cards at a time, if they are same increase 'kind',
        # add the value of the card to val1, if it is repeating again we
        # will add 2 to 'kind' as there are now 3 cards with same value.
        # If we get card of different value than val1, we will do the same
        # thing with val2
        if self._card_values[i] == self._card_values[i + 1]:
           if not vala:
              __lowerCAmelCase  :			List[str]					    =						self._card_values[i]
              kind += 1
           elif vala == self._card_values[i]:
              kind += 2
           elif not vala:
              __lowerCAmelCase  :			Optional[Any]					    =						self._card_values[i]
              kind += 1
           elif vala == self._card_values[i]:
              kind += 2
        # For consistency in hand type (look at note in _get_hand_type function)
     __lowerCAmelCase  :			List[Any]					    =						kind + 2 if kind in [4, 5] else kind
     # first meaning first pair to compare in 'compare_with'
     __lowerCAmelCase  :			Optional[int]					    =						max(lowerCAmelCase       ,							lowerCAmelCase    )
     __lowerCAmelCase  :			Optional[Any]					    =						min(lowerCAmelCase       ,							lowerCAmelCase    )
     # If it's full house (three count pair + two count pair), make sure
     # first pair is three count and if not then switch them both.
     if kind == 6 and self._card_values.count(lowerCAmelCase    ) != 3:
        __lowerCAmelCase    ,__lowerCAmelCase  :			Tuple					    =						second, first
     __lowerCAmelCase  :			Optional[Any]					    =						first
     __lowerCAmelCase  :			Union[str, Any]					    =						second
     return kind







  def        SCREAMING_SNAKE_CASE    (			self :    List[Any]    )							->	tuple[list[int], set[str]]:






     """simple docstring"""







     __lowerCAmelCase  :			dict					    =						{"T": "10", "J": "11", "Q": "12", "K": "13", "A": "14"}
     __lowerCAmelCase  :			Optional[Any]					    =						self._hand.translate(str.maketrans(lowerCAmelCase    )    ).split()
     __lowerCAmelCase  :			List[str]					    =						[int(card[:-1]    ) for card in new_hand]
     __lowerCAmelCase  :			str					    =						{card[-1] for card in new_hand}
     return sorted(lowerCAmelCase       ,							reverse=lowerCAmelCase    ), card_suit







  def __repr__(			self :    List[str]    )							->	Any:






     """simple docstring"""







     return f'''{self.__class__}("{self._hand}")'''







  def __str__(			self :    Any    )							->	Any:






     """simple docstring"""







     return self._hand







  def __eq__(			self :    Union[str, Any]       ,							lowerCAmelCase :    List[Any]    )							->	Union[str, Any]:






     """simple docstring"""







     if isinstance(lowerCAmelCase       ,							lowerCAmelCase    ):
        return self.compare_with(lowerCAmelCase    ) == "Tie"
     return NotImplemented







  def __lt__(			self :    Dict       ,							lowerCAmelCase :    str    )							->	List[str]:






     """simple docstring"""







     if isinstance(lowerCAmelCase       ,							lowerCAmelCase    ):
        return self.compare_with(lowerCAmelCase    ) == "Loss"
     return NotImplemented







  def __le__(			self :    str       ,							lowerCAmelCase :    int    )							->	Union[str, Any]:






     """simple docstring"""







     if isinstance(lowerCAmelCase       ,							lowerCAmelCase    ):
        return self < other or self == other
     return NotImplemented







  def __gt__(			self :    Dict       ,							lowerCAmelCase :    str    )							->	Optional[Any]:






     """simple docstring"""







     if isinstance(lowerCAmelCase       ,							lowerCAmelCase    ):
        return not self < other and self != other
     return NotImplemented







  def __ge__(			self :    Tuple       ,							lowerCAmelCase :    Tuple    )							->	Dict:






     """simple docstring"""







     if isinstance(lowerCAmelCase       ,							lowerCAmelCase    ):
        return not self < other
     return NotImplemented







  def __hash__(			self :    List[str]    )							->	str:






     """simple docstring"""







     return object.__hash__(self    )






def 	snake_case_      ()			->	int:
   # Solution for problem number 54 from Project Euler
   # Input from poker_hands.txt file
   __lowerCAmelCase  :			str					    =						0
   __lowerCAmelCase  :			List[str]					    =						os.path.abspath(os.path.dirname(__A     )     )
   __lowerCAmelCase  :			Optional[Any]					    =						os.path.join(__A					,   """poker_hands.txt"""     )
   with open(__A     ) as file_hand:
      for line in file_hand:
         __lowerCAmelCase  :			Union[str, Any]					    =						line[:1_4].strip()
         __lowerCAmelCase  :			Optional[int]					    =						line[1_5:].strip()
         __lowerCAmelCase    ,__lowerCAmelCase  :			List[str]					    =						PokerHand(__A     ), PokerHand(__A     )
         __lowerCAmelCase  :			List[str]					    =						player.compare_with(__A     )
         if output == "Win":
            answer += 1
   return answer


if __name__ == "__main__":
   solution()


