
import tensorflow as tf

from ...tf_utils import shape_list







class   lowerCamelCase	(						tf.keras.layers.Layer						):





     def __init__(self   :					str       ,					_A   :					str       ,					_A   :					int       ,					_A   :					str       ,					_A   :					Optional[Any]       ,					_A   :					List[str]=1       ,					_A   :					Union[str, Any]=False       ,					**_A   :					Optional[Any]     )		->		List[str]:
         super().__init__(**_A     )

         snake_case				  =      vocab_size
         snake_case				  =      d_embed
         snake_case				  =      d_proj

         snake_case				  =      cutoffs + [vocab_size]
         snake_case				  =      [0] + self.cutoffs
         snake_case				  =      div_val

         snake_case				  =      self.cutoffs[0]
         snake_case				  =      len(self.cutoffs     ) - 1
         snake_case				  =      self.shortlist_size + self.n_clusters
         snake_case				  =      keep_order

         snake_case				  =      []
         snake_case				  =      []





     def 	UpperCAmelCase(self   :					str       ,					_A   :					Any     )		->		Any:
         if self.n_clusters > 0:
             snake_case				  =      self.add_weight(
                 shape=(self.n_clusters, self.d_embed)       ,					initializer="zeros"       ,					trainable=_A       ,					name="cluster_weight"     )
             snake_case				  =      self.add_weight(
                 shape=(self.n_clusters,)       ,					initializer="zeros"       ,					trainable=_A       ,					name="cluster_bias"     )

         if self.div_val == 1:
             for i in range(len(self.cutoffs     )     ):
                 if self.d_proj != self.d_embed:
                     snake_case				  =      self.add_weight(
                         shape=(self.d_embed, self.d_proj)       ,					initializer="zeros"       ,					trainable=_A       ,					name=f'out_projs_._{i}'       ,					)
                     self.out_projs.append(_A     )
                 else:
                     self.out_projs.append(_A     )
                 snake_case				  =      self.add_weight(
                     shape=(self.vocab_size, self.d_embed)       ,					initializer="zeros"       ,					trainable=_A       ,					name=f'out_layers_._{i}_._weight'       ,					)
                 snake_case				  =      self.add_weight(
                     shape=(self.vocab_size,)       ,					initializer="zeros"       ,					trainable=_A       ,					name=f'out_layers_._{i}_._bias'       ,					)
                 self.out_layers.append((weight, bias)     )
         else:
             for i in range(len(self.cutoffs     )     ):
                 snake_case  ,							snake_case				  =      self.cutoff_ends[i], self.cutoff_ends[i + 1]
                 snake_case				  =      self.d_embed // (self.div_val**i)

                 snake_case				  =      self.add_weight(
                     shape=(d_emb_i, self.d_proj)       ,					initializer="zeros"       ,					trainable=_A       ,					name=f'out_projs_._{i}'     )
                 self.out_projs.append(_A     )
                 snake_case				  =      self.add_weight(
                     shape=(r_idx - l_idx, d_emb_i)       ,					initializer="zeros"       ,					trainable=_A       ,					name=f'out_layers_._{i}_._weight'       ,					)
                 snake_case				  =      self.add_weight(
                     shape=(r_idx - l_idx,)       ,					initializer="zeros"       ,					trainable=_A       ,					name=f'out_layers_._{i}_._bias'       ,					)
                 self.out_layers.append((weight, bias)     )
         super().build(_A     )





     @staticmethod
     def 	UpperCAmelCase(_A   :					List[Any]       ,					_A   :					str       ,					_A   :					List[Any]       ,					_A   :					Tuple=None     )		->		int:
         snake_case				  =      x
         if proj is not None:
             snake_case				  =      tf.einsum("ibd,ed->ibe"       ,					_A       ,					_A     )
         return tf.einsum("ibd,nd->ibn"       ,					_A       ,					_A     ) + b





     @staticmethod
     def 	UpperCAmelCase(_A   :					int       ,					_A   :					Optional[int]     )		->		int:
         snake_case				  =      shape_list(_A     )
         snake_case				  =      tf.range(lp_size[0]       ,					dtype=target.dtype     )
         snake_case				  =      tf.stack([r, target]       ,					1     )
         return tf.gather_nd(_A       ,					_A     )





     def 	UpperCAmelCase(self   :					Any       ,					_A   :					Any       ,					_A   :					Dict       ,					_A   :					Optional[Any]=True       ,					_A   :					Optional[int]=False     )		->		Any:
         snake_case				  =      0
         if self.n_clusters == 0:
             snake_case				  =      self._logit(_A       ,					self.out_layers[0][0]       ,					self.out_layers[0][1]       ,					self.out_projs[0]     )
             if target is not None:
                 snake_case				  =      tf.nn.sparse_softmax_cross_entropy_with_logits(labels=_A       ,					logits=_A     )
             snake_case				  =      tf.nn.log_softmax(_A       ,					axis=-1     )
         else:
             snake_case				  =      shape_list(_A     )
             snake_case				  =      []
             snake_case				  =      tf.zeros(hidden_sizes[:2]     )
             for i in range(len(self.cutoffs     )     ):
                 snake_case  ,							snake_case				  =      self.cutoff_ends[i], self.cutoff_ends[i + 1]
                 if target is not None:
                     snake_case				  =      (target >= l_idx) & (target < r_idx)
                     snake_case				  =      tf.where(_A     )
                     snake_case				  =      tf.boolean_mask(_A       ,					_A     ) - l_idx

                 if self.div_val == 1:
                     snake_case				  =      self.out_layers[0][0][l_idx:r_idx]
                     snake_case				  =      self.out_layers[0][1][l_idx:r_idx]
                 else:
                     snake_case				  =      self.out_layers[i][0]
                     snake_case				  =      self.out_layers[i][1]

                 if i == 0:
                     snake_case				  =      tf.concat([cur_W, self.cluster_weight]       ,					0     )
                     snake_case				  =      tf.concat([cur_b, self.cluster_bias]       ,					0     )

                     snake_case				  =      self._logit(_A       ,					_A       ,					_A       ,					self.out_projs[0]     )
                     snake_case				  =      tf.nn.log_softmax(_A     )
                     out.append(head_logprob[..., : self.cutoffs[0]]     )
                     if target is not None:
                         snake_case				  =      tf.boolean_mask(_A       ,					_A     )
                         snake_case				  =      self._gather_logprob(_A       ,					_A     )
                 else:
                     snake_case				  =      self._logit(_A       ,					_A       ,					_A       ,					self.out_projs[i]     )
                     snake_case				  =      tf.nn.log_softmax(_A     )
                     snake_case				  =      self.cutoffs[0] + i - 1  # No probability for the head cluster
                     snake_case				  =      head_logprob[..., cluster_prob_idx, None] + tail_logprob
                     out.append(_A     )
                     if target is not None:
                         snake_case				  =      tf.boolean_mask(_A       ,					_A     )
                         snake_case				  =      tf.boolean_mask(_A       ,					_A     )
                         snake_case				  =      self._gather_logprob(_A       ,					_A     )
                         cur_logprob += cur_head_logprob[:, self.cutoff_ends[1] + i - 1]
                 if target is not None:
                     loss += tf.scatter_nd(_A       ,					-cur_logprob       ,					shape_list(_A     )     )
             snake_case				  =      tf.concat(_A       ,					axis=-1     )

         if target is not None:
             if return_mean:
                 snake_case				  =      tf.reduce_mean(_A     )
             # Add the training-time loss value to the layer using `self.add_loss()`.
             self.add_loss(_A     )

             # Log the loss as a metric (we could log arbitrary metrics,
             # including different metrics for training and inference.
             self.add_metric(_A       ,					name=self.name       ,					aggregation="mean" if return_mean else ""     )

         return out



import os
from shutil import copyfile
from typing import Any, Dict, List, Optional, Tuple

import sentencepiece as spm

from ...tokenization_utils import PreTrainedTokenizer
from ...utils import logging


_A						      =				"▁"

_A						      =				{"vocab_file": "spiece.model"}

_A						      =				{
    "vocab_file": {"google/pegasus-xsum": "https://huggingface.co/google/pegasus-xsum/resolve/main/spiece.model"}
}

_A						      =				{
    "google/pegasus-xsum": 5_12,
}


_A						      =				logging.get_logger(__name__)







class   lowerCamelCase	(						A_						):
     UpperCAmelCase__       :							Tuple     =	VOCAB_FILES_NAMES

     UpperCAmelCase__       :							Tuple     =	VOCAB_FILES_NAMES
     UpperCAmelCase__       :							List[str]     =	PRETRAINED_VOCAB_FILES_MAP
     UpperCAmelCase__       :							Optional[int]     =	PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
     UpperCAmelCase__       :							Optional[Any]     =	["input_ids", "attention_mask"]





     def __init__(self   :					Optional[Any]       ,					_A   :					Any       ,					_A   :					List[Any]="<pad>"       ,					_A   :					int="</s>"       ,					_A   :					Dict="<unk>"       ,					_A   :					str="<mask_2>"       ,					_A   :					Optional[int]="<mask_1>"       ,					_A   :					Optional[Any]=None       ,					_A   :					Tuple=1_0_3       ,					_A   :					Optional[Dict[str, Any]] = None       ,					**_A   :					List[str]       ,					)		->		None:
         snake_case				  =      offset
         if additional_special_tokens is not None:
             if not isinstance(_A       ,					_A     ):
                 raise TypeError(
                     f'additional_special_tokens should be of type {type(_A     )}, but is'
                     f' {type(_A     )}'     )

             snake_case				  =      (
                 ([mask_token_sent] + additional_special_tokens)
                 if mask_token_sent not in additional_special_tokens and mask_token_sent is not None
                 else additional_special_tokens
             )
             # fill additional tokens with ..., <unk_token_102> in case not all additional tokens are already taken
             additional_special_tokens_extended += [
                 f'<unk_{i}>' for i in range(len(_A     )       ,					self.offset - 1     )
             ]

             if len(set(_A     )     ) != len(_A     ):
                 raise ValueError(
                     "Please make sure that the provided additional_special_tokens do not contain an incorrectly"
                     f' shifted list of <unk_x> tokens. Found {additional_special_tokens_extended}.'     )
             snake_case				  =      additional_special_tokens_extended
         else:
             snake_case				  =      [mask_token_sent] if mask_token_sent is not None else []
             additional_special_tokens += [f'<unk_{i}>' for i in range(2       ,					self.offset     )]

         snake_case				  =      {} if sp_model_kwargs is None else sp_model_kwargs

         super().__init__(
             eos_token=_A       ,					unk_token=_A       ,					mask_token=_A       ,					pad_token=_A       ,					mask_token_sent=_A       ,					offset=_A       ,					additional_special_tokens=_A       ,					sp_model_kwargs=self.sp_model_kwargs       ,					**_A       ,					)
         snake_case				  =      mask_token_sent
         snake_case				  =      vocab_file
         snake_case				  =      spm.SentencePieceProcessor(**self.sp_model_kwargs     )
         self.sp_model.Load(_A     )

         # add special tokens to encoder dict
         snake_case				  =      {
             0: self.pad_token,
             1: self.eos_token,
         }

         if self.mask_token_sent is not None:
             self.encoder.update(
                 {
                     2: self.mask_token_sent,
                     3: self.mask_token,
                 }     )

         if self.offset > 0:
             # entries 2-104 are only used for pretraining and called <mask_1>, <mask_2>, unk_2, ...unk_102
             # mask_token_sent is already added to list -> so start at 1
             self.encoder.update({i + 3: additional_special_tokens[i] for i in range(1       ,					self.offset - 1     )}     )

         snake_case				  =      {v: k for k, v in self.encoder.items()}





     @property
     def 	UpperCAmelCase(self   :					str     )		->		int:
         return len(self.sp_model     ) + self.offset





     def 	UpperCAmelCase(self   :					List[str]     )		->		Dict[str, int]:
         snake_case				  =      {self.convert_ids_to_tokens(_A     ): i for i in range(self.vocab_size     )}
         vocab.update(self.added_tokens_encoder     )
         return vocab





     def __getstate__(self   :					Any     )		->		List[Any]:
         snake_case				  =      self.__dict__.copy()
         snake_case				  =      None
         return state





     def __setstate__(self   :					str       ,					_A   :					Union[str, Any]     )		->		Tuple:
         snake_case				  =      d

         # for backward compatibility
         if not hasattr(self       ,					"sp_model_kwargs"     ):
             snake_case				  =      {}

         snake_case				  =      spm.SentencePieceProcessor(**self.sp_model_kwargs     )
         self.sp_model.Load(self.vocab_file     )





     def 	UpperCAmelCase(self   :					List[Any]       ,					_A   :					str     )		->		List[str]:
         return self.sp_model.encode(_A       ,					out_type=_A     )





     def 	UpperCAmelCase(self   :					List[str]       ,					_A   :					str     )		->		int:
         if token in self.decoder:
             return self.decoder[token]
         elif token in self.added_tokens_decoder:
             return self.added_tokens_decoder[token]
         snake_case				  =      self.sp_model.piece_to_id(_A     )
         return sp_id + self.offset





     def 	UpperCAmelCase(self   :					Union[str, Any]       ,					_A   :					int     )		->		str:
         if index in self.encoder:
             return self.encoder[index]
         elif index in self.added_tokens_encoder:
             return self.added_tokens_encoder[index]
         else:
             snake_case				  =      self.sp_model.IdToPiece(index - self.offset     )
         return token





     def 	UpperCAmelCase(self   :					List[Any]       ,					_A   :					Tuple     )		->		Tuple:
         snake_case				  =      []
         snake_case				  =      ""
         for token in tokens:
             # make sure that special tokens are not decoded using sentencepiece model
             if token in self.all_special_tokens:
                 out_string += self.sp_model.decode(_A     ) + token
                 snake_case				  =      []
             else:
                 current_sub_tokens.append(_A     )
         out_string += self.sp_model.decode(_A     )
         return out_string.strip()





     def 	UpperCAmelCase(self   :					List[Any]       ,					_A   :					Tuple=False     )		->		Tuple:
         return 1





     def 	UpperCAmelCase(self   :					Tuple       ,					_A   :					Optional[int]     )		->		Tuple:
         snake_case				  =      set(self.all_special_ids     )  # call it once instead of inside list comp
         all_special_ids.remove(self.unk_token_id     )  # <unk> is only sometimes special

         return [1 if x in all_special_ids else 0 for x in seq]





     def 	UpperCAmelCase(self   :					str       ,					_A   :					List       ,					_A   :					Optional[List] = None       ,					_A   :					bool = False     )		->		List[int]:
         if already_has_special_tokens:
             return self._special_token_mask(_A     )
         elif token_ids_a is None:
             return self._special_token_mask(_A     ) + [1]
         else:
             return self._special_token_mask(token_ids_a + token_ids_a     ) + [1]





     def 	UpperCAmelCase(self   :					int       ,					_A   :					Dict       ,					_A   :					List[Any]=None     )		->		List[int]:
         if token_ids_a is None:
             return token_ids_a + [self.eos_token_id]
         # We don't expect to process pairs, but leave the pair logic for API consistency
         return token_ids_a + token_ids_a + [self.eos_token_id]





     def 	UpperCAmelCase(self   :					Optional[Any]       ,					_A   :					str       ,					_A   :					Optional[str] = None     )		->		Tuple[str]:
         if not os.path.isdir(_A     ):
             logger.error(f'Vocabulary path ({save_directory}) should be a directory'     )
             return
         snake_case				  =      os.path.join(
             _A       ,					(filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]     )

         if os.path.abspath(self.vocab_file     ) != os.path.abspath(_A     ) and os.path.isfile(self.vocab_file     ):
             copyfile(self.vocab_file       ,					_A     )
         elif not os.path.isfile(self.vocab_file     ):
             with open(_A       ,					"wb"     ) as fi:
                 snake_case				  =      self.sp_model.serialized_model_proto()
                 fi.write(_A     )

         return (out_vocab_file,)

