

'''simple docstring'''

import tensorflow as tf

from ...tf_utils import shape_list


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







       def __init__(				self      :			int    ,   __lowercase      :			int    ,   __lowercase      :			str    ,   __lowercase      :			Tuple    ,   __lowercase      :			List[Any]    ,   __lowercase      :			Any=1    ,   __lowercase      :			Any=False    ,   **__lowercase      :			Optional[int]   ):







            """simple docstring"""







            super().__init__(**__lowercase   )

            __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       snake_case (				self      :			Any    ,   __lowercase      :			Tuple   ):







            """simple docstring"""







            if self.n_clusters > 0:
                 __lowercase      		=self.add_weight(
                     shape=(self.n_clusters, self.d_embed)    ,   initializer='zeros'    ,   trainable=__lowercase    ,   name='cluster_weight'   )
                 __lowercase      		=self.add_weight(
                     shape=(self.n_clusters,)    ,   initializer='zeros'    ,   trainable=__lowercase    ,   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=__lowercase    ,   name=f'''out_projs_._{i}'''    ,   )
                           self.out_projs.append(__lowercase   )
                      else:
                           self.out_projs.append(__lowercase   )
                      __lowercase      		=self.add_weight(
                          shape=(self.vocab_size, self.d_embed)    ,   initializer='zeros'    ,   trainable=__lowercase    ,   name=f'''out_layers_._{i}_._weight'''    ,   )
                      __lowercase      		=self.add_weight(
                          shape=(self.vocab_size,)    ,   initializer='zeros'    ,   trainable=__lowercase    ,   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=__lowercase    ,   name=f'''out_projs_._{i}'''   )
                      self.out_projs.append(__lowercase   )
                      __lowercase      		=self.add_weight(
                          shape=(r_idx - l_idx, d_emb_i)    ,   initializer='zeros'    ,   trainable=__lowercase    ,   name=f'''out_layers_._{i}_._weight'''    ,   )
                      __lowercase      		=self.add_weight(
                          shape=(r_idx - l_idx,)    ,   initializer='zeros'    ,   trainable=__lowercase    ,   name=f'''out_layers_._{i}_._bias'''    ,   )
                      self.out_layers.append((weight, bias)   )
            super().build(__lowercase   )







       @staticmethod
       def       snake_case (				__lowercase      :			Tuple    ,   __lowercase      :			Any    ,   __lowercase      :			List[str]    ,   __lowercase      :			str=None   ):







            """simple docstring"""







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







       @staticmethod
       def       snake_case (				__lowercase      :			List[Any]    ,   __lowercase      :			List[Any]   ):







            """simple docstring"""







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







       def       snake_case (				self      :			Union[str, Any]    ,   __lowercase      :			List[Any]    ,   __lowercase      :			str    ,   __lowercase      :			List[str]=True    ,   __lowercase      :			Optional[Any]=False   ):







            """simple docstring"""







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

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

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

            return out





'''simple docstring'''

def 					__UpperCamelCase				(						lowercase__    :	int			):






     '''simple docstring'''





     if upper_limit < 0:
          raise ValueError('Limit for the Catalan sequence must be ≥ 0'			)

     __lowercase      		=[0] * (upper_limit + 1)

     # Base case: C(0) = C(1) = 1
     __lowercase      		=1
     if upper_limit > 0:
          __lowercase      		=1

     # Recurrence relation: C(i) = sum(C(j).C(i-j-1)), from j = 0 to i
     for i in range(2,       upper_limit + 1			):
          for j in range(lowercase__			):
               catalan_list[i] += catalan_list[j] * catalan_list[i - j - 1]

     return catalan_list


if __name__ == "__main__":
       print('''\n********* Catalan Numbers Using Dynamic Programming ************\n''')
       print('''\n*** Enter -1 at any time to quit ***''')
       print('''\nEnter the upper limit (≥ 0) for the Catalan number sequence: ''', end='''''')
       try:
              while True:
                     UpperCAmelCase					 =	int(input().strip())
                     if N < 0:
                            print('''\n********* Goodbye!! ************''')
                            break
                     else:
                            print(F'''The Catalan numbers from 0 through {N} are:''')
                            print(catalan_numbers(N))
                            print('''Try another upper limit for the sequence: ''', end='''''')
       except (NameError, ValueError):
              print('''\n********* Invalid input, goodbye! ************\n''')

       import doctest

       doctest.testmod()


