


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				(			SCREAMING_SNAKE_CASE__			:					Union[dict, list, tuple, torch.Tensor]				):
     __UpperCamelCase    							=[]
     if isinstance(SCREAMING_SNAKE_CASE__			,     SCREAMING_SNAKE_CASE__				):
          for v in tree.values():
               shapes.extend(_fetch_dims(SCREAMING_SNAKE_CASE__				)				)
     elif isinstance(SCREAMING_SNAKE_CASE__			,     (list, tuple)				):
          for t in tree:
               shapes.extend(_fetch_dims(SCREAMING_SNAKE_CASE__				)				)
     elif isinstance(SCREAMING_SNAKE_CASE__			,     torch.Tensor				):
          shapes.append(tree.shape				)
     else:
          raise ValueError('Not supported'				)

     return shapes

@torch.jit.ignore
def 						_UpperCAmelCase				(			SCREAMING_SNAKE_CASE__			:					int			,     SCREAMING_SNAKE_CASE__			:					Tuple[int, ...]				):
     __UpperCamelCase    							=[]
     for d in reversed(SCREAMING_SNAKE_CASE__				):
          idx.append(flat_idx % d				)
          __UpperCamelCase    							=flat_idx // d

     return tuple(reversed(SCREAMING_SNAKE_CASE__				)				)

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

     # start_edges and end_edges both indicate whether, starting from any given
     # dimension, the start/end index is at the top/bottom edge of the
     # corresponding tensor, modeled as a tree
     def reduce_edge_list(SCREAMING_SNAKE_CASE__			:					List[bool]				) -> None:
          __UpperCamelCase    							=True
          for i in range(len(SCREAMING_SNAKE_CASE__				)				):
               __UpperCamelCase    							=-1 * (i + 1)
               l[reversed_idx] &= tally
               __UpperCamelCase    							=l[reversed_idx]

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

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

     __UpperCamelCase    							=[]
     __UpperCamelCase    							=[]

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

     __UpperCamelCase    							=tuple(SCREAMING_SNAKE_CASE__				)
     __UpperCamelCase    							=len(SCREAMING_SNAKE_CASE__				)

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

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

          __UpperCamelCase    							=start[divergence_idx]
          return tuple(
              path + (slice(SCREAMING_SNAKE_CASE__			,     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

          __UpperCamelCase    							=end[divergence_idx]
          return tuple(
              path + (slice(SCREAMING_SNAKE_CASE__			,     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()				)
          __UpperCamelCase    							=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				(			SCREAMING_SNAKE_CASE__			:					torch.Tensor			,     SCREAMING_SNAKE_CASE__			:					int			,     SCREAMING_SNAKE_CASE__			:					int			,     SCREAMING_SNAKE_CASE__			:					int				):
     __UpperCamelCase    							=t.shape[:no_batch_dims]
     __UpperCamelCase    							=list(_flat_idx_to_idx(SCREAMING_SNAKE_CASE__			,     SCREAMING_SNAKE_CASE__				)				)
     # _get_minimal_slice_set is inclusive
     __UpperCamelCase    							=list(_flat_idx_to_idx(flat_end - 1			,     SCREAMING_SNAKE_CASE__				)				)

     # Get an ordered list of slices to perform
     __UpperCamelCase    							=_get_minimal_slice_set(
         SCREAMING_SNAKE_CASE__			,     SCREAMING_SNAKE_CASE__			,     SCREAMING_SNAKE_CASE__			,     )

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

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

def 						_UpperCAmelCase				(			SCREAMING_SNAKE_CASE__			:					Callable			,     SCREAMING_SNAKE_CASE__			:					Dict[str, Any]			,     SCREAMING_SNAKE_CASE__			:					int			,     SCREAMING_SNAKE_CASE__			:					int			,     SCREAMING_SNAKE_CASE__			:					bool = False			,     SCREAMING_SNAKE_CASE__			:					Any = None			,     SCREAMING_SNAKE_CASE__			:					bool = False			,     ):
     if not (len(SCREAMING_SNAKE_CASE__				) > 0):
          raise ValueError('Must provide at least one input'				)

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

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

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

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

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

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

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

          __UpperCamelCase    							=tensor_tree_map(SCREAMING_SNAKE_CASE__			,     SCREAMING_SNAKE_CASE__				)

          # Run the layer on the chunk
          __UpperCamelCase    							=layer(**SCREAMING_SNAKE_CASE__				)

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

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

               def assign(SCREAMING_SNAKE_CASE__			:					dict			,     SCREAMING_SNAKE_CASE__			:					dict				) -> None:
                    for k, v in da.items():
                         if isinstance(SCREAMING_SNAKE_CASE__			,     SCREAMING_SNAKE_CASE__				):
                              assign(SCREAMING_SNAKE_CASE__			,     da[k]				)
                         else:
                              if _add_into_out:
                                   v[i : i + chunk_size] += da[k]
                              else:
                                   __UpperCamelCase    							=da[k]

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

          i += chunk_size

     __UpperCamelCase    							=tensor_tree_map(lambda SCREAMING_SNAKE_CASE__				: t.view(orig_batch_dims + t.shape[1:]				)			,     SCREAMING_SNAKE_CASE__				)

     return out






class     UpperCAmelCase__       :



    """simple docstring"""






    def __init__(			self					,   A_ = 512					,   )  ->       Tuple:
         __UpperCamelCase    							=max_chunk_size
         __UpperCamelCase    							=None
         __UpperCamelCase    							=None






    def _a					(			self					,   A_					,   A_					,   A_    )  ->       int:
         logging.info('Tuning chunk size...'    )

         if min_chunk_size >= self.max_chunk_size:
              return min_chunk_size

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

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

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

         return candidates[min_viable_chunk_size_index]






    def _a					(			self					,   A_					,   A_    )  ->       bool:
         __UpperCamelCase    							=True
         for aa, aa in zip(A_					,   A_    ):
              assert type(A_    ) == type(A_    )
              if isinstance(A_					,   (list, tuple)    ):
                   consistent &= self._compare_arg_caches(A_					,   A_    )
              elif isinstance(A_					,   A_    ):
                   __UpperCamelCase    							=[v for _, v in sorted(aa.items()					,   key=lambda A_    : x[0]    )]
                   __UpperCamelCase    							=[v for _, v in sorted(aa.items()					,   key=lambda A_    : x[0]    )]
                   consistent &= self._compare_arg_caches(A_					,   A_    )
              else:
                   consistent &= aa == aa

         return consistent






    def _a					(			self					,   A_					,   A_					,   A_					,   )  ->       int:
         __UpperCamelCase    							=True
         __UpperCamelCase    							=tree_map(lambda A_    : a.shape if isinstance(A_					,   torch.Tensor    ) else a					,   A_					,   A_    )
         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(A_    )
              __UpperCamelCase    							=self._compare_arg_caches(self.cached_arg_data					,   A_    )
         else:
              # Otherwise, we can reuse the precomputed value
              __UpperCamelCase    							=False

         if not consistent:
              __UpperCamelCase    							=self._determine_favorable_chunk_size(
                  A_					,   A_					,   A_					,   )
              __UpperCamelCase    							=arg_data

         assert self.cached_chunk_size is not None

         return self.cached_chunk_size









from typing import Dict, List, Optional, Union

import numpy as np

from ...image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
from ...image_transforms import (
    center_crop,
    convert_to_rgb,
    get_resize_output_image_size,
    normalize,
    rescale,
    resize,
    to_channel_dimension_format,
)
from ...image_utils import (
    OPENAI_CLIP_MEAN,
    OPENAI_CLIP_STD,
    ChannelDimension,
    ImageInput,
    PILImageResampling,
    make_list_of_images,
    to_numpy_array,
    valid_images,
)
from ...utils import TensorType, is_vision_available, logging


_A		       =						logging.get_logger(__name__)


if is_vision_available():
   import PIL






class     UpperCAmelCase__       (					A_		):



    """simple docstring"""






    UpperCAmelCase__						:		Union[str, Any]      =  ["pixel_values"]






    def __init__(			self					,   A_ = True					,   A_ = None					,   A_ = PILImageResampling.BICUBIC					,   A_ = True					,   A_ = None					,   A_ = True					,   A_ = 1 / 255					,   A_ = True					,   A_ = None					,   A_ = None					,   A_ = True					,   **A_					,   )  ->       None:
         super().__init__(**A_    )
         __UpperCamelCase    							=size if size is not None else {'shortest_edge': 224}
         __UpperCamelCase    							=get_size_dict(A_					,   default_to_square=A_    )
         __UpperCamelCase    							=crop_size if crop_size is not None else {'height': 224, 'width': 224}
         __UpperCamelCase    							=get_size_dict(A_					,   default_to_square=A_					,   param_name='crop_size'    )

         __UpperCamelCase    							=do_resize
         __UpperCamelCase    							=size
         __UpperCamelCase    							=resample
         __UpperCamelCase    							=do_center_crop
         __UpperCamelCase    							=crop_size
         __UpperCamelCase    							=do_rescale
         __UpperCamelCase    							=rescale_factor
         __UpperCamelCase    							=do_normalize
         __UpperCamelCase    							=image_mean if image_mean is not None else OPENAI_CLIP_MEAN
         __UpperCamelCase    							=image_std if image_std is not None else OPENAI_CLIP_STD
         __UpperCamelCase    							=do_convert_rgb






    def _a					(			self					,   A_					,   A_					,   A_ = PILImageResampling.BICUBIC					,   A_ = None					,   **A_					,   )  ->       np.ndarray:
         __UpperCamelCase    							=get_size_dict(A_					,   default_to_square=A_    )
         if "shortest_edge" not in size:
              raise ValueError(f'The `size` parameter must contain the key `shortest_edge`. Got {size.keys()}'    )
         __UpperCamelCase    							=get_resize_output_image_size(A_					,   size=size['shortest_edge']					,   default_to_square=A_    )
         return resize(A_					,   size=A_					,   resample=A_					,   data_format=A_					,   **A_    )






    def _a					(			self					,   A_					,   A_					,   A_ = None					,   **A_					,   )  ->       np.ndarray:
         __UpperCamelCase    							=get_size_dict(A_    )
         if "height" not in size or "width" not in size:
              raise ValueError(f'The `size` parameter must contain the keys (height, width). Got {size.keys()}'    )
         return center_crop(A_					,   size=(size['height'], size['width'])					,   data_format=A_					,   **A_    )






    def _a					(			self					,   A_					,   A_					,   A_ = None					,   **A_					,   )  ->       Union[str, Any]:
         return rescale(A_					,   scale=A_					,   data_format=A_					,   **A_    )






    def _a					(			self					,   A_					,   A_					,   A_					,   A_ = None					,   **A_					,   )  ->       np.ndarray:
         return normalize(A_					,   mean=A_					,   std=A_					,   data_format=A_					,   **A_    )






    def _a					(			self					,   A_					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = None					,   A_ = ChannelDimension.FIRST					,   **A_					,   )  ->       PIL.Image.Image:
         __UpperCamelCase    							=do_resize if do_resize is not None else self.do_resize
         __UpperCamelCase    							=size if size is not None else self.size
         __UpperCamelCase    							=get_size_dict(A_					,   param_name='size'					,   default_to_square=A_    )
         __UpperCamelCase    							=resample if resample is not None else self.resample
         __UpperCamelCase    							=do_center_crop if do_center_crop is not None else self.do_center_crop
         __UpperCamelCase    							=crop_size if crop_size is not None else self.crop_size
         __UpperCamelCase    							=get_size_dict(A_					,   param_name='crop_size'					,   default_to_square=A_    )
         __UpperCamelCase    							=do_rescale if do_rescale is not None else self.do_rescale
         __UpperCamelCase    							=rescale_factor if rescale_factor is not None else self.rescale_factor
         __UpperCamelCase    							=do_normalize if do_normalize is not None else self.do_normalize
         __UpperCamelCase    							=image_mean if image_mean is not None else self.image_mean
         __UpperCamelCase    							=image_std if image_std is not None else self.image_std
         __UpperCamelCase    							=do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb

         __UpperCamelCase    							=make_list_of_images(A_    )

         if not valid_images(A_    ):
              raise ValueError(
                  'Invalid image type. Must be of type PIL.Image.Image, numpy.ndarray, '
                  'torch.Tensor, tf.Tensor or jax.ndarray.'    )

         if do_resize and size is None:
              raise ValueError('Size must be specified if do_resize is True.'    )

         if do_center_crop and crop_size is None:
              raise ValueError('Crop size must be specified if do_center_crop is True.'    )

         if do_rescale and rescale_factor is None:
              raise ValueError('Rescale factor must be specified if do_rescale is True.'    )

         if do_normalize and (image_mean is None or image_std is None):
              raise ValueError('Image mean and std must be specified if do_normalize is True.'    )

         # PIL RGBA images are converted to RGB
         if do_convert_rgb:
              __UpperCamelCase    							=[convert_to_rgb(A_    ) for image in images]

         # All transformations expect numpy arrays.
         __UpperCamelCase    							=[to_numpy_array(A_    ) for image in images]

         if do_resize:
              __UpperCamelCase    							=[self.resize(image=A_					,   size=A_					,   resample=A_    ) for image in images]

         if do_center_crop:
              __UpperCamelCase    							=[self.center_crop(image=A_					,   size=A_    ) for image in images]

         if do_rescale:
              __UpperCamelCase    							=[self.rescale(image=A_					,   scale=A_    ) for image in images]

         if do_normalize:
              __UpperCamelCase    							=[self.normalize(image=A_					,   mean=A_					,   std=A_    ) for image in images]

         __UpperCamelCase    							=[to_channel_dimension_format(A_					,   A_    ) for image in images]

         __UpperCamelCase    							={'pixel_values': images}
         return BatchFeature(data=A_					,   tensor_type=A_    )





