



'''simple docstring'''




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      a      (			lowerCamelCase__   ):
			'''simple docstring'''





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

			return shapes




@torch.jit.ignore
def      a      (			lowerCamelCase__						,				lowerCamelCase__   ):
			'''simple docstring'''





			A_     :						List[str]     =					[]
			for d in reversed(_a   ):
						idx.append(flat_idx % d   )
						A_     :						List[Any]     =					flat_idx // d

			return tuple(reversed(_a   )   )




@torch.jit.ignore
def      a      (			lowerCamelCase__						,				lowerCamelCase__						,				lowerCamelCase__						,				lowerCamelCase__ = None						,				lowerCamelCase__ = None						,				):
			'''simple docstring'''





			def reduce_edge_list(lowerCamelCase__   ) -> None:
						A_     :						Tuple     =					True
						for i in range(len(_a   )   ):
									A_     :						Any     =					-1 * (i + 1)
									l[reversed_idx] &= tally
									A_     :						Tuple     =					l[reversed_idx]

			if start_edges is None:
						A_     :						List[Any]     =					[s == 0 for s in start]
						reduce_edge_list(_a   )
			if end_edges is None:
						A_     :						str     =					[e == (d - 1) for e, d in zip(_a						,				_a   )]
						reduce_edge_list(_a   )

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

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

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

			A_     :						Tuple[slice, ...]     =					tuple(_a   )
			A_     :						Tuple     =					len(_a   )

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

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

						A_     :						int     =					start[divergence_idx]
						return tuple(
						    path + (slice(_a						,				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_     :						Any     =					end[divergence_idx]
						return tuple(
						    path + (slice(_a						,				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_     :						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      a      (			lowerCamelCase__						,				lowerCamelCase__						,				lowerCamelCase__						,				lowerCamelCase__   ):
			'''simple docstring'''





			A_     :						Dict     =					t.shape[:no_batch_dims]
			A_     :						List[Any]     =					list(_flat_idx_to_idx(_a						,				_a   )   )
			# _get_minimal_slice_set is inclusive
			A_     :						Tuple     =					list(_flat_idx_to_idx(flat_end - 1						,				_a   )   )

			# Get an ordered list of slices to perform
			A_     :						int     =					_get_minimal_slice_set(
			    _a						,				_a						,				_a						,				)

			A_     :						List[Any]     =					[t[s] for s in slices]

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




def      a      (			lowerCamelCase__						,				lowerCamelCase__						,				lowerCamelCase__						,				lowerCamelCase__						,				lowerCamelCase__ = False						,				lowerCamelCase__ = None						,				lowerCamelCase__ = False						,				):
			'''simple docstring'''





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

			A_     :						Tuple     =					[shape[:no_batch_dims] for shape in _fetch_dims(_a   )]
			A_     :						Dict     =					tuple([max(_a   ) for s in zip(*_a   )]   )

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

			A_     :						Dict[str, Any]     =					tensor_tree_map(_prep_inputs						,				_a   )
			A_     :						Any     =					None
			if _out is not None:
						A_     :						int     =					tensor_tree_map(lambda lowerCamelCase__   : t.view([-1] + list(t.shape[no_batch_dims:]   )   )						,				_out   )

			A_     :						Any     =					1
			for d in orig_batch_dims:
						flat_batch_dim *= d

			A_     :						str     =					flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

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

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

						A_     :						Dict[str, Any]     =					tensor_tree_map(_a						,				_a   )

						# Run the layer on the chunk
						A_     :						Optional[int]     =					layer(**_a   )

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

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

									def assign(lowerCamelCase__						,				lowerCamelCase__   ) -> None:
												for k, v in da.items():
															if isinstance(_a						,				_a   ):
																		assign(_a						,				da[k]   )
															else:
																		if _add_into_out:
																					v[i : i + chunk_size] += da[k]
																		else:
																					A_     :						Union[str, Any]     =					da[k]

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

						i += chunk_size

			A_     :						Optional[Any]     =					tensor_tree_map(lambda lowerCamelCase__   : t.view(orig_batch_dims + t.shape[1:]   )						,				_a   )

			return out







class      _lowerCAmelCase							:


	def __init__(self	,				lowercase = 512	,				):
				A_     :						int     =					max_chunk_size
				A_     :						Optional[int]     =					None
				A_     :						Optional[tuple]     =					None


	def    _a     (self	,				lowercase	,				lowercase	,				lowercase							):
				logging.info("""Tuning chunk size..."""							)

				if min_chunk_size >= self.max_chunk_size:
							return min_chunk_size

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

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

				A_     :						Union[str, Any]     =					0
				A_     :						Optional[int]     =					len(_SCREAMING_SNAKE_CASE							) - 1
				while i > min_viable_chunk_size_index:
							A_     :						Union[str, Any]     =					test_chunk_size(candidates[i]							)
							if not viable:
										A_     :						Dict     =					(min_viable_chunk_size_index + i) // 2
							else:
										A_     :						Optional[Any]     =					i
										A_     :						int     =					(i + len(_SCREAMING_SNAKE_CASE							) - 1) // 2

				return candidates[min_viable_chunk_size_index]


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

				return consistent


	def    _a     (self	,				lowercase	,				lowercase	,				lowercase	,				):
				A_     :						List[Any]     =					True
				A_     :						tuple     =					tree_map(lambda lowercase							: a.shape if isinstance(_SCREAMING_SNAKE_CASE	,				torch.Tensor							) else a	,				_SCREAMING_SNAKE_CASE	,				_SCREAMING_SNAKE_CASE							)
				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(_SCREAMING_SNAKE_CASE							)
							A_     :						Union[str, Any]     =					self._compare_arg_caches(self.cached_arg_data	,				_SCREAMING_SNAKE_CASE							)
				else:
							# Otherwise, we can reuse the precomputed value
							A_     :						List[Any]     =					False

				if not consistent:
							A_     :						List[Any]     =					self._determine_favorable_chunk_size(
							    _SCREAMING_SNAKE_CASE	,				_SCREAMING_SNAKE_CASE	,				_SCREAMING_SNAKE_CASE	,				)
							A_     :						List[str]     =					arg_data

				assert self.cached_chunk_size is not None

				return self.cached_chunk_size




'''simple docstring'''




from typing import Dict, List, Optional, Tuple, Union

import numpy as np

from ...image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
from ...image_transforms import (
    center_crop,
    flip_channel_order,
    get_resize_output_image_size,
    rescale,
    resize,
    to_channel_dimension_format,
)
from ...image_utils import (
    ChannelDimension,
    ImageInput,
    PILImageResampling,
    make_list_of_images,
    to_numpy_array,
    valid_images,
)
from ...utils import TensorType, is_torch_available, is_torch_tensor, is_vision_available, logging


if is_vision_available():
						import PIL

if is_torch_available():
						import torch


lowerCamelCase							:str       = logging.get_logger(__name__)







class      _lowerCAmelCase							(      __UpperCAmelCase			):
	__SCREAMING_SNAKE_CASE       :		Tuple		      = ['pixel_values']


	def __init__(self	,				lowercase = True	,				lowercase = None	,				lowercase = PILImageResampling.BILINEAR	,				lowercase = True	,				lowercase = 1 / 255	,				lowercase = True	,				lowercase = None	,				lowercase = True	,				**lowercase	,				):
				super().__init__(**lowercase							)
				A_     :						Union[str, Any]     =					size if size is not None else {"""shortest_edge""": 224}
				A_     :						Union[str, Any]     =					get_size_dict(lowercase	,				default_to_square=lowercase							)
				A_     :						Optional[Any]     =					crop_size if crop_size is not None else {"""height""": 256, """width""": 256}
				A_     :						Tuple     =					get_size_dict(lowercase	,				param_name="""crop_size"""							)

				A_     :						List[Any]     =					do_resize
				A_     :						List[str]     =					size
				A_     :						Dict     =					resample
				A_     :						int     =					do_rescale
				A_     :						str     =					rescale_factor
				A_     :						Tuple     =					do_center_crop
				A_     :						Tuple     =					crop_size
				A_     :						List[str]     =					do_flip_channel_order


	def    _a     (self	,				lowercase	,				lowercase	,				lowercase = PIL.Image.BILINEAR	,				lowercase = None	,				**lowercase	,				):
				A_     :						Any     =					get_size_dict(lowercase	,				default_to_square=lowercase							)
				if "shortest_edge" not in size:
							raise ValueError(F'The `size` dictionary must contain the key `shortest_edge`. Got {size.keys()}'							)
				A_     :						Any     =					get_resize_output_image_size(lowercase	,				size=size["""shortest_edge"""]	,				default_to_square=lowercase							)
				return resize(lowercase	,				size=lowercase	,				resample=lowercase	,				data_format=lowercase	,				**lowercase							)


	def    _a     (self	,				lowercase	,				lowercase	,				lowercase = None	,				**lowercase	,				):
				A_     :						Tuple     =					get_size_dict(lowercase							)
				if "height" not in size or "width" not in size:
							raise ValueError(F'The `size` dictionary must contain the keys `height` and `width`. Got {size.keys()}'							)
				return center_crop(lowercase	,				size=(size["""height"""], size["""width"""])	,				data_format=lowercase	,				**lowercase							)


	def    _a     (self	,				lowercase	,				lowercase	,				lowercase = None	,				**lowercase	,				):
				return rescale(lowercase	,				scale=lowercase	,				data_format=lowercase	,				**lowercase							)


	def    _a     (self	,				lowercase	,				lowercase = None							):
				return flip_channel_order(lowercase	,				data_format=lowercase							)


	def    _a     (self	,				lowercase	,				lowercase = None	,				lowercase = None	,				lowercase = None	,				lowercase = None	,				lowercase = None	,				lowercase = None	,				lowercase = None	,				lowercase = None	,				lowercase = None	,				lowercase = ChannelDimension.FIRST	,				**lowercase	,				):
				A_     :						str     =					do_resize if do_resize is not None else self.do_resize
				A_     :						Optional[int]     =					resample if resample is not None else self.resample
				A_     :						str     =					do_rescale if do_rescale is not None else self.do_rescale
				A_     :						str     =					rescale_factor if rescale_factor is not None else self.rescale_factor
				A_     :						str     =					do_center_crop if do_center_crop is not None else self.do_center_crop
				A_     :						Dict     =					(
				    do_flip_channel_order if do_flip_channel_order is not None else self.do_flip_channel_order
				)

				A_     :						Union[str, Any]     =					size if size is not None else self.size
				A_     :						Dict     =					get_size_dict(lowercase	,				default_to_square=lowercase							)
				A_     :						Any     =					crop_size if crop_size is not None else self.crop_size
				A_     :						Union[str, Any]     =					get_size_dict(lowercase	,				param_name="""crop_size"""							)

				A_     :						Union[str, Any]     =					make_list_of_images(lowercase							)

				if not valid_images(lowercase							):
							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_rescale and rescale_factor is None:
							raise ValueError("""Rescale factor must be specified if do_rescale is True."""							)

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

				# All transformations expect numpy arrays.
				A_     :						Optional[Any]     =					[to_numpy_array(lowercase							) for image in images]

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

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

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

				# the pretrained checkpoints assume images are BGR, not RGB
				if do_flip_channel_order:
							A_     :						List[str]     =					[self.flip_channel_order(image=lowercase							) for image in images]

				A_     :						List[str]     =					[to_channel_dimension_format(lowercase	,				lowercase							) for image in images]

				A_     :						str     =					{"""pixel_values""": images}
				return BatchFeature(data=lowercase	,				tensor_type=lowercase							)


	def    _a     (self	,				lowercase	,				lowercase = None							):
				A_     :						Optional[Any]     =					outputs.logits

				# Resize logits and compute semantic segmentation maps
				if target_sizes is not None:
							if len(lowercase							) != len(lowercase							):
										raise ValueError(
										    """Make sure that you pass in as many target sizes as the batch dimension of the logits"""							)

							if is_torch_tensor(lowercase							):
										A_     :						Dict     =					target_sizes.numpy()

							A_     :						Union[str, Any]     =					[]

							for idx in range(len(lowercase							)							):
										A_     :						Union[str, Any]     =					torch.nn.functional.interpolate(
										    logits[idx].unsqueeze(dim=0							)	,				size=target_sizes[idx]	,				mode="""bilinear"""	,				align_corners=lowercase							)
										A_     :						Any     =					resized_logits[0].argmax(dim=0							)
										semantic_segmentation.append(lowercase							)
				else:
							A_     :						str     =					logits.argmax(dim=1							)
							A_     :						Optional[Any]     =					[semantic_segmentation[i] for i in range(semantic_segmentation.shape[0]							)]

				return semantic_segmentation