






'''simple docstring'''







import logging
import random

import ray

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


UpperCamelCase    :      Optional[Any]  			=		logging.getLogger(__name__)




class 		UpperCamelCase__    :




		'''simple docstring'''





		def __init__(      self       ):
								lowerCamelCase__         =  False






		def 			UpperCamelCase_					(      self   ,_lowerCAmelCase   ,_lowerCAmelCase   ,_lowerCAmelCase   ,_lowerCAmelCase       ):
								if not self.initialized:
														lowerCamelCase__         =  RagRetriever(
														    _lowerCAmelCase   ,question_encoder_tokenizer=_lowerCAmelCase   ,generator_tokenizer=_lowerCAmelCase   ,index=_lowerCAmelCase   ,init_retrieval=_lowerCAmelCase   ,)
														lowerCamelCase__         =  True






		def 			UpperCamelCase_					(      self       ):
								self.retriever.index.init_index()






		def 			UpperCamelCase_					(      self   ,_lowerCAmelCase   ,_lowerCAmelCase       ):
								lowerCamelCase__       ,			lowerCamelCase__         =  self.retriever._main_retrieve(_lowerCAmelCase   ,_lowerCAmelCase       )
								return doc_ids, retrieved_doc_embeds




class 		UpperCamelCase__    (a			):




		'''simple docstring'''





		def __init__(      self   ,_lowerCAmelCase   ,_lowerCAmelCase   ,_lowerCAmelCase   ,_lowerCAmelCase   ,_lowerCAmelCase=None       ):
								if index is not None and index.is_initialized() and len(_lowerCAmelCase       ) > 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__(
								    _lowerCAmelCase   ,question_encoder_tokenizer=_lowerCAmelCase   ,generator_tokenizer=_lowerCAmelCase   ,index=_lowerCAmelCase   ,init_retrieval=_lowerCAmelCase   ,)
								lowerCamelCase__         =  retrieval_workers
								if len(self.retrieval_workers       ) > 0:
														ray.get(
														    [
														        worker.create_rag_retriever.remote(_lowerCAmelCase   ,_lowerCAmelCase   ,_lowerCAmelCase   ,_lowerCAmelCase       )
														        for worker in self.retrieval_workers
														    ]       )






		def 			UpperCamelCase_					(      self       ):
								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 			UpperCamelCase_					(      self   ,_lowerCAmelCase   ,_lowerCAmelCase       ):
								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(_lowerCAmelCase   ,_lowerCAmelCase       )       )
								else:
														lowerCamelCase__       ,			lowerCamelCase__         =  self._main_retrieve(_lowerCAmelCase   ,_lowerCAmelCase       )
								return retrieved_doc_embeds, doc_ids, self.index.get_doc_dicts(_lowerCAmelCase       )






		@classmethod
		def 			UpperCamelCase_					(      cls   ,_lowerCAmelCase   ,_lowerCAmelCase=None   ,**_lowerCAmelCase       ):
								return super(_lowerCAmelCase   ,cls       ).get_tokenizers(_lowerCAmelCase   ,_lowerCAmelCase   ,**_lowerCAmelCase       )






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









'''simple docstring'''







UpperCamelCase    :      Tuple  			=		[sum(int(c, 10) ** 2 for c in i.__str__()) for i in range(10_00_00)]
def 						A__			(				__lowerCAmelCase		:			int						):
						lowerCamelCase__         =  0
						while number:
												# Increased Speed Slightly by checking every 5 digits together.
												sum_of_digits_squared += DIGITS_SQUARED[number % 10_0000]
												number //= 10_0000

						return sum_of_digits_squared


# There are 2 Chains made,
# One ends with 89 with the chain member 58 being the one which when declared first,
# there will be the least number of iterations for all the members to be checked.

# The other one ends with 1 and has only one element 1.

# So 58 and 1 are chosen to be declared at the starting.

# Changed dictionary to an array to quicken the solution
UpperCamelCase    :      list[bool | None]  			=		[None] * 10_00_00_00
UpperCamelCase    :      Tuple  			=		True
UpperCamelCase    :      Optional[int]  			=		False
def 						A__			(				__lowerCAmelCase		:			int						):

						if CHAINS[number - 1] is not None:
												return CHAINS[number - 1]  # type: ignore

						lowerCamelCase__         =  chain(next_number(__lowerCAmelCase						)						)
						lowerCamelCase__         =  number_chain

						while number < 1000_0000:
												lowerCamelCase__         =  number_chain
												number *= 10

						return number_chain
def 						A__			(				__lowerCAmelCase		:			int = 1000_0000						):
						for i in range(1   ,    __lowerCAmelCase						):
												if CHAINS[i] is None:
																		chain(i + 1						)

						return CHAINS[:number].count(__lowerCAmelCase						)


if __name__ == "__main__":
							import doctest

							doctest.testmod()
							print(F'{solution() = }')

