import enum
import inspect
from typing import Iterable, List, Optional, Tuple, Union

class 	_lowerCamelCase  (     enum.Enum				):

      """simple docstring"""

      lowerCAmelCase__     :	List[Any]      =   'timm'
      lowerCAmelCase__     :	List[Any]      =   'transformers'







def    __SCREAMING_SNAKE_CASE				(					lowercase_   ,       lowercase_   ,       lowercase_ )    ->		Any:

    """simple docstring"""


    if stage_names is None:
        raise ValueError('''Stage_names must be set for transformers backbones''' )

    if out_features is not None:
        if not isinstance(SCREAMING_SNAKE_CASE__   ,       (list,) ):
            raise ValueError(F"out_features must be a list {type(SCREAMING_SNAKE_CASE__ )}" )
        if any(feat not in stage_names for feat in out_features ):
            raise ValueError(F"out_features must be a subset of stage_names: {stage_names} got {out_features}" )

    if out_indices is not None:
        if not isinstance(SCREAMING_SNAKE_CASE__   ,       (list, tuple) ):
            raise ValueError(F"out_indices must be a list or tuple, got {type(SCREAMING_SNAKE_CASE__ )}" )
        if any(idx >= len(SCREAMING_SNAKE_CASE__ ) for idx in out_indices ):
            raise ValueError('''out_indices must be valid indices for stage_names {stage_names}, got {out_indices}''' )

    if out_features is not None and out_indices is not None:
        if len(SCREAMING_SNAKE_CASE__ ) != len(SCREAMING_SNAKE_CASE__ ):
            raise ValueError('''out_features and out_indices should have the same length if both are set''' )
        if out_features != [stage_names[idx] for idx in out_indices]:
            raise ValueError('''out_features and out_indices should correspond to the same stages if both are set''' )




def    __SCREAMING_SNAKE_CASE				(					lowercase_   ,       lowercase_   ,       lowercase_   ,       )    ->		Union[str, Any]:

    """simple docstring"""


    if out_indices is None and out_features is None:
        __UpperCamelCase											=  [len(SCREAMING_SNAKE_CASE__ ) - 1]
        __UpperCamelCase											=  [stage_names[-1]]
    elif out_indices is None and out_features is not None:
        __UpperCamelCase											=  [stage_names.index(SCREAMING_SNAKE_CASE__ ) for layer in out_features]
    elif out_features is None and out_indices is not None:
        __UpperCamelCase											=  [stage_names[idx] for idx in out_indices]
    return out_features, out_indices




def    __SCREAMING_SNAKE_CASE				(					lowercase_   ,       lowercase_   ,       lowercase_   ,       )    ->		int:

    """simple docstring"""


    verify_out_features_out_indices(out_features=SCREAMING_SNAKE_CASE__   ,       out_indices=SCREAMING_SNAKE_CASE__   ,       stage_names=SCREAMING_SNAKE_CASE__ )
    __UpperCamelCase											=  _align_output_features_output_indices(
        out_features=SCREAMING_SNAKE_CASE__   ,       out_indices=SCREAMING_SNAKE_CASE__   ,       stage_names=SCREAMING_SNAKE_CASE__ )
    # Verify that the aligned out_features and out_indices are valid
    verify_out_features_out_indices(out_features=SCREAMING_SNAKE_CASE__   ,       out_indices=SCREAMING_SNAKE_CASE__   ,       stage_names=SCREAMING_SNAKE_CASE__ )
    return output_features, output_indices

class 	_lowerCamelCase  :

      """simple docstring"""

      lowerCAmelCase__     :	Optional[BackboneType]      =   None







      def  snake_case		(       self   :	List[Any]	,    snake_case   :	List[str]			):




          if getattr(self	,    '''_backbone'''	,    lowercase_			) is None:
              raise ValueError('''self._backbone must be set before calling _init_timm_backbone'''			)

          # These will diagree with the defaults for the transformers models e.g. for resnet50
          # the transformer model has out_features = ['stem', 'stage1', 'stage2', 'stage3', 'stage4']
          # the timm model has out_features = ['act', 'layer1', 'layer2', 'layer3', 'layer4']
          __UpperCamelCase											=  [stage['module'] for stage in self._backbone.feature_info.info]
          __UpperCamelCase											=  [stage['num_chs'] for stage in self._backbone.feature_info.info]
          __UpperCamelCase											=  self._backbone.feature_info.out_indices
          __UpperCamelCase											=  self._backbone.feature_info.module_name()

          # We verify the out indices and out features are valid
          verify_out_features_out_indices(
              out_features=lowercase_	,    out_indices=lowercase_	,    stage_names=self.stage_names			)
          __UpperCamelCase											=  out_features, out_indices







      def  snake_case		(       self   :	Tuple	,    snake_case   :	int			):
          __UpperCamelCase											=  getattr(lowercase_	,    '''stage_names'''			)
          __UpperCamelCase											=  getattr(lowercase_	,    '''out_features'''	,    lowercase_			)
          __UpperCamelCase											=  getattr(lowercase_	,    '''out_indices'''	,    lowercase_			)

          __UpperCamelCase											=  stage_names
          __UpperCamelCase											=  get_aligned_output_features_output_indices(
              out_features=lowercase_	,    out_indices=lowercase_	,    stage_names=lowercase_			)
          # Number of channels for each stage. This is set in the transformer backbone model init
          __UpperCamelCase											=  None







      def  snake_case		(       self   :	Optional[Any]	,    snake_case   :	List[Any]			):
          __UpperCamelCase											=  config

          __UpperCamelCase											=  getattr(lowercase_	,    '''use_timm_backbone'''	,    lowercase_			)
          __UpperCamelCase											=  BackboneType.TIMM if self.use_timm_backbone else BackboneType.TRANSFORMERS

          if self.backbone_type == BackboneType.TIMM:
              self._init_timm_backbone(lowercase_			)
          elif self.backbone_type == BackboneType.TRANSFORMERS:
              self._init_transformers_backbone(lowercase_			)
          else:
              raise ValueError(F"backbone_type {self.backbone_type} not supported."			)







      @property
      def  snake_case		(       self   :	str			):
          return self._out_features







      @out_features.setter
      def  snake_case		(       self   :	List[Any]	,    snake_case   :	List[str]			):
          __UpperCamelCase											=  get_aligned_output_features_output_indices(
              out_features=lowercase_	,    out_indices=lowercase_	,    stage_names=self.stage_names			)







      @property
      def  snake_case		(       self   :	List[Any]			):
          return self._out_indices







      @out_indices.setter
      def  snake_case		(       self   :	int	,    snake_case   :	Union[Tuple[int], List[int]]			):
          __UpperCamelCase											=  get_aligned_output_features_output_indices(
              out_features=lowercase_	,    out_indices=lowercase_	,    stage_names=self.stage_names			)







      @property
      def  snake_case		(       self   :	Optional[Any]			):
          return {stage: self.num_features[i] for i, stage in enumerate(self.stage_names			)}







      @property
      def  snake_case		(       self   :	List[str]			):
          return [self.out_feature_channels[name] for name in self.out_features]







      def  snake_case		(       self   :	Optional[Any]	,    *snake_case   :	Optional[int]	,    **snake_case   :	Optional[int]			):
          __UpperCamelCase											=  dict(inspect.signature(self.forward			).parameters			)
          __UpperCamelCase											=  {k: v for k, v in kwargs.items() if k in signature}
          return self(*lowercase_	,    **lowercase_			)







      def  snake_case		(       self   :	Optional[int]	,    snake_case   :	str	,    snake_case   :	Optional[bool] = None	,    snake_case   :	Optional[bool] = None	,    snake_case   :	Optional[bool] = None	,    ):
          raise NotImplementedError('''This method should be implemented by the derived class.'''			)







      def  snake_case		(       self   :	Optional[int]			):
          __UpperCamelCase											=  super().to_dict()
          __UpperCamelCase											=  output.pop('''_out_features'''			)
          __UpperCamelCase											=  output.pop('''_out_indices'''			)
          return output







class 	_lowerCamelCase  :

      """simple docstring"""

      @property
      def  snake_case		(       self   :	int			):
          return self._out_features







      @out_features.setter
      def  snake_case		(       self   :	Dict	,    snake_case   :	List[str]			):
          __UpperCamelCase											=  get_aligned_output_features_output_indices(
              out_features=lowercase_	,    out_indices=lowercase_	,    stage_names=self.stage_names			)







      @property
      def  snake_case		(       self   :	Optional[Any]			):
          return self._out_indices







      @out_indices.setter
      def  snake_case		(       self   :	Union[str, Any]	,    snake_case   :	Union[Tuple[int], List[int]]			):
          __UpperCamelCase											=  get_aligned_output_features_output_indices(
              out_features=lowercase_	,    out_indices=lowercase_	,    stage_names=self.stage_names			)







      def  snake_case		(       self   :	Optional[int]			):
          __UpperCamelCase											=  super().to_dict()
          __UpperCamelCase											=  output.pop('''_out_features'''			)
          __UpperCamelCase											=  output.pop('''_out_indices'''			)
          return output












def    __SCREAMING_SNAKE_CASE				(					lowercase_ )    ->		list:

    """simple docstring"""


    __UpperCamelCase											=  len(lowercase_ )

    # Set the gap value to be decreased by a factor of 1.3
    # after each iteration
    __UpperCamelCase											=  1.3

    # Continue sorting until the gap is 1
    while gap > 1:
        # Decrease the gap value
        __UpperCamelCase											=  int(gap / shrink )

        # Sort the elements using insertion sort
        for i in range(lowercase_   ,       len(lowercase_ ) ):
            __UpperCamelCase											=  collection[i]
            __UpperCamelCase											=  i
            while j >= gap and collection[j - gap] > temp:
                __UpperCamelCase											=  collection[j - gap]
                j -= gap
            __UpperCamelCase											=  temp

    return collection


if __name__ == "__main__":
 import doctest

 doctest.testmod()






