



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 	_lowerCAmelCase						(				__lowerCamelCase   :     Union[dict, list, tuple, torch.Tensor]     ):



 """simple docstring"""





 __SCREAMING_SNAKE_CASE       :    Any       =	[]
 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 	_lowerCAmelCase						(				__lowerCamelCase   :     int		,	__lowerCamelCase   :     Tuple[int, ...]     ):



 """simple docstring"""





 __SCREAMING_SNAKE_CASE       :    Any       =	[]
 for d in reversed(__lowerCamelCase     ):
  idx.append(flat_idx % d     )
  __SCREAMING_SNAKE_CASE       :    int       =	flat_idx // d

 return tuple(reversed(__lowerCamelCase     )     )






@torch.jit.ignore
def 	_lowerCAmelCase						(				__lowerCamelCase   :     Sequence[int]		,	__lowerCamelCase   :     Sequence[int]		,	__lowerCamelCase   :     Sequence[int]		,	__lowerCamelCase   :     Optional[Sequence[bool]] = None		,	__lowerCamelCase   :     Optional[Sequence[bool]] = None		,	):



 """simple docstring"""





 def reduce_edge_list(__lowerCamelCase   :     List[bool]     ) -> None:
  __SCREAMING_SNAKE_CASE       :    Tuple       =	True
  for i in range(len(__lowerCamelCase     )     ):
   __SCREAMING_SNAKE_CASE       :    Tuple       =	-1 * (i + 1)
   l[reversed_idx] &= tally
   __SCREAMING_SNAKE_CASE       :    str       =	l[reversed_idx]

 if start_edges is None:
  __SCREAMING_SNAKE_CASE       :    List[str]       =	[s == 0 for s in start]
  reduce_edge_list(__lowerCamelCase     )
 if end_edges is None:
  __SCREAMING_SNAKE_CASE       :    str       =	[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     ),)]

 __SCREAMING_SNAKE_CASE       :    List[Tuple[slice, ...]]       =	[]
 __SCREAMING_SNAKE_CASE       :    List[slice]       =	[]

 # 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

 __SCREAMING_SNAKE_CASE       :    Tuple[slice, ...]       =	tuple(__lowerCamelCase     )
 __SCREAMING_SNAKE_CASE       :    Any       =	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

  __SCREAMING_SNAKE_CASE       :    Union[str, Any]       =	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

  __SCREAMING_SNAKE_CASE       :    Union[str, Any]       =	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()     )
  __SCREAMING_SNAKE_CASE       :    List[str]       =	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 	_lowerCAmelCase						(				__lowerCamelCase   :     torch.Tensor		,	__lowerCamelCase   :     int		,	__lowerCamelCase   :     int		,	__lowerCamelCase   :     int     ):



 """simple docstring"""





 __SCREAMING_SNAKE_CASE       :    List[str]       =	t.shape[:no_batch_dims]
 __SCREAMING_SNAKE_CASE       :    str       =	list(_flat_idx_to_idx(__lowerCamelCase		,	__lowerCamelCase     )     )
 # _get_minimal_slice_set is inclusive
 __SCREAMING_SNAKE_CASE       :    List[str]       =	list(_flat_idx_to_idx(flat_end - 1		,	__lowerCamelCase     )     )

 # Get an ordered list of slices to perform
 __SCREAMING_SNAKE_CASE       :    List[str]       =	_get_minimal_slice_set(
     __lowerCamelCase		,	__lowerCamelCase		,	__lowerCamelCase		,	)

 __SCREAMING_SNAKE_CASE       :    Any       =	[t[s] for s in slices]

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






def 	_lowerCAmelCase						(				__lowerCamelCase   :     Callable		,	__lowerCamelCase   :     Dict[str, Any]		,	__lowerCamelCase   :     int		,	__lowerCamelCase   :     int		,	__lowerCamelCase   :     bool = False		,	__lowerCamelCase   :     Any = None		,	__lowerCamelCase   :     bool = False		,	):



 """simple docstring"""





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

 __SCREAMING_SNAKE_CASE       :    Optional[int]       =	[shape[:no_batch_dims] for shape in _fetch_dims(__lowerCamelCase     )]
 __SCREAMING_SNAKE_CASE       :    Tuple       =	tuple([max(__lowerCamelCase     ) for s in zip(*__lowerCamelCase     )]     )

 def _prep_inputs(__lowerCamelCase   :     torch.Tensor     ) -> torch.Tensor:
  if not low_mem:
   if not sum(t.shape[:no_batch_dims]     ) == no_batch_dims:
    __SCREAMING_SNAKE_CASE       :    Any       =	t.expand(orig_batch_dims + t.shape[no_batch_dims:]     )
   __SCREAMING_SNAKE_CASE       :    int       =	t.reshape(-1		,	*t.shape[no_batch_dims:]     )
  else:
   __SCREAMING_SNAKE_CASE       :    List[str]       =	t.expand(orig_batch_dims + t.shape[no_batch_dims:]     )
  return t

 __SCREAMING_SNAKE_CASE       :    Dict[str, Any]       =	tensor_tree_map(_prep_inputs		,	__lowerCamelCase     )
 __SCREAMING_SNAKE_CASE       :    Dict       =	None
 if _out is not None:
  __SCREAMING_SNAKE_CASE       :    List[str]       =	tensor_tree_map(lambda __lowerCamelCase     : t.view([-1] + list(t.shape[no_batch_dims:]     )     )		,	_out     )

 __SCREAMING_SNAKE_CASE       :    Dict       =	1
 for d in orig_batch_dims:
  flat_batch_dim *= d

 __SCREAMING_SNAKE_CASE       :    int       =	flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

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

 __SCREAMING_SNAKE_CASE       :    Optional[Any]       =	0
 __SCREAMING_SNAKE_CASE       :    Dict       =	prepped_outputs
 for _ in range(__lowerCamelCase     ):
  # Chunk the input
  if not low_mem:
   __SCREAMING_SNAKE_CASE       :    int       =	_select_chunk
  else:
   __SCREAMING_SNAKE_CASE       :    Any       =	partial(
       _chunk_slice		,	flat_start=__lowerCamelCase		,	flat_end=min(__lowerCamelCase		,	i + chunk_size     )		,	no_batch_dims=len(__lowerCamelCase     )		,	)

  __SCREAMING_SNAKE_CASE       :    Dict[str, Any]       =	tensor_tree_map(__lowerCamelCase		,	__lowerCamelCase     )

  # Run the layer on the chunk
  __SCREAMING_SNAKE_CASE       :    Optional[int]       =	layer(**__lowerCamelCase     )

  # Allocate space for the output
  if out is None:
   __SCREAMING_SNAKE_CASE       :    Union[str, Any]       =	tensor_tree_map(lambda __lowerCamelCase     : t.new_zeros((flat_batch_dim,) + t.shape[1:]     )		,	__lowerCamelCase     )

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

   def assign(__lowerCamelCase   :     dict		,	__lowerCamelCase   :     dict     ) -> 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:
       __SCREAMING_SNAKE_CASE       :    List[Any]       =	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:
     __SCREAMING_SNAKE_CASE       :    Optional[int]       =	xa
  elif isinstance(__lowerCamelCase		,	torch.Tensor     ):
   if _add_into_out:
    out[i : i + chunk_size] += output_chunk
   else:
    __SCREAMING_SNAKE_CASE       :    Optional[int]       =	output_chunk
  else:
   raise ValueError("Not supported"     )

  i += chunk_size

 __SCREAMING_SNAKE_CASE       :    Optional[Any]       =	tensor_tree_map(lambda __lowerCamelCase     : t.view(orig_batch_dims + t.shape[1:]     )		,	__lowerCamelCase     )

 return out






class       _SCREAMING_SNAKE_CASE	:





     def __init__(       self :							str     ,  UpperCamelCase :							int = 5_1_2     ,  )->str:
      __SCREAMING_SNAKE_CASE       :    List[str]       =	max_chunk_size
      __SCREAMING_SNAKE_CASE       :    Optional[int]       =	None
      __SCREAMING_SNAKE_CASE       :    Optional[tuple]       =	None





     def 	__snake_case    (       self :							Union[str, Any]     ,  UpperCamelCase :							Callable     ,  UpperCamelCase :							tuple     ,  UpperCamelCase :							int				)->int:
      logging.info("Tuning chunk size..."				)

      if min_chunk_size >= self.max_chunk_size:
       return min_chunk_size

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

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

      __SCREAMING_SNAKE_CASE       :    List[str]       =	0
      __SCREAMING_SNAKE_CASE       :    Any       =	len(UpperCamelCase				) - 1
      while i > min_viable_chunk_size_index:
       __SCREAMING_SNAKE_CASE       :    str       =	test_chunk_size(candidates[i]				)
       if not viable:
        __SCREAMING_SNAKE_CASE       :    Tuple       =	(min_viable_chunk_size_index + i) // 2
       else:
        __SCREAMING_SNAKE_CASE       :    Optional[int]       =	i
        __SCREAMING_SNAKE_CASE       :    int       =	(i + len(UpperCamelCase				) - 1) // 2

      return candidates[min_viable_chunk_size_index]





     def 	__snake_case    (       self :							str     ,  UpperCamelCase :							Iterable     ,  UpperCamelCase :							Iterable				)->bool:
      __SCREAMING_SNAKE_CASE       :    Union[str, Any]       =	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				):
        __SCREAMING_SNAKE_CASE       :    Optional[int]       =	[v for _, v in sorted(aa.items()     ,  key=lambda UpperCamelCase				: x[0]				)]
        __SCREAMING_SNAKE_CASE       :    Dict       =	[v for _, v in sorted(aa.items()     ,  key=lambda UpperCamelCase				: x[0]				)]
        consistent &= self._compare_arg_caches(UpperCamelCase     ,  UpperCamelCase				)
       else:
        consistent &= aa == aa

      return consistent






     def 	__snake_case    (       self :							List[str]     ,  UpperCamelCase :							Callable     ,  UpperCamelCase :							tuple     ,  UpperCamelCase :							int     ,  )->int:
      __SCREAMING_SNAKE_CASE       :    List[str]       =	True
      __SCREAMING_SNAKE_CASE       :    tuple       =	tree_map(lambda UpperCamelCase				: 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				)
       __SCREAMING_SNAKE_CASE       :    List[str]       =	self._compare_arg_caches(self.cached_arg_data     ,  UpperCamelCase				)
      else:
       # Otherwise, we can reuse the precomputed value
       __SCREAMING_SNAKE_CASE       :    Optional[int]       =	False

      if not consistent:
       __SCREAMING_SNAKE_CASE       :    Any       =	self._determine_favorable_chunk_size(
           UpperCamelCase     ,  UpperCamelCase     ,  UpperCamelCase     ,  )
       __SCREAMING_SNAKE_CASE       :    Tuple       =	arg_data

      assert self.cached_chunk_size is not None

      return self.cached_chunk_size











import warnings

from ...utils import logging
from .image_processing_layoutlmva import LayoutLMvaImageProcessor


_lowerCamelCase						    =  logging.get_logger(__name__)

class       _SCREAMING_SNAKE_CASE	(UpperCamelCase ):





     def __init__(       self :							int     ,  *UpperCamelCase :							Optional[int]     ,  **UpperCamelCase :							Optional[int]				)->None:
      warnings.warn(
          "The class LayoutLMv2FeatureExtractor is deprecated and will be removed in version 5 of Transformers."
          " Please use LayoutLMv2ImageProcessor instead."     ,  UpperCamelCase     ,  )
      super().__init__(*UpperCamelCase     ,  **UpperCamelCase				)






