

import collections
import types

import numpy as np

from ..utils import (
    add_end_docstrings,
    is_tensorflow_probability_available,
    is_tf_available,
    is_torch_available,
    requires_backends,
)
from .base import PIPELINE_INIT_ARGS, ArgumentHandler, Dataset, Pipeline, PipelineException


if is_torch_available():
    import torch

    from ..models.auto.modeling_auto import (
        MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING,
        MODEL_FOR_TABLE_QUESTION_ANSWERING_MAPPING,
    )

if is_tf_available() and is_tensorflow_probability_available():
    import tensorflow as tf
    import tensorflow_probability as tfp

    from ..models.auto.modeling_tf_auto import (
        TF_MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING,
        TF_MODEL_FOR_TABLE_QUESTION_ANSWERING_MAPPING,
    )







class 					__lowerCamelCase							(      __snake_case      ):







      def __call__(	self				,    lowerCamelCase=None				,    lowerCamelCase=None				,    **lowerCamelCase  )		->			List[Any]:
        # Returns tqa_pipeline_inputs of shape:
        # [
        #   {"table": pd.DataFrame, "query": List[str]},
        #   ...,
        #   {"table": pd.DataFrame, "query" : List[str]}
        # ]
        requires_backends(self				,    """pandas"""  )
        import pandas as pd

        if table is None:
          raise ValueError("""Keyword argument `table` cannot be None."""  )
        elif query is None:
          if isinstance(lowerCamelCase				,    lowerCamelCase  ) and table.get("""query"""  ) is not None and table.get("""table"""  ) is not None:
            snake_case_					= [table]
          elif isinstance(lowerCamelCase				,    lowerCamelCase  ) and len(lowerCamelCase  ) > 0:
            if not all(isinstance(lowerCamelCase				,    lowerCamelCase  ) for d in table  ):
              raise ValueError(
                  f'''Keyword argument `table` should be a list of dict, but is {(type(lowerCamelCase  ) for d in table)}'''  )

            if table[0].get("""query"""  ) is not None and table[0].get("""table"""  ) is not None:
              snake_case_					= table
            else:
              raise ValueError(
                  """If keyword argument `table` is a list of dictionaries, each dictionary should have a `table`"""
                  f''' and `query` key, but only dictionary has keys {table[0].keys()} `table` and `query` keys.'''  )
          elif Dataset is not None and isinstance(lowerCamelCase				,    lowerCamelCase  ) or isinstance(lowerCamelCase				,    types.GeneratorType  ):
            return table
          else:
            raise ValueError(
                """Invalid input. Keyword argument `table` should be either of type `dict` or `list`, but """
                f'''is {type(lowerCamelCase  )})'''  )
        else:
          snake_case_					= [{"""table""": table, """query""": query}]

        for tqa_pipeline_input in tqa_pipeline_inputs:
          if not isinstance(tqa_pipeline_input["""table"""]				,    pd.DataFrame  ):
            if tqa_pipeline_input["table"] is None:
              raise ValueError("""Table cannot be None."""  )

            snake_case_					= pd.DataFrame(tqa_pipeline_input["""table"""]  )

        return tqa_pipeline_inputs







@add_end_docstrings(__snake_case      )
class 					__lowerCamelCase							(      __snake_case      ):
      lowerCamelCase_      : List[Any]  			=   'table,query'







      def __init__(	self				,    lowerCamelCase=TableQuestionAnsweringArgumentHandler()				,    *lowerCamelCase				,    **lowerCamelCase  )		->			Union[str, Any]:
        super().__init__(*lowerCamelCase				,    **lowerCamelCase  )
        snake_case_					= args_parser

        self.check_model_type(
            dict(
                TF_MODEL_FOR_TABLE_QUESTION_ANSWERING_MAPPING.items()
                + TF_MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING.items()  )
            if self.framework == """tf"""
            else dict(
                MODEL_FOR_TABLE_QUESTION_ANSWERING_MAPPING.items() + MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING.items()  )  )

        snake_case_					= bool(getattr(self.model.config				,    """aggregation_labels"""				,    lowerCamelCase  )  ) and bool(
            getattr(self.model.config				,    """num_aggregation_labels"""				,    lowerCamelCase  )  )
        snake_case_					= """tapas""" if hasattr(self.model.config				,    """aggregation_labels"""  ) else None







      def       lowerCAmelCase_       (	self				,    **lowerCamelCase  )		->			Tuple:
        return self.model(**lowerCamelCase  )







      def       lowerCAmelCase_       (	self				,    **lowerCamelCase  )		->			Dict:
        if self.framework == "pt":
          snake_case_					= []
          snake_case_					= []
          snake_case_					= None
          snake_case_					= inputs["""input_ids"""].shape[0]

          snake_case_					= inputs["""input_ids"""].to(self.device  )
          snake_case_					= inputs["""attention_mask"""].to(self.device  )
          snake_case_					= inputs["""token_type_ids"""].to(self.device  )
          snake_case_					= None

          for index in range(lowerCamelCase  ):
            # If sequences have already been processed, the token type IDs will be created according to the previous
            # answer.
            if prev_answers is not None:
              snake_case_					= token_type_ids_example[:, 3]  # shape (seq_len,)
              snake_case_					= np.zeros_like(prev_labels_example.cpu().numpy()  )  # shape (seq_len,)

              snake_case_					= token_type_ids[index]  # shape (seq_len, 7)
              for i in range(model_labels.shape[0]  ):
                snake_case_					= token_type_ids_example[:, 0].tolist()[i]
                snake_case_					= token_type_ids_example[:, 1].tolist()[i] - 1
                snake_case_					= token_type_ids_example[:, 2].tolist()[i] - 1

                if row_id >= 0 and col_id >= 0 and segment_id == 1:
                  snake_case_					= int(prev_answers[(col_id, row_id)]  )

              snake_case_					= torch.from_numpy(lowerCamelCase  ).type(torch.long  ).to(self.device  )

            snake_case_					= input_ids[index]
            snake_case_					= attention_mask[index]  # shape (seq_len,)
            snake_case_					= token_type_ids[index]  # shape (seq_len, 7)
            snake_case_					= self.model(
                input_ids=input_ids_example.unsqueeze(0  )				,    attention_mask=attention_mask_example.unsqueeze(0  )				,    token_type_ids=token_type_ids_example.unsqueeze(0  )				,    )
            snake_case_					= outputs.logits

            if self.aggregate:
              all_aggregations.append(outputs.logits_aggregation  )

            all_logits.append(lowerCamelCase  )

            snake_case_					= torch.distributions.Bernoulli(logits=lowerCamelCase  )
            snake_case_					= dist_per_token.probs * attention_mask_example.type(torch.floataa  ).to(
                dist_per_token.probs.device  )

            snake_case_					= collections.defaultdict(lowerCamelCase  )
            for i, p in enumerate(probabilities.squeeze().tolist()  ):
              snake_case_					= token_type_ids_example[:, 0].tolist()[i]
              snake_case_					= token_type_ids_example[:, 1].tolist()[i] - 1
              snake_case_					= token_type_ids_example[:, 2].tolist()[i] - 1
              if col >= 0 and row >= 0 and segment_id == 1:
                coords_to_probs[(col, row)].append(lowerCamelCase  )

            snake_case_					= {key: np.array(coords_to_probs[key]  ).mean() > 0.5 for key in coords_to_probs}

          snake_case_					= torch.cat(tuple(lowerCamelCase  )				,    0  )

          return (logits_batch,) if not self.aggregate else (logits_batch, torch.cat(tuple(lowerCamelCase  )				,    0  ))
        else:
          snake_case_					= []
          snake_case_					= []
          snake_case_					= None
          snake_case_					= inputs["""input_ids"""].shape[0]

          snake_case_					= inputs["""input_ids"""]
          snake_case_					= inputs["""attention_mask"""]
          snake_case_					= inputs["""token_type_ids"""].numpy()
          snake_case_					= None

          for index in range(lowerCamelCase  ):
            # If sequences have already been processed, the token type IDs will be created according to the previous
            # answer.
            if prev_answers is not None:
              snake_case_					= token_type_ids_example[:, 3]  # shape (seq_len,)
              snake_case_					= np.zeros_like(lowerCamelCase				,    dtype=np.intaa  )  # shape (seq_len,)

              snake_case_					= token_type_ids[index]  # shape (seq_len, 7)
              for i in range(model_labels.shape[0]  ):
                snake_case_					= token_type_ids_example[:, 0].tolist()[i]
                snake_case_					= token_type_ids_example[:, 1].tolist()[i] - 1
                snake_case_					= token_type_ids_example[:, 2].tolist()[i] - 1

                if row_id >= 0 and col_id >= 0 and segment_id == 1:
                  snake_case_					= int(prev_answers[(col_id, row_id)]  )

              snake_case_					= model_labels

            snake_case_					= input_ids[index]
            snake_case_					= attention_mask[index]  # shape (seq_len,)
            snake_case_					= token_type_ids[index]  # shape (seq_len, 7)
            snake_case_					= self.model(
                input_ids=np.expand_dims(lowerCamelCase				,    axis=0  )				,    attention_mask=np.expand_dims(lowerCamelCase				,    axis=0  )				,    token_type_ids=np.expand_dims(lowerCamelCase				,    axis=0  )				,    )
            snake_case_					= outputs.logits

            if self.aggregate:
              all_aggregations.append(outputs.logits_aggregation  )

            all_logits.append(lowerCamelCase  )

            snake_case_					= tfp.distributions.Bernoulli(logits=lowerCamelCase  )
            snake_case_					= dist_per_token.probs_parameter() * tf.cast(lowerCamelCase				,    tf.floataa  )

            snake_case_					= collections.defaultdict(lowerCamelCase  )
            snake_case_					= token_type_ids_example
            for i, p in enumerate(tf.squeeze(lowerCamelCase  ).numpy().tolist()  ):
              snake_case_					= token_type_ids_example[:, 0].tolist()[i]
              snake_case_					= token_type_ids_example[:, 1].tolist()[i] - 1
              snake_case_					= token_type_ids_example[:, 2].tolist()[i] - 1
              if col >= 0 and row >= 0 and segment_id == 1:
                coords_to_probs[(col, row)].append(lowerCamelCase  )

            snake_case_					= {key: np.array(coords_to_probs[key]  ).mean() > 0.5 for key in coords_to_probs}

          snake_case_					= tf.concat(tuple(lowerCamelCase  )				,    0  )

          return (logits_batch,) if not self.aggregate else (logits_batch, tf.concat(tuple(lowerCamelCase  )				,    0  ))







      def __call__(	self				,    *lowerCamelCase				,    **lowerCamelCase  )		->			str:
        snake_case_					= self._args_parser(*lowerCamelCase				,    **lowerCamelCase  )

        snake_case_					= super().__call__(lowerCamelCase				,    **lowerCamelCase  )
        if len(lowerCamelCase  ) == 1:
          return results[0]
        return results







      def       lowerCAmelCase_       (	self				,    lowerCamelCase=None				,    lowerCamelCase=None				,    lowerCamelCase=None				,    **lowerCamelCase  )		->			str:
        snake_case_					= {}
        if padding is not None:
          snake_case_					= padding
        if truncation is not None:
          snake_case_					= truncation

        snake_case_					= {}
        if sequential is not None:
          snake_case_					= sequential
        return preprocess_params, forward_params, {}







      def       lowerCAmelCase_       (	self				,    lowerCamelCase				,    lowerCamelCase=None				,    lowerCamelCase=True				,    lowerCamelCase=None  )		->			Union[str, Any]:
        if truncation is None:
          if self.type == "tapas":
            snake_case_					= """drop_rows_to_fit"""
          else:
            snake_case_					= """do_not_truncate"""

        snake_case_		,							snake_case_					= pipeline_input["""table"""], pipeline_input["""query"""]
        if table.empty:
          raise ValueError("""table is empty"""  )
        if query is None or query == "":
          raise ValueError("""query is empty"""  )
        snake_case_					= self.tokenizer(lowerCamelCase				,    lowerCamelCase				,    return_tensors=self.framework				,    truncation=lowerCamelCase				,    padding=lowerCamelCase  )
        snake_case_					= table
        return inputs







      def       lowerCAmelCase_       (	self				,    lowerCamelCase				,    lowerCamelCase=False  )		->			Optional[int]:
        snake_case_					= model_inputs.pop("""table"""  )

        if self.type == "tapas":
          if sequential:
            snake_case_					= self.sequential_inference(**lowerCamelCase  )
          else:
            snake_case_					= self.batch_inference(**lowerCamelCase  )
        else:
          snake_case_					= self.model.generate(**lowerCamelCase  )
        snake_case_					= {"""model_inputs""": model_inputs, """table""": table, """outputs""": outputs}
        return model_outputs







      def       lowerCAmelCase_       (	self				,    lowerCamelCase  )		->			List[str]:
        snake_case_					= model_outputs["""model_inputs"""]
        snake_case_					= model_outputs["""table"""]
        snake_case_					= model_outputs["""outputs"""]
        if self.type == "tapas":
          if self.aggregate:
            snake_case_		,							snake_case_					= outputs[:2]
            snake_case_					= self.tokenizer.convert_logits_to_predictions(lowerCamelCase				,    lowerCamelCase				,    lowerCamelCase  )
            snake_case_		,							snake_case_					= predictions
            snake_case_					= {i: self.model.config.aggregation_labels[pred] for i, pred in enumerate(lowerCamelCase  )}

            snake_case_					= self.model.config.no_aggregation_label_index
            snake_case_					= {
                i: aggregators[i] + """ > """ for i, pred in enumerate(lowerCamelCase  ) if pred != no_agg_label_index
            }
          else:
            snake_case_					= outputs[0]
            snake_case_					= self.tokenizer.convert_logits_to_predictions(lowerCamelCase				,    lowerCamelCase  )
            snake_case_					= predictions[0]
            snake_case_					= {}
            snake_case_					= {}
          snake_case_					= []
          for index, coordinates in enumerate(lowerCamelCase  ):
            snake_case_					= [table.iat[coordinate] for coordinate in coordinates]
            snake_case_					= aggregators.get(lowerCamelCase				,    """"""  )
            snake_case_					= aggregators_prefix.get(lowerCamelCase				,    """"""  )
            snake_case_					= {
                """answer""": aggregator_prefix + """, """.join(lowerCamelCase  ),
                """coordinates""": coordinates,
                """cells""": [table.iat[coordinate] for coordinate in coordinates],
            }
            if aggregator:
              snake_case_					= aggregator

            answers.append(lowerCamelCase  )
          if len(lowerCamelCase  ) == 0:
            raise PipelineException("""Empty answer"""  )
        else:
          snake_case_					= [{"""answer""": answer} for answer in self.tokenizer.batch_decode(lowerCamelCase				,    skip_special_tokens=lowerCamelCase  )]

        return answers if len(lowerCamelCase  ) > 1 else answers[0]


from math import pi



def   UpperCamelCase(   lowercase_				)      ->							float:





  '''simple docstring'''





  return degree / (180 / pi)


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

    testmod()