






import logging
import math
from functools import partial
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union

import torch

from .tensor_utils import tensor_tree_map, tree_map


def 	UpperCAmelCase__      (      UpperCAmelCase__ :Dict					):






 '''simple docstring'''

 a						=		[]
 if isinstance(lowerCamelCase_ ,					lowerCamelCase_					):
  for v in tree.values():
   shapes.extend(_fetch_dims(lowerCamelCase_					)					)
 elif isinstance(lowerCamelCase_ ,					(list, tuple)					):
  for t in tree:
   shapes.extend(_fetch_dims(lowerCamelCase_					)					)
 elif isinstance(lowerCamelCase_ ,					torch.Tensor					):
  shapes.append(tree.shape					)
 else:
  raise ValueError("Not supported"					)

 return shapes


@torch.jit.ignore
def 	UpperCAmelCase__      (      UpperCAmelCase__ :List[str] ,					UpperCAmelCase__ :List[str]					):






 '''simple docstring'''

 a						=		[]
 for d in reversed(lowerCamelCase_					):
  idx.append(flat_idx % d					)
  a						=		flat_idx // d

 return tuple(reversed(lowerCamelCase_					)					)


@torch.jit.ignore
def 	UpperCAmelCase__      (      UpperCAmelCase__ :Dict ,					UpperCAmelCase__ :str ,					UpperCAmelCase__ :Optional[int] ,					UpperCAmelCase__ :List[Any] = None ,					UpperCAmelCase__ :Tuple = None ,					):






 '''simple docstring'''

 def reduce_edge_list(UpperCAmelCase__ :Any					) -> None:
  a						=		True
  for i in range(len(lowerCamelCase_					)					):
   a						=		-1 * (i + 1)
   l[reversed_idx] &= tally
   a						=		l[reversed_idx]

 if start_edges is None:
  a						=		[s == 0 for s in start]
  reduce_edge_list(lowerCamelCase_					)
 if end_edges is None:
  a						=		[e == (d - 1) for e, d in zip(lowerCamelCase_ ,					lowerCamelCase_					)]
  reduce_edge_list(lowerCamelCase_					)

 # Base cases. Either start/end are empty and we're done, or the final,
 # one-dimensional tensor can be simply sliced
 if len(lowerCamelCase_					) == 0:
  return [()]
 elif len(lowerCamelCase_					) == 1:
  return [(slice(start[0] ,					end[0] + 1					),)]

 a						=		[]
 a						=		[]

 # Dimensions common to start and end can be selected directly
 for s, e in zip(lowerCamelCase_ ,					lowerCamelCase_					):
  if s == e:
   path_list.append(slice(lowerCamelCase_ ,					s + 1					)					)
  else:
   break

 a						=		tuple(lowerCamelCase_					)
 a						=		len(lowerCamelCase_					)

 # start == end, and we're done
 if divergence_idx == len(lowerCamelCase_					):
  return [path]

 def upper() -> Tuple[Tuple[slice, ...], ...]:
  assert start_edges is not None
  assert end_edges is not None

  a						=		start[divergence_idx]
  return tuple(
      path + (slice(lowerCamelCase_ ,					sdi + 1					),) + s
      for s in _get_minimal_slice_set(
          start[divergence_idx + 1 :] ,					[d - 1 for d in dims[divergence_idx + 1 :]] ,					dims[divergence_idx + 1 :] ,					start_edges=start_edges[divergence_idx + 1 :] ,					end_edges=[True for _ in end_edges[divergence_idx + 1 :]] ,					)					)

 def lower() -> Tuple[Tuple[slice, ...], ...]:
  assert start_edges is not None
  assert end_edges is not None

  a						=		end[divergence_idx]
  return tuple(
      path + (slice(lowerCamelCase_ ,					edi + 1					),) + s
      for s in _get_minimal_slice_set(
          [0 for _ in start[divergence_idx + 1 :]] ,					end[divergence_idx + 1 :] ,					dims[divergence_idx + 1 :] ,					start_edges=[True for _ in start_edges[divergence_idx + 1 :]] ,					end_edges=end_edges[divergence_idx + 1 :] ,					)					)

 # If both start and end are at the edges of the subtree rooted at
 # divergence_idx, we can just select the whole subtree at once
 if start_edges[divergence_idx] and end_edges[divergence_idx]:
  slices.append(path + (slice(start[divergence_idx] ,					end[divergence_idx] + 1					),)					)
 # If just start is at the edge, we can grab almost all of the subtree,
 # treating only the ragged bottom edge as an edge case
 elif start_edges[divergence_idx]:
  slices.append(path + (slice(start[divergence_idx] ,					end[divergence_idx]					),)					)
  slices.extend(lower()					)
 # Analogous to the previous case, but the top is ragged this time
 elif end_edges[divergence_idx]:
  slices.extend(upper()					)
  slices.append(path + (slice(start[divergence_idx] + 1 ,					end[divergence_idx] + 1					),)					)
 # If both sides of the range are ragged, we need to handle both sides
 # separately. If there's contiguous meat in between them, we can index it
 # in one big chunk
 else:
  slices.extend(upper()					)
  a						=		end[divergence_idx] - start[divergence_idx]
  if middle_ground > 1:
   slices.append(path + (slice(start[divergence_idx] + 1 ,					end[divergence_idx]					),)					)
  slices.extend(lower()					)

 return slices


@torch.jit.ignore
def 	UpperCAmelCase__      (      UpperCAmelCase__ :int ,					UpperCAmelCase__ :Optional[Any] ,					UpperCAmelCase__ :Union[str, Any] ,					UpperCAmelCase__ :Union[str, Any]					):






 '''simple docstring'''

 a						=		t.shape[:no_batch_dims]
 a						=		list(_flat_idx_to_idx(lowerCamelCase_ ,					lowerCamelCase_					)					)
 # _get_minimal_slice_set is inclusive
 a						=		list(_flat_idx_to_idx(flat_end - 1 ,					lowerCamelCase_					)					)

 # Get an ordered list of slices to perform
 a						=		_get_minimal_slice_set(
     lowerCamelCase_ ,					lowerCamelCase_ ,					lowerCamelCase_ ,					)

 a						=		[t[s] for s in slices]

 return torch.cat([s.view((-1,) + t.shape[no_batch_dims:]					) for s in sliced_tensors]					)


def 	UpperCAmelCase__      (      UpperCAmelCase__ :Optional[Any] ,					UpperCAmelCase__ :List[Any] ,					UpperCAmelCase__ :Optional[int] ,					UpperCAmelCase__ :List[str] ,					UpperCAmelCase__ :Optional[int] = False ,					UpperCAmelCase__ :Any = None ,					UpperCAmelCase__ :int = False ,					):






 '''simple docstring'''

 if not (len(lowerCamelCase_					) > 0):
  raise ValueError("Must provide at least one input"					)

 a						=		[shape[:no_batch_dims] for shape in _fetch_dims(lowerCamelCase_					)]
 a						=		tuple([max(lowerCamelCase_					) for s in zip(*lowerCamelCase_					)]					)

 def _prep_inputs(UpperCAmelCase__ :Dict					) -> torch.Tensor:
  if not low_mem:
   if not sum(t.shape[:no_batch_dims]					) == no_batch_dims:
    a						=		t.expand(orig_batch_dims + t.shape[no_batch_dims:]					)
   a						=		t.reshape(-1 ,					*t.shape[no_batch_dims:]					)
  else:
   a						=		t.expand(orig_batch_dims + t.shape[no_batch_dims:]					)
  return t

 a						=		tensor_tree_map(_prep_inputs ,					lowerCamelCase_					)
 a						=		None
 if _out is not None:
  a						=		tensor_tree_map(lambda UpperCAmelCase__					: t.view([-1] + list(t.shape[no_batch_dims:]					)					) ,					_out					)

 a						=		1
 for d in orig_batch_dims:
  flat_batch_dim *= d

 a						=		flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

 def _select_chunk(UpperCAmelCase__ :Tuple					) -> torch.Tensor:
  return t[i : i + chunk_size] if t.shape[0] != 1 else t

 a						=		0
 a						=		prepped_outputs
 for _ in range(lowerCamelCase_					):
  # Chunk the input
  if not low_mem:
   a						=		_select_chunk
  else:
   a						=		partial(
       _chunk_slice ,					flat_start=lowerCamelCase_ ,					flat_end=min(lowerCamelCase_ ,					i + chunk_size					) ,					no_batch_dims=len(lowerCamelCase_					) ,					)

  a						=		tensor_tree_map(lowerCamelCase_ ,					lowerCamelCase_					)

  # Run the layer on the chunk
  a						=		layer(**lowerCamelCase_					)

  # Allocate space for the output
  if out is None:
   a						=		tensor_tree_map(lambda UpperCAmelCase__					: t.new_zeros((flat_batch_dim,) + t.shape[1:]					) ,					lowerCamelCase_					)

  # Put the chunk in its pre-allocated space
  if isinstance(lowerCamelCase_ ,					lowerCamelCase_					):

   def assign(UpperCAmelCase__ :List[str] ,					UpperCAmelCase__ :Optional[int]					) -> None:
    for k, v in da.items():
     if isinstance(lowerCamelCase_ ,					lowerCamelCase_					):
      assign(lowerCamelCase_ ,					da[k]					)
     else:
      if _add_into_out:
       v[i : i + chunk_size] += da[k]
      else:
       a						=		da[k]

   assign(lowerCamelCase_ ,					lowerCamelCase_					)
  elif isinstance(lowerCamelCase_ ,					lowerCamelCase_					):
   for xa, xa in zip(lowerCamelCase_ ,					lowerCamelCase_					):
    if _add_into_out:
     xa[i : i + chunk_size] += xa
    else:
     a						=		xa
  elif isinstance(lowerCamelCase_ ,					torch.Tensor					):
   if _add_into_out:
    out[i : i + chunk_size] += output_chunk
   else:
    a						=		output_chunk
  else:
   raise ValueError("Not supported"					)

  i += chunk_size

 a						=		tensor_tree_map(lambda UpperCAmelCase__					: t.view(orig_batch_dims + t.shape[1:]					) ,					lowerCamelCase_					)

 return out




class 		_lowercase		:

   def __init__(      self			:       List[str]							,   __lowerCAmelCase			:       int = 512							,   )       ->				Tuple:


    """simple docstring"""






    a						=		max_chunk_size
    a						=		None
    a						=		None

   def 		A							(      self			:       str							,   __lowerCAmelCase			:       Callable							,   __lowerCAmelCase			:       tuple							,   __lowerCAmelCase			:       int							)       ->				List[Any]:


    """simple docstring"""






    logging.info("Tuning chunk size..."							)

    if min_chunk_size >= self.max_chunk_size:
     return min_chunk_size

    a						=		[2**l for l in range(int(math.log(self.max_chunk_size							,   2							)							) + 1							)]
    a						=		[c for c in candidates if c > min_chunk_size]
    a						=		[min_chunk_size] + candidates
    candidates[-1] += 4

    def test_chunk_size(__lowerCAmelCase			:       int							) -> bool:
     try:
      with torch.no_grad():
       fn(*UpperCAmelCase_							,   chunk_size=UpperCAmelCase_							)
      return True
     except RuntimeError:
      return False

    a						=		0
    a						=		len(UpperCAmelCase_							) - 1
    while i > min_viable_chunk_size_index:
     a						=		test_chunk_size(candidates[i]							)
     if not viable:
      a						=		(min_viable_chunk_size_index + i) // 2
     else:
      a						=		i
      a						=		(i + len(UpperCAmelCase_							) - 1) // 2

    return candidates[min_viable_chunk_size_index]

   def 		A							(      self			:       Any							,   __lowerCAmelCase			:       Iterable							,   __lowerCAmelCase			:       Iterable							)       ->				Any:


    """simple docstring"""






    a						=		True
    for aa, aa in zip(UpperCAmelCase_							,   UpperCAmelCase_							):
     assert type(UpperCAmelCase_							) == type(UpperCAmelCase_							)
     if isinstance(UpperCAmelCase_							,   (list, tuple)							):
      consistent &= self._compare_arg_caches(UpperCAmelCase_							,   UpperCAmelCase_							)
     elif isinstance(UpperCAmelCase_							,   UpperCAmelCase_							):
      a						=		[v for _, v in sorted(aa.items()							,   key=lambda __lowerCAmelCase							: x[0]							)]
      a						=		[v for _, v in sorted(aa.items()							,   key=lambda __lowerCAmelCase							: x[0]							)]
      consistent &= self._compare_arg_caches(UpperCAmelCase_							,   UpperCAmelCase_							)
     else:
      consistent &= aa == aa

    return consistent




   def 		A							(      self			:       List[Any]							,   __lowerCAmelCase			:       Callable							,   __lowerCAmelCase			:       tuple							,   __lowerCAmelCase			:       int							,   )       ->				Dict:


    """simple docstring"""






    a						=		True
    a						=		tree_map(lambda __lowerCAmelCase							: a.shape if isinstance(UpperCAmelCase_							,   torch.Tensor							) else a							,   UpperCAmelCase_							,   UpperCAmelCase_							)
    if self.cached_arg_data is not None:
     # If args have changed shape/value, we need to re-tune
     assert len(self.cached_arg_data							) == len(UpperCAmelCase_							)
     a						=		self._compare_arg_caches(self.cached_arg_data							,   UpperCAmelCase_							)
    else:
     # Otherwise, we can reuse the precomputed value
     a						=		False

    if not consistent:
     a						=		self._determine_favorable_chunk_size(
         UpperCAmelCase_							,   UpperCAmelCase_							,   UpperCAmelCase_							,   )
     a						=		arg_data

    assert self.cached_chunk_size is not None

    return self.cached_chunk_size






from ...configuration_utils import PretrainedConfig
from ...utils import logging
from ...utils.backbone_utils import BackboneConfigMixin, get_aligned_output_features_output_indices


A_		:     int        =     logging.get_logger(__name__)

A_		:     str        =     {
    '''microsoft/focalnet-tiny''': '''https://huggingface.co/microsoft/focalnet-tiny/resolve/main/config.json''',
}



class 		_lowercase		(       UpperCAmelCase__,   UpperCAmelCase__	):
   _UpperCAmelCase     	=			'''focalnet'''

   def __init__(      self			:       int							,   __lowerCAmelCase			:       Optional[Any]=224							,   __lowerCAmelCase			:       Any=4							,   __lowerCAmelCase			:       Any=3							,   __lowerCAmelCase			:       Tuple=96							,   __lowerCAmelCase			:       Dict=False							,   __lowerCAmelCase			:       Optional[int]=[192, 384, 768, 768]							,   __lowerCAmelCase			:       Union[str, Any]=[2, 2, 6, 2]							,   __lowerCAmelCase			:       Optional[int]=[2, 2, 2, 2]							,   __lowerCAmelCase			:       Union[str, Any]=[3, 3, 3, 3]							,   __lowerCAmelCase			:       str="gelu"							,   __lowerCAmelCase			:       Any=4.0							,   __lowerCAmelCase			:       Optional[int]=0.0							,   __lowerCAmelCase			:       Tuple=0.1							,   __lowerCAmelCase			:       str=False							,   __lowerCAmelCase			:       Optional[int]=1E-4							,   __lowerCAmelCase			:       Optional[Any]=False							,   __lowerCAmelCase			:       Union[str, Any]=False							,   __lowerCAmelCase			:       str=False							,   __lowerCAmelCase			:       Any=0.0_2							,   __lowerCAmelCase			:       str=1E-5							,   __lowerCAmelCase			:       Optional[Any]=32							,   __lowerCAmelCase			:       Dict=None							,   __lowerCAmelCase			:       str=None							,   **__lowerCAmelCase			:       Any							,   )       ->				List[str]:


    """simple docstring"""






    super().__init__(**__lowerCAmelCase							)

    a						=		image_size
    a						=		patch_size
    a						=		num_channels
    a						=		embed_dim
    a						=		use_conv_embed
    a						=		hidden_sizes
    a						=		depths
    a						=		focal_levels
    a						=		focal_windows
    a						=		hidden_act
    a						=		mlp_ratio
    a						=		hidden_dropout_prob
    a						=		drop_path_rate
    a						=		use_layerscale
    a						=		layerscale_value
    a						=		use_post_layernorm
    a						=		use_post_layernorm_in_modulation
    a						=		normalize_modulator
    a						=		initializer_range
    a						=		layer_norm_eps
    a						=		encoder_stride
    a						=		["stem"] + [f"""stage{idx}""" for idx in range(1							,   len(self.depths							) + 1							)]
    a		,  a						=		get_aligned_output_features_output_indices(
        out_features=__lowerCAmelCase							,   out_indices=__lowerCAmelCase							,   stage_names=self.stage_names							)

