



import tensorflow as tf

from ...tf_utils import shape_list



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

   '''simple docstring'''




   def __init__(						self  :			int			,				lowerCAmelCase  :			List[str]			,				lowerCAmelCase  :			Any			,				lowerCAmelCase  :			Dict			,				lowerCAmelCase  :			Optional[Any]			,				lowerCAmelCase  :			List[Any]=1			,				lowerCAmelCase  :			Any=False			,				**lowerCAmelCase  :			Optional[int])	->				Any:




         """simple docstring"""

         super().__init__(**_A)

         lowercase__     =  vocab_size
         lowercase__     =  d_embed
         lowercase__     =  d_proj

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

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

         lowercase__     =  []
         lowercase__     =  []


   def 			UpperCAmelCase		(						self  :			List[str]			,				lowerCAmelCase  :			List[str])	->				List[str]:




         """simple docstring"""

         if self.n_clusters > 0:
               lowercase__     =  self.add_weight(
                   shape=(self.n_clusters, self.d_embed)			,				initializer='zeros'			,				trainable=_A			,				name='cluster_weight')
               lowercase__     =  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:
                           lowercase__     =  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)
                     lowercase__     =  self.add_weight(
                         shape=(self.vocab_size, self.d_embed)			,				initializer='zeros'			,				trainable=_A			,				name=f'''out_layers_._{i}_._weight'''			,				)
                     lowercase__     =  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)):
                     lowercase__,	lowercase__     =  self.cutoff_ends[i], self.cutoff_ends[i + 1]
                     lowercase__     =  self.d_embed // (self.div_val**i)

                     lowercase__     =  self.add_weight(
                         shape=(d_emb_i, self.d_proj)			,				initializer='zeros'			,				trainable=_A			,				name=f'''out_projs_._{i}''')
                     self.out_projs.append(_A)
                     lowercase__     =  self.add_weight(
                         shape=(r_idx - l_idx, d_emb_i)			,				initializer='zeros'			,				trainable=_A			,				name=f'''out_layers_._{i}_._weight'''			,				)
                     lowercase__     =  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		(						lowerCAmelCase  :			List[str]			,				lowerCAmelCase  :			str			,				lowerCAmelCase  :			Optional[int]			,				lowerCAmelCase  :			Dict=None)	->				int:




         """simple docstring"""

         lowercase__     =  x
         if proj is not None:
               lowercase__     =  tf.einsum('ibd,ed->ibe'			,				_A			,				_A)
         return tf.einsum('ibd,nd->ibn'			,				_A			,				_A) + b


   @staticmethod
   def 			UpperCAmelCase		(						lowerCAmelCase  :			str			,				lowerCAmelCase  :			Dict)	->				Union[str, Any]:




         """simple docstring"""

         lowercase__     =  shape_list(_A)
         lowercase__     =  tf.range(lp_size[0]			,				dtype=target.dtype)
         lowercase__     =  tf.stack([r, target]			,				1)
         return tf.gather_nd(_A			,				_A)



   def 			UpperCAmelCase		(						self  :			int			,				lowerCAmelCase  :			List[Any]			,				lowerCAmelCase  :			Optional[int]			,				lowerCAmelCase  :			int=True			,				lowerCAmelCase  :			Dict=False)	->				int:




         """simple docstring"""

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

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

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

                           lowercase__     =  self._logit(_A			,				_A			,				_A			,				self.out_projs[0])
                           lowercase__     =  tf.nn.log_softmax(_A)
                           out.append(head_logprob[..., : self.cutoffs[0]])
                           if target is not None:
                                 lowercase__     =  tf.boolean_mask(_A			,				_A)
                                 lowercase__     =  self._gather_logprob(_A			,				_A)
                     else:
                           lowercase__     =  self._logit(_A			,				_A			,				_A			,				self.out_projs[i])
                           lowercase__     =  tf.nn.log_softmax(_A)
                           lowercase__     =  self.cutoffs[0] + i - 1  # No probability for the head cluster
                           lowercase__     =  head_logprob[..., cluster_prob_idx, None] + tail_logprob
                           out.append(_A)
                           if target is not None:
                                 lowercase__     =  tf.boolean_mask(_A			,				_A)
                                 lowercase__     =  tf.boolean_mask(_A			,				_A)
                                 lowercase__     =  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))
               lowercase__     =  tf.concat(_A			,				axis=-1)

         if target is not None:
               if return_mean:
                     lowercase__     =  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





from __future__ import annotations

def   _lowerCAmelCase   (						A__						,  A__	):
      if b == 0:
            return (1, 0)
      ((lowercase__),	(lowercase__))     =  extended_euclid(A__						,  a % b	)
      lowercase__     =  a // b
      return (y, x - k * y)

def   _lowerCAmelCase   (						A__						,  A__						,  A__						,  A__	):
      ((lowercase__),	(lowercase__))     =  extended_euclid(A__						,  A__	)
      lowercase__     =  na * na
      lowercase__     =  ra * x * na + ra * y * na
      return (n % m + m) % m

def   _lowerCAmelCase   (						A__						,  A__	):
      ((lowercase__),	(lowercase__))     =  extended_euclid(A__						,  A__	)
      if b < 0:
            lowercase__     =  (b % n + n) % n
      return b

def   _lowerCAmelCase   (						A__						,  A__						,  A__						,  A__	):
      lowercase__,	lowercase__     =  invert_modulo(A__						,  A__	), invert_modulo(A__						,  A__	)
      lowercase__     =  na * na
      lowercase__     =  ra * x * na + ra * y * na
      return (n % m + m) % m


if __name__ == "__main__":
       from doctest import testmod

       testmod(name="chinese_remainder_theorem", verbose=True)
       testmod(name="chinese_remainder_theorem2", verbose=True)
       testmod(name="invert_modulo", verbose=True)
       testmod(name="extended_euclid", verbose=True)
