



'''simple docstring'''




import tensorflow as tf

from ...tf_utils import shape_list



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






      """simple docstring"""




      def __init__(       self							:     int			,a__							:     str			,a__							:     Optional[int]			,a__							:     Any			,a__							:     Dict			,a__							:     List[Any]=1			,a__							:     Tuple=False			,**a__							:     Tuple   ):
             super().__init__(**_UpperCAmelCase   )

             a__								= vocab_size
             a__								= d_embed
             a__								= d_proj

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

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

             a__								= []
             a__								= []




      def lowerCAmelCase_					(       self							:     int			,a__							:     Union[str, Any]   ):
             if self.n_clusters > 0:
                    a__								= self.add_weight(
                        shape=(self.n_clusters, self.d_embed)			,initializer="zeros"			,trainable=_UpperCAmelCase			,name="cluster_weight"   )
                    a__								= self.add_weight(
                        shape=(self.n_clusters,)			,initializer="zeros"			,trainable=_UpperCAmelCase			,name="cluster_bias"   )

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

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




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




      @staticmethod
      def lowerCAmelCase_					(       a__							:     List[Any]			,a__							:     Dict   ):
             a__								= shape_list(_UpperCAmelCase   )
             a__								= tf.range(lp_size[0]			,dtype=target.dtype   )
             a__								= tf.stack([r, target]			,1   )
             return tf.gather_nd(_UpperCAmelCase			,_UpperCAmelCase   )




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

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

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

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

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

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

             return out








import datasets

from .evaluate import evaluate


snake_case__   :						int													=   """\
@article{hendrycks2021cuad,
      title={CUAD: An Expert-Annotated NLP Dataset for Legal Contract Review},
      author={Dan Hendrycks and Collin Burns and Anya Chen and Spencer Ball},
      journal={arXiv preprint arXiv:2103.06268},
      year={2021}
}
"""

snake_case__   :						Union[str, Any]													=   """
This metric wrap the official scoring script for version 1 of the Contract
Understanding Atticus Dataset (CUAD).
Contract Understanding Atticus Dataset (CUAD) v1 is a corpus of more than 13,000 labels in 510
commercial legal contracts that have been manually labeled to identify 41 categories of important
clauses that lawyers look for when reviewing contracts in connection with corporate transactions.
"""

snake_case__   :						Any													=   """
Computes CUAD scores (EM, F1, AUPR, Precision@80%Recall, and Precision@90%Recall).
Args:
    predictions: List of question-answers dictionaries with the following key-values:
        - 'id': id of the question-answer pair as given in the references (see below)
        - 'prediction_text': list of possible texts for the answer, as a list of strings
        depending on a threshold on the confidence probability of each prediction.
    references: List of question-answers dictionaries with the following key-values:
        - 'id': id of the question-answer pair (see above),
        - 'answers': a Dict in the CUAD dataset format
            {
                'text': list of possible texts for the answer, as a list of strings
                'answer_start': list of start positions for the answer, as a list of ints
            }
            Note that answer_start values are not taken into account to compute the metric.
Returns:
    'exact_match': Exact match (the normalized answer exactly match the gold answer)
    'f1': The F-score of predicted tokens versus the gold answer
    'aupr': Area Under the Precision-Recall curve
    'prec_at_80_recall': Precision at 80% recall
    'prec_at_90_recall': Precision at 90% recall
Examples:
    >>> predictions = [{'prediction_text': ['The seller:', 'The buyer/End-User: Shenzhen LOHAS Supply Chain Management Co., Ltd.'], 'id': 'LohaCompanyltd_20191209_F-1_EX-10.16_11917878_EX-10.16_Supply Agreement__Parties'}]
    >>> references = [{'answers': {'answer_start': [143, 49], 'text': ['The seller:', 'The buyer/End-User: Shenzhen LOHAS Supply Chain Management Co., Ltd.']}, 'id': 'LohaCompanyltd_20191209_F-1_EX-10.16_11917878_EX-10.16_Supply Agreement__Parties'}]
    >>> cuad_metric = datasets.load_metric(\"cuad\")
    >>> results = cuad_metric.compute(predictions=predictions, references=references)
    >>> print(results)
    {'exact_match': 100.0, 'f1': 100.0, 'aupr': 0.0, 'prec_at_80_recall': 1.0, 'prec_at_90_recall': 1.0}
"""


@datasets.utils.file_utils.add_start_docstrings(_DESCRIPTION    ,							_KWARGS_DESCRIPTION     )
class     _a							(	datasets.Metric     ):






  """simple docstring"""





  def  _UpperCAmelCase  (  self			)      ->			Optional[int]:
     return datasets.MetricInfo(
         description=_DESCRIPTION		,		citation=_CITATION		,		inputs_description=_KWARGS_DESCRIPTION		,		features=datasets.Features(
             {
                 'predictions': {
                     'id': datasets.Value('string'			),
                     'prediction_text': datasets.features.Sequence(datasets.Value('string'			)			),
                 },
                 'references': {
                     'id': datasets.Value('string'			),
                     'answers': datasets.features.Sequence(
                         {
                             'text': datasets.Value('string'			),
                             'answer_start': datasets.Value('int32'			),
                         }			),
                 },
             }			)		,		codebase_urls=['https://www.atticusprojectai.org/cuad']		,		reference_urls=['https://www.atticusprojectai.org/cuad']		,		)




  def  _UpperCAmelCase  (  self		,		_UpperCAmelCase		,		_UpperCAmelCase			)      ->			Dict:
     UpperCamelCase_						=  {prediction['id']: prediction['prediction_text'] for prediction in predictions}
     UpperCamelCase_						=  [
         {
             'paragraphs': [
                 {
                     'qas': [
                         {
                             'answers': [{'text': answer_text} for answer_text in ref['answers']['text']],
                             'id': ref['id'],
                         }
                         for ref in references
                     ]
                 }
             ]
         }
     ]
     UpperCamelCase_						=  evaluate(dataset=_UpperCAmelCase		,		predictions=_UpperCAmelCase			)
     return score





