





"""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 					lowercase__    (					lowercase_			)					->		List[Tuple[int, ...]]:




      """simple docstring"""

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

      return shapes




@torch.jit.ignore
def 					lowercase__    (					lowercase_		,lowercase_			)					->		Tuple[int, ...]:




      """simple docstring"""

      _UpperCamelCase      :	Any						=       []
      for d in reversed(lowercase_			):
            idx.append(flat_idx % d			)
            _UpperCamelCase      :	Dict						=       flat_idx // d

      return tuple(reversed(lowercase_			)			)




@torch.jit.ignore
def 					lowercase__    (					lowercase_		,lowercase_		,lowercase_		,lowercase_ = None		,lowercase_ = None		,)					->		List[Tuple[slice, ...]]:




      """simple docstring"""

      def reduce_edge_list(lowercase_			) -> None:
            _UpperCamelCase      :	List[Any]						=       True
            for i in range(len(lowercase_			)			):
                  _UpperCamelCase      :	Dict						=       -1 * (i + 1)
                  l[reversed_idx] &= tally
                  _UpperCamelCase      :	str						=       l[reversed_idx]

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

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

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

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

      _UpperCamelCase      :	Tuple[slice, ...]						=       tuple(lowercase_			)
      _UpperCamelCase      :	List[Any]						=       len(lowercase_			)

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

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

            _UpperCamelCase      :	int						=       start[divergence_idx]
            return tuple(
                path + (slice(lowercase_		,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      :	Optional[Any]						=       end[divergence_idx]
            return tuple(
                path + (slice(lowercase_		,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      :	Any						=       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 					lowercase__    (					lowercase_		,lowercase_		,lowercase_		,lowercase_			)					->		torch.Tensor:




      """simple docstring"""

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

      # Get an ordered list of slices to perform
      _UpperCamelCase      :	Dict						=       _get_minimal_slice_set(
          lowercase_		,lowercase_		,lowercase_		,)

      _UpperCamelCase      :	Optional[Any]						=       [t[s] for s in slices]

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




def 					lowercase__    (					lowercase_		,lowercase_		,lowercase_		,lowercase_		,lowercase_ = False		,lowercase_ = None		,lowercase_ = False		,)					->		Any:




      """simple docstring"""

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

      _UpperCamelCase      :	int						=       [shape[:no_batch_dims] for shape in _fetch_dims(lowercase_			)]
      _UpperCamelCase      :	List[Any]						=       tuple([max(lowercase_			) for s in zip(*lowercase_			)]			)

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

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

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

      _UpperCamelCase      :	Dict						=       flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

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

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

            _UpperCamelCase      :	Dict[str, Any]						=       tensor_tree_map(lowercase_		,lowercase_			)

            # Run the layer on the chunk
            _UpperCamelCase      :	List[str]						=       layer(**lowercase_			)

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

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

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

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

            i += chunk_size

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

      return out



class      __SCREAMING_SNAKE_CASE    :







  '''simple docstring'''


  def __init__(		self   :       Optional[int]					,   __a   :       int = 512					,   )		->				Optional[Any]:
        _UpperCamelCase      :	Optional[Any]						=       max_chunk_size
        _UpperCamelCase      :	Optional[int]						=       None
        _UpperCamelCase      :	Optional[tuple]						=       None

  def    __SCREAMING_SNAKE_CASE				(		self   :       List[Any]					,   __a   :       Callable					,   __a   :       tuple					,   __a   :       int	)		->				int:
        logging.info("Tuning chunk size..."	)

        if min_chunk_size >= self.max_chunk_size:
              return min_chunk_size

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

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

        _UpperCamelCase      :	Tuple						=       0
        _UpperCamelCase      :	Tuple						=       len(__a	) - 1
        while i > min_viable_chunk_size_index:
              _UpperCamelCase      :	int						=       test_chunk_size(candidates[i]	)
              if not viable:
                    _UpperCamelCase      :	Dict						=       (min_viable_chunk_size_index + i) // 2
              else:
                    _UpperCamelCase      :	List[str]						=       i
                    _UpperCamelCase      :	int						=       (i + len(__a	) - 1) // 2

        return candidates[min_viable_chunk_size_index]

  def    __SCREAMING_SNAKE_CASE				(		self   :       List[Any]					,   __a   :       Iterable					,   __a   :       Iterable	)		->				bool:
        _UpperCamelCase      :	Optional[Any]						=       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      :	List[Any]						=       [v for _, v in sorted(aa.items()					,   key=lambda __a	: x[0]	)]
                    _UpperCamelCase      :	Tuple						=       [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    __SCREAMING_SNAKE_CASE				(		self   :       str					,   __a   :       Callable					,   __a   :       tuple					,   __a   :       int					,   )		->				int:
        _UpperCamelCase      :	Dict						=       True
        _UpperCamelCase      :	tuple						=       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      :	Any						=       self._compare_arg_caches(self.cached_arg_data					,   __a	)
        else:
              # Otherwise, we can reuse the precomputed value
              _UpperCamelCase      :	Optional[int]						=       False

        if not consistent:
              _UpperCamelCase      :	Optional[Any]						=       self._determine_favorable_chunk_size(
                  __a					,   __a					,   __a					,   )
              _UpperCamelCase      :	int						=       arg_data

        assert self.cached_chunk_size is not None

        return self.cached_chunk_size







"""simple docstring"""


from dataclasses import dataclass, field
from typing import ClassVar, Dict

from ..features import Features, Value
from .base import TaskTemplate



@dataclass(frozen=_UpperCamelCase   )
class      __SCREAMING_SNAKE_CASE    (						_UpperCamelCase   ):







  '''simple docstring'''


  SCREAMING_SNAKE_CASE__							:str	     =					field(default="summarization"		,  metadata={"include_in_asdict_even_if_is_default": True}   )
  SCREAMING_SNAKE_CASE__							:ClassVar[Features]	     =					Features({"text": Value("string"   )}   )
  SCREAMING_SNAKE_CASE__							:ClassVar[Features]	     =					Features({"summary": Value("string"   )}   )
  SCREAMING_SNAKE_CASE__							:str	     =					"text"
  SCREAMING_SNAKE_CASE__							:str	     =					"summary"

  @property
  def    __SCREAMING_SNAKE_CASE				(		self   :       List[Any]	)		->				Dict[str, str]:
        return {self.text_column: "text", self.summary_column: "summary"}
