




"""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				(						SCREAMING_SNAKE_CASE_							:    Union[dict, list, tuple, torch.Tensor]					):
					__lowerCAmelCase           =	[]
					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      _a				(						SCREAMING_SNAKE_CASE_							:    int				,				SCREAMING_SNAKE_CASE_							:    Tuple[int, ...]					):
					__lowerCAmelCase           =	[]
					for d in reversed(SCREAMING_SNAKE_CASE_					):
										idx.append(flat_idx % d					)
										__lowerCAmelCase           =	flat_idx // d

					return tuple(reversed(SCREAMING_SNAKE_CASE_					)					)







@torch.jit.ignore
def      _a				(						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:
										__lowerCAmelCase           =	True
										for i in range(len(SCREAMING_SNAKE_CASE_					)					):
															__lowerCAmelCase           =	-1 * (i + 1)
															l[reversed_idx] &= tally
															__lowerCAmelCase           =	l[reversed_idx]

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

					__lowerCAmelCase           =	[]
					__lowerCAmelCase           =	[]

					# 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

					__lowerCAmelCase           =	tuple(SCREAMING_SNAKE_CASE_					)
					__lowerCAmelCase           =	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

										__lowerCAmelCase           =	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

										__lowerCAmelCase           =	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()					)
										__lowerCAmelCase           =	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				(						SCREAMING_SNAKE_CASE_							:    torch.Tensor				,				SCREAMING_SNAKE_CASE_							:    int				,				SCREAMING_SNAKE_CASE_							:    int				,				SCREAMING_SNAKE_CASE_							:    int					):
					__lowerCAmelCase           =	t.shape[:no_batch_dims]
					__lowerCAmelCase           =	list(_flat_idx_to_idx(SCREAMING_SNAKE_CASE_				,				SCREAMING_SNAKE_CASE_					)					)
					# _get_minimal_slice_set is inclusive
					__lowerCAmelCase           =	list(_flat_idx_to_idx(flat_end - 1				,				SCREAMING_SNAKE_CASE_					)					)

					# Get an ordered list of slices to perform
					__lowerCAmelCase           =	_get_minimal_slice_set(
					    SCREAMING_SNAKE_CASE_				,				SCREAMING_SNAKE_CASE_				,				SCREAMING_SNAKE_CASE_				,				)

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

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







def      _a				(						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"					)

					__lowerCAmelCase           =	[shape[:no_batch_dims] for shape in _fetch_dims(SCREAMING_SNAKE_CASE_					)]
					__lowerCAmelCase           =	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:
																				__lowerCAmelCase           =	t.expand(orig_batch_dims + t.shape[no_batch_dims:]					)
															__lowerCAmelCase           =	t.reshape(-1				,				*t.shape[no_batch_dims:]					)
										else:
															__lowerCAmelCase           =	t.expand(orig_batch_dims + t.shape[no_batch_dims:]					)
										return t

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

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

					__lowerCAmelCase           =	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

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

										__lowerCAmelCase           =	tensor_tree_map(SCREAMING_SNAKE_CASE_				,				SCREAMING_SNAKE_CASE_					)

										# Run the layer on the chunk
										__lowerCAmelCase           =	layer(**SCREAMING_SNAKE_CASE_					)

										# Allocate space for the output
										if out is None:
															__lowerCAmelCase           =	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:
																																			__lowerCAmelCase           =	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:
																									__lowerCAmelCase           =	xa
										elif isinstance(SCREAMING_SNAKE_CASE_				,				torch.Tensor					):
															if _add_into_out:
																				out[i : i + chunk_size] += output_chunk
															else:
																				__lowerCAmelCase           =	output_chunk
										else:
															raise ValueError("Not supported"					)

										i += chunk_size

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

					return out


class       a__   :






						def __init__(       self		,      _A = 5_1_2		,      ):




											"""simple docstring"""



											__lowerCAmelCase           =	max_chunk_size
											__lowerCAmelCase           =	None
											__lowerCAmelCase           =	None






						def     __SCREAMING_SNAKE_CASE(       self		,      _A		,      _A		,      _A      ):




											"""simple docstring"""



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

											if min_chunk_size >= self.max_chunk_size:
																return min_chunk_size

											__lowerCAmelCase           =	[2**l for l in range(int(math.log(self.max_chunk_size		,      2      )      ) + 1      )]
											__lowerCAmelCase           =	[c for c in candidates if c > min_chunk_size]
											__lowerCAmelCase           =	[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

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

											return candidates[min_viable_chunk_size_index]






						def     __SCREAMING_SNAKE_CASE(       self		,      _A		,      _A      ):




											"""simple docstring"""



											__lowerCAmelCase           =	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      ):
																					__lowerCAmelCase           =	[v for _, v in sorted(aa.items()		,      key=lambda _A      : x[0]      )]
																					__lowerCAmelCase           =	[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		,      _A		,      _A		,      _A		,      ):




											"""simple docstring"""



											__lowerCAmelCase           =	True
											__lowerCAmelCase           =	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      )
																__lowerCAmelCase           =	self._compare_arg_caches(self.cached_arg_data		,      _a      )
											else:
																# Otherwise, we can reuse the precomputed value
																__lowerCAmelCase           =	False

											if not consistent:
																__lowerCAmelCase           =	self._determine_favorable_chunk_size(
																    _a		,      _a		,      _a		,      )
																__lowerCAmelCase           =	arg_data

											assert self.cached_chunk_size is not None

											return self.cached_chunk_size










import logging
import random

import ray

from transformers import RagConfig, RagRetriever, RagTokenizer
from transformers.models.rag.retrieval_rag import CustomHFIndex


UpperCamelCase__         =      logging.getLogger(__name__)
class       a__   :






						def __init__(       self      ):




											"""simple docstring"""



											__lowerCAmelCase           =	False






						def     __SCREAMING_SNAKE_CASE(       self		,      _A		,      _A		,      _A		,      _A      ):




											"""simple docstring"""



											if not self.initialized:
																__lowerCAmelCase           =	RagRetriever(
																    _A		,      question_encoder_tokenizer=_A		,      generator_tokenizer=_A		,      index=_A		,      init_retrieval=_A		,      )
																__lowerCAmelCase           =	True






						def     __SCREAMING_SNAKE_CASE(       self      ):




											"""simple docstring"""



											self.retriever.index.init_index()






						def     __SCREAMING_SNAKE_CASE(       self		,      _A		,      _A      ):




											"""simple docstring"""



											__lowerCAmelCase       ,							__lowerCAmelCase           =	self.retriever._main_retrieve(_A		,      _A      )
											return doc_ids, retrieved_doc_embeds






class       a__   ( snake_case__				):






						def __init__(       self		,      _A		,      _A		,      _A		,      _A		,      _A=None      ):




											"""simple docstring"""



											if index is not None and index.is_initialized() and len(_A      ) > 0:
																raise ValueError(
																    "When using Ray for distributed fine-tuning, "
																    "you'll need to provide the paths instead, "
																    "as the dataset and the index are loaded "
																    "separately. More info in examples/rag/use_own_knowledge_dataset.py "      )
											super().__init__(
											    _A		,      question_encoder_tokenizer=_A		,      generator_tokenizer=_A		,      index=_A		,      init_retrieval=_A		,      )
											__lowerCAmelCase           =	retrieval_workers
											if len(self.retrieval_workers      ) > 0:
																ray.get(
																    [
																        worker.create_rag_retriever.remote(_A		,      _A		,      _A		,      _A      )
																        for worker in self.retrieval_workers
																    ]      )






						def     __SCREAMING_SNAKE_CASE(       self      ):




											"""simple docstring"""



											logger.info("initializing retrieval"      )

											if len(self.retrieval_workers      ) > 0:
																ray.get([worker.init_retrieval.remote() for worker in self.retrieval_workers]      )
											else:
																# Non-distributed training. Load index into this same process.
																self.index.init_index()






						def     __SCREAMING_SNAKE_CASE(       self		,      _A		,      _A      ):




											"""simple docstring"""



											if len(self.retrieval_workers      ) > 0:
																# Select a random retrieval actor.
																__lowerCAmelCase           =	self.retrieval_workers[random.randint(0		,      len(self.retrieval_workers      ) - 1      )]
																__lowerCAmelCase       ,							__lowerCAmelCase           =	ray.get(random_worker.retrieve.remote(_A		,      _A      )      )
											else:
																__lowerCAmelCase       ,							__lowerCAmelCase           =	self._main_retrieve(_A		,      _A      )
											return retrieved_doc_embeds, doc_ids, self.index.get_doc_dicts(_A      )






						@classmethod
						def     __SCREAMING_SNAKE_CASE(       cls		,      _A		,      _A=None		,      **_A      ):




											"""simple docstring"""



											return super(_A		,      cls      ).get_tokenizers(_A		,      _A		,      **_A      )






						@classmethod
						def     __SCREAMING_SNAKE_CASE(       cls		,      _A		,      _A		,      _A=None		,      **_A      ):




											"""simple docstring"""



											__lowerCAmelCase           =	kwargs.pop("config"		,      _A      ) or RagConfig.from_pretrained(_A		,      **_A      )
											__lowerCAmelCase           =	RagTokenizer.from_pretrained(_A		,      config=_A      )
											__lowerCAmelCase           =	rag_tokenizer.question_encoder
											__lowerCAmelCase           =	rag_tokenizer.generator
											if indexed_dataset is not None:
																__lowerCAmelCase           =	"custom"
																__lowerCAmelCase           =	CustomHFIndex(config.retrieval_vector_size		,      _A      )
											else:
																__lowerCAmelCase           =	cls._build_index(_A      )
											return cls(
											    _A		,      question_encoder_tokenizer=_A		,      generator_tokenizer=_A		,      retrieval_workers=_A		,      index=_A		,      )




