




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        UpperCAmelCase__				(							UpperCAmelCase__				):



     '''simple docstring'''
     def __call__(				self ,    _lowerCAmelCase=None ,    _lowerCAmelCase=None ,    **_lowerCAmelCase	):
            # 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:
                          a			   =[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:
                                 a			   =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:
                   a			   =[{"""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."""	)

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

            return tqa_pipeline_inputs



@add_end_docstrings(UpperCAmelCase__				)
class        UpperCAmelCase__				(							UpperCAmelCase__				):



     '''simple docstring'''
     _SCREAMING_SNAKE_CASE      :					Optional[int]     					=    "table,query"
     def __init__(				self ,    _lowerCAmelCase=TableQuestionAnsweringArgumentHandler() ,    *_lowerCAmelCase ,    **_lowerCAmelCase	):
            super().__init__(*_lowerCAmelCase ,    **_lowerCAmelCase	)
            a			   =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()	)	)

            a			   =bool(getattr(self.model.config ,    """aggregation_labels""" ,    _lowerCAmelCase	)	) and bool(
                getattr(self.model.config ,    """num_aggregation_labels""" ,    _lowerCAmelCase	)	)
            a			   ="""tapas""" if hasattr(self.model.config ,    """aggregation_labels"""	) else None
     def        lowerCAmelCase__  (				self ,    **_lowerCAmelCase	):
            return self.model(**_lowerCAmelCase	)
     def        lowerCAmelCase__  (				self ,    **_lowerCAmelCase	):
            if self.framework == "pt":
                   a			   =[]
                   a			   =[]
                   a			   =None
                   a			   =inputs["""input_ids"""].shape[0]

                   a			   =inputs["""input_ids"""].to(self.device	)
                   a			   =inputs["""attention_mask"""].to(self.device	)
                   a			   =inputs["""token_type_ids"""].to(self.device	)
                   a			   =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:
                                 a			   =token_type_ids_example[:, 3]  # shape (seq_len,)
                                 a			   =np.zeros_like(prev_labels_example.cpu().numpy()	)  # shape (seq_len,)

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

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

                                 a			   =torch.from_numpy(_lowerCAmelCase	).type(torch.long	).to(self.device	)

                          a			   =input_ids[index]
                          a			   =attention_mask[index]  # shape (seq_len,)
                          a			   =token_type_ids[index]  # shape (seq_len, 7)
                          a			   =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	) ,    )
                          a			   =outputs.logits

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

                          all_logits.append(_lowerCAmelCase	)

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

                          a			   =collections.defaultdict(_lowerCAmelCase	)
                          for i, p in enumerate(probabilities.squeeze().tolist()	):
                                 a			   =token_type_ids_example[:, 0].tolist()[i]
                                 a			   =token_type_ids_example[:, 1].tolist()[i] - 1
                                 a			   =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	)

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

                   a			   =torch.cat(tuple(_lowerCAmelCase	) ,    0	)

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

                   a			   =inputs["""input_ids"""]
                   a			   =inputs["""attention_mask"""]
                   a			   =inputs["""token_type_ids"""].numpy()
                   a			   =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:
                                 a			   =token_type_ids_example[:, 3]  # shape (seq_len,)
                                 a			   =np.zeros_like(_lowerCAmelCase ,    dtype=np.intaa	)  # shape (seq_len,)

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

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

                                 a			   =model_labels

                          a			   =input_ids[index]
                          a			   =attention_mask[index]  # shape (seq_len,)
                          a			   =token_type_ids[index]  # shape (seq_len, 7)
                          a			   =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	) ,    )
                          a			   =outputs.logits

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

                          all_logits.append(_lowerCAmelCase	)

                          a			   =tfp.distributions.Bernoulli(logits=_lowerCAmelCase	)
                          a			   =dist_per_token.probs_parameter() * tf.cast(_lowerCAmelCase ,    tf.floataa	)

                          a			   =collections.defaultdict(_lowerCAmelCase	)
                          a			   =token_type_ids_example
                          for i, p in enumerate(tf.squeeze(_lowerCAmelCase	).numpy().tolist()	):
                                 a			   =token_type_ids_example[:, 0].tolist()[i]
                                 a			   =token_type_ids_example[:, 1].tolist()[i] - 1
                                 a			   =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	)

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

                   a			   =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	):
            a			   =self._args_parser(*_lowerCAmelCase ,    **_lowerCAmelCase	)

            a			   =super().__call__(_lowerCAmelCase ,    **_lowerCAmelCase	)
            if len(_lowerCAmelCase	) == 1:
                   return results[0]
            return results
     def        lowerCAmelCase__  (				self ,    _lowerCAmelCase=None ,    _lowerCAmelCase=None ,    _lowerCAmelCase=None ,    **_lowerCAmelCase	):
            a			   ={}
            if padding is not None:
                   a			   =padding
            if truncation is not None:
                   a			   =truncation

            a			   ={}
            if sequential is not None:
                   a			   =sequential
            return preprocess_params, forward_params, {}
     def        lowerCAmelCase__  (				self ,    _lowerCAmelCase ,    _lowerCAmelCase=None ,    _lowerCAmelCase=True ,    _lowerCAmelCase=None	):
            if truncation is None:
                   if self.type == "tapas":
                          a			   ="""drop_rows_to_fit"""
                   else:
                          a			   ="""do_not_truncate"""

            a   ,      a			   =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"""	)
            a			   =self.tokenizer(_lowerCAmelCase ,    _lowerCAmelCase ,    return_tensors=self.framework ,    truncation=_lowerCAmelCase ,    padding=_lowerCAmelCase	)
            a			   =table
            return inputs
     def        lowerCAmelCase__  (				self ,    _lowerCAmelCase ,    _lowerCAmelCase=False	):
            a			   =model_inputs.pop("""table"""	)

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






     def        lowerCAmelCase__  (				self ,    _lowerCAmelCase	):
            a			   =model_outputs["""model_inputs"""]
            a			   =model_outputs["""table"""]
            a			   =model_outputs["""outputs"""]
            if self.type == "tapas":
                   if self.aggregate:
                          a   ,      a			   =outputs[:2]
                          a			   =self.tokenizer.convert_logits_to_predictions(_lowerCAmelCase ,    _lowerCAmelCase ,    _lowerCAmelCase	)
                          a   ,      a			   =predictions
                          a			   ={i: self.model.config.aggregation_labels[pred] for i, pred in enumerate(_lowerCAmelCase	)}

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

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

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






from __future__ import annotations

from typing import Any


class        UpperCAmelCase__				:



     '''simple docstring'''
     def __init__(				self ,    _lowerCAmelCase ,    _lowerCAmelCase	):  # noqa: A002
            a			   =item
            a			   =next



class        UpperCAmelCase__				:



     '''simple docstring'''
     def __init__(				self	):
            a			   =None
            a			   =0
     def        lowerCAmelCase__  (				self ,    _lowerCAmelCase	):
            a			   =Node(_lowerCAmelCase ,    self.head	)
            self.size += 1
     def        lowerCAmelCase__  (				self	):
            # Switched 'self.is_empty()' to 'self.head is None'
            # because mypy was considering the possibility that 'self.head'
            # can be None in below else part and giving error
            if self.head is None:
                   return None
            else:
                   a			   =self.head.item
                   a			   =self.head.next
                   self.size -= 1
                   return item
     def        lowerCAmelCase__  (				self	):
            return self.head is None
     def __str__(				self	):
            if self.is_empty():
                   return ""
            else:
                   a			   =self.head
                   a			   =""""""
                   a			   =[]
                   while iterate:
                          item_list.append(str(iterate.item	)	)
                          a			   =iterate.next

                   a			   =""" --> """.join(_lowerCAmelCase	)

                   return item_str






     def __len__(				self	):
            return self.size
