





'''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 			_lowerCAmelCase     (    __snake_case    :					Union[dict, list, tuple, torch.Tensor]     )	->	List[Tuple[int, ...]]:
     __A		:					Optional[Any]						=			[]
     if isinstance(_snake_case					,				_snake_case     ):
          for v in tree.values():
               shapes.extend(_fetch_dims(_snake_case     )     )
     elif isinstance(_snake_case					,				(list, tuple)     ):
          for t in tree:
               shapes.extend(_fetch_dims(_snake_case     )     )
     elif isinstance(_snake_case					,				torch.Tensor     ):
          shapes.append(tree.shape     )
     else:
          raise ValueError('Not supported'     )

     return shapes






@torch.jit.ignore
def 			_lowerCAmelCase     (    __snake_case    :					int					,				__snake_case    :					Tuple[int, ...]     )	->	Tuple[int, ...]:
     __A		:					Optional[Any]						=			[]
     for d in reversed(_snake_case     ):
          idx.append(flat_idx % d     )
          __A		:					List[Any]						=			flat_idx // d

     return tuple(reversed(_snake_case     )     )






@torch.jit.ignore
def 			_lowerCAmelCase     (    __snake_case    :					Sequence[int]					,				__snake_case    :					Sequence[int]					,				__snake_case    :					Sequence[int]					,				__snake_case    :					Optional[Sequence[bool]] = None					,				__snake_case    :					Optional[Sequence[bool]] = None					,				)	->	List[Tuple[slice, ...]]:

     # 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(__snake_case    :					List[bool]     ) -> None:
          __A		:					Any						=			True
          for i in range(len(_snake_case     )     ):
               __A		:					str						=			-1 * (i + 1)
               l[reversed_idx] &= tally
               __A		:					Optional[int]						=			l[reversed_idx]

     if start_edges is None:
          __A		:					Optional[Any]						=			[s == 0 for s in start]
          reduce_edge_list(_snake_case     )
     if end_edges is None:
          __A		:					Optional[int]						=			[e == (d - 1) for e, d in zip(_snake_case					,				_snake_case     )]
          reduce_edge_list(_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(_snake_case     ) == 0:
          return [()]
     elif len(_snake_case     ) == 1:
          return [(slice(start[0]					,				end[0] + 1     ),)]

     __A		:					Tuple						=			[]
     __A		:					Optional[Any]						=			[]

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

     __A		:					str						=			tuple(_snake_case     )
     __A		:					List[str]						=			len(_snake_case     )

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

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

          __A		:					Optional[int]						=			start[divergence_idx]
          return tuple(
              path + (slice(_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

          __A		:					int						=			end[divergence_idx]
          return tuple(
              path + (slice(_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()     )
          __A		:					Optional[int]						=			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     (    __snake_case    :					torch.Tensor					,				__snake_case    :					int					,				__snake_case    :					int					,				__snake_case    :					int     )	->	torch.Tensor:
     __A		:					Union[str, Any]						=			t.shape[:no_batch_dims]
     __A		:					str						=			list(_flat_idx_to_idx(_snake_case					,				_snake_case     )     )
     # _get_minimal_slice_set is inclusive
     __A		:					Any						=			list(_flat_idx_to_idx(flat_end - 1					,				_snake_case     )     )

     # Get an ordered list of slices to perform
     __A		:					Any						=			_get_minimal_slice_set(
         _snake_case					,				_snake_case					,				_snake_case					,				)

     __A		:					int						=			[t[s] for s in slices]

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






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

     __A		:					List[Any]						=			[shape[:no_batch_dims] for shape in _fetch_dims(_snake_case     )]
     __A		:					Dict						=			tuple([max(_snake_case     ) for s in zip(*_snake_case     )]     )

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

     __A		:					Union[str, Any]						=			tensor_tree_map(_prep_inputs					,				_snake_case     )
     __A		:					Union[str, Any]						=			None
     if _out is not None:
          __A		:					Tuple						=			tensor_tree_map(lambda __snake_case     : t.view([-1] + list(t.shape[no_batch_dims:]     )     )					,				_out     )

     __A		:					Optional[Any]						=			1
     for d in orig_batch_dims:
          flat_batch_dim *= d

     __A		:					Optional[Any]						=			flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

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

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

          __A		:					List[str]						=			tensor_tree_map(_snake_case					,				_snake_case     )

          # Run the layer on the chunk
          __A		:					int						=			layer(**_snake_case     )

          # Allocate space for the output
          if out is None:
               __A		:					Optional[Any]						=			tensor_tree_map(lambda __snake_case     : t.new_zeros((flat_batch_dim,) + t.shape[1:]     )					,				_snake_case     )

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

               def assign(__snake_case    :					dict					,				__snake_case    :					dict     ) -> None:
                    for k, v in da.items():
                         if isinstance(_snake_case					,				_snake_case     ):
                              assign(_snake_case					,				da[k]     )
                         else:
                              if _add_into_out:
                                   v[i : i + chunk_size] += da[k]
                              else:
                                   __A		:					Optional[int]						=			da[k]

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

          i += chunk_size

     __A		:					str						=			tensor_tree_map(lambda __snake_case     : t.view(orig_batch_dims + t.shape[1:]     )					,				_snake_case     )

     return out







class 					SCREAMING_SNAKE_CASE       :


     def __init__(		self		,      _UpperCAmelCase = 512		,      ):

          '''simple docstring'''






          __A		:					Union[str, Any]						=			max_chunk_size
          __A		:					int						=			None
          __A		:					int						=			None


     def 				SCREAMING_SNAKE_CASE    (		self		,      _UpperCAmelCase		,      _UpperCAmelCase		,      _UpperCAmelCase):

          '''simple docstring'''






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

          if min_chunk_size >= self.max_chunk_size:
               return min_chunk_size

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

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

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

          return candidates[min_viable_chunk_size_index]


     def 				SCREAMING_SNAKE_CASE    (		self		,      _UpperCAmelCase		,      _UpperCAmelCase):

          '''simple docstring'''






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

          return consistent


     def 				SCREAMING_SNAKE_CASE    (		self		,      _UpperCAmelCase		,      _UpperCAmelCase		,      _UpperCAmelCase		,      ):

          '''simple docstring'''






          __A		:					List[Any]						=			True
          __A		:					List[Any]						=			tree_map(lambda _UpperCAmelCase: a.shape if isinstance(__lowerCAmelCase		,      torch.Tensor) else a		,      __lowerCAmelCase		,      __lowerCAmelCase)
          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(__lowerCAmelCase)
               __A		:					Optional[Any]						=			self._compare_arg_caches(self.cached_arg_data		,      __lowerCAmelCase)
          else:
               # Otherwise, we can reuse the precomputed value
               __A		:					Optional[Any]						=			False

          if not consistent:
               __A		:					List[str]						=			self._determine_favorable_chunk_size(
                   __lowerCAmelCase		,      __lowerCAmelCase		,      __lowerCAmelCase		,      )
               __A		:					Union[str, Any]						=			arg_data

          assert self.cached_chunk_size is not None

          return self.cached_chunk_size




import unittest

from transformers import is_vision_available
from transformers.pipelines import pipeline
from transformers.testing_utils import (
    is_pipeline_test,
    nested_simplify,
    require_tf,
    require_torch,
    require_vision,
    slow,
)

from .test_pipelines_common import ANY


if is_vision_available():
   from PIL import Image
else:


   class 	lowerCamelCase__	:



    """simple docstring"""

    @staticmethod
    def     snake_case_      (    *__lowerCAmelCase					:					Optional[Any]			,						**__lowerCAmelCase					:					Any      )   ->	Any:
       pass


@is_pipeline_test
@require_vision
class 	lowerCamelCase__	(       unittest.TestCase):



 """simple docstring"""

 @require_torch
 def     snake_case_      (    self					:					Tuple      )   ->	Tuple:
    _A      =       pipeline(
        model='''hf-internal-testing/tiny-random-clip-zero-shot-image-classification'''			,						)
    _A      =       Image.open('''./tests/fixtures/tests_samples/COCO/000000039769.png'''      )
    _A      =       image_classifier(__lowerCAmelCase			,						candidate_labels=['''a''', '''b''', '''c''']      )

    # The floating scores are so close, we enter floating error approximation and the order is not guaranteed across
    # python and torch versions.
    self.assertIn(
        nested_simplify(__lowerCAmelCase      )			,						[
            [{'''score''': 0.333, '''label''': '''a'''}, {'''score''': 0.333, '''label''': '''b'''}, {'''score''': 0.333, '''label''': '''c'''}],
            [{'''score''': 0.333, '''label''': '''a'''}, {'''score''': 0.333, '''label''': '''c'''}, {'''score''': 0.333, '''label''': '''b'''}],
        ]			,						)

    _A      =       image_classifier([image] * 5			,						candidate_labels=['''A''', '''B''', '''C''']			,						batch_size=2      )
    self.assertEqual(
        nested_simplify(__lowerCAmelCase      )			,						[
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
        ]			,						)

 @require_tf
 def     snake_case_      (    self					:					int      )   ->	Optional[int]:
    _A      =       pipeline(
        model='''hf-internal-testing/tiny-random-clip-zero-shot-image-classification'''			,						framework='''tf'''      )
    _A      =       Image.open('''./tests/fixtures/tests_samples/COCO/000000039769.png'''      )
    _A      =       image_classifier(__lowerCAmelCase			,						candidate_labels=['''a''', '''b''', '''c''']      )

    self.assertEqual(
        nested_simplify(__lowerCAmelCase      )			,						[{'''score''': 0.333, '''label''': '''a'''}, {'''score''': 0.333, '''label''': '''b'''}, {'''score''': 0.333, '''label''': '''c'''}]			,						)

    _A      =       image_classifier([image] * 5			,						candidate_labels=['''A''', '''B''', '''C''']			,						batch_size=2      )
    self.assertEqual(
        nested_simplify(__lowerCAmelCase      )			,						[
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
            [
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
                {'''score''': 0.333, '''label''': ANY(__lowerCAmelCase      )},
            ],
        ]			,						)

 @slow
 @require_torch
 def     snake_case_      (    self					:					Optional[int]      )   ->	int:
    _A      =       pipeline(
        task='''zero-shot-image-classification'''			,						model='''openai/clip-vit-base-patch32'''			,						)
    # This is an image of 2 cats with remotes and no planes
    _A      =       Image.open('''./tests/fixtures/tests_samples/COCO/000000039769.png'''      )
    _A      =       image_classifier(__lowerCAmelCase			,						candidate_labels=['''cat''', '''plane''', '''remote''']      )

    self.assertEqual(
        nested_simplify(__lowerCAmelCase      )			,						[
            {'''score''': 0.511, '''label''': '''remote'''},
            {'''score''': 0.485, '''label''': '''cat'''},
            {'''score''': 0.004, '''label''': '''plane'''},
        ]			,						)

    _A      =       image_classifier([image] * 5			,						candidate_labels=['''cat''', '''plane''', '''remote''']			,						batch_size=2      )
    self.assertEqual(
        nested_simplify(__lowerCAmelCase      )			,						[
            [
                {'''score''': 0.511, '''label''': '''remote'''},
                {'''score''': 0.485, '''label''': '''cat'''},
                {'''score''': 0.004, '''label''': '''plane'''},
            ],
        ]
        * 5			,						)

 @slow
 @require_tf
 def     snake_case_      (    self					:					Optional[int]      )   ->	Dict:
    _A      =       pipeline(
        task='''zero-shot-image-classification'''			,						model='''openai/clip-vit-base-patch32'''			,						framework='''tf'''      )
    # This is an image of 2 cats with remotes and no planes
    _A      =       Image.open('''./tests/fixtures/tests_samples/COCO/000000039769.png'''      )
    _A      =       image_classifier(__lowerCAmelCase			,						candidate_labels=['''cat''', '''plane''', '''remote''']      )
    self.assertEqual(
        nested_simplify(__lowerCAmelCase      )			,						[
            {'''score''': 0.511, '''label''': '''remote'''},
            {'''score''': 0.485, '''label''': '''cat'''},
            {'''score''': 0.004, '''label''': '''plane'''},
        ]			,						)

    _A      =       image_classifier([image] * 5			,						candidate_labels=['''cat''', '''plane''', '''remote''']			,						batch_size=2      )
    self.assertEqual(
        nested_simplify(__lowerCAmelCase      )			,						[
            [
                {'''score''': 0.511, '''label''': '''remote'''},
                {'''score''': 0.485, '''label''': '''cat'''},
                {'''score''': 0.004, '''label''': '''plane'''},
            ],
        ]
        * 5			,						)



