



"""simple docstring"""







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




	"""simple docstring"""






	def __call__(     self				,UpperCAmelCase_=None				,UpperCAmelCase_=None				,**UpperCAmelCase_   ):
			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:
							_lowercase				: int     =   [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:
									_lowercase				: Tuple     =   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:
					_lowercase				: List[Any]     =   [{'''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."""   )

							_lowercase				: Any     =   pd.DataFrame(tqa_pipeline_input["""table"""]   )

			return tqa_pipeline_inputs







@add_end_docstrings(SCREAMING_SNAKE_CASE__       )
class   UpperCamelCase	(     SCREAMING_SNAKE_CASE__       ):




	"""simple docstring"""
	SCREAMING_SNAKE_CASE_							:       Any						       =  '''table,query'''






	def __init__(     self				,UpperCAmelCase_=TableQuestionAnsweringArgumentHandler()				,*UpperCAmelCase_				,**UpperCAmelCase_   ):
			super().__init__(*lowerCAmelCase_				,**lowerCAmelCase_   )
			_lowercase				: List[str]     =   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()   )   )

			_lowercase				: Tuple     =   bool(getattr(self.model.config				,"""aggregation_labels"""				,lowerCAmelCase_   )   ) and bool(
			    getattr(self.model.config				,"""num_aggregation_labels"""				,lowerCAmelCase_   )   )
			_lowercase				: Optional[int]     =   '''tapas''' if hasattr(self.model.config				,"""aggregation_labels"""   ) else None






	def    lowerCamelCase__					(     self				,**UpperCAmelCase_   ):
			return self.model(**lowerCAmelCase_   )






	def    lowerCamelCase__					(     self				,**UpperCAmelCase_   ):
			if self.framework == "pt":
					_lowercase				: Any     =   []
					_lowercase				: int     =   []
					_lowercase				: Union[str, Any]     =   None
					_lowercase				: Optional[int]     =   inputs['''input_ids'''].shape[0]

					_lowercase				: Optional[Any]     =   inputs['''input_ids'''].to(self.device   )
					_lowercase				: int     =   inputs['''attention_mask'''].to(self.device   )
					_lowercase				: List[str]     =   inputs['''token_type_ids'''].to(self.device   )
					_lowercase				: Any     =   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:
									_lowercase				: Any     =   token_type_ids_example[:, 3]  # shape (seq_len,)
									_lowercase				: Any     =   np.zeros_like(prev_labels_example.cpu().numpy()   )  # shape (seq_len,)

									_lowercase				: Dict     =   token_type_ids[index]  # shape (seq_len, 7)
									for i in range(model_labels.shape[0]   ):
											_lowercase				: Optional[Any]     =   token_type_ids_example[:, 0].tolist()[i]
											_lowercase				: Tuple     =   token_type_ids_example[:, 1].tolist()[i] - 1
											_lowercase				: List[str]     =   token_type_ids_example[:, 2].tolist()[i] - 1

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

									_lowercase				: Union[str, Any]     =   torch.from_numpy(lowerCAmelCase_   ).type(torch.long   ).to(self.device   )

							_lowercase				: Any     =   input_ids[index]
							_lowercase				: List[str]     =   attention_mask[index]  # shape (seq_len,)
							_lowercase				: Any     =   token_type_ids[index]  # shape (seq_len, 7)
							_lowercase				: Tuple     =   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   )				,)
							_lowercase				: Union[str, Any]     =   outputs.logits

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

							all_logits.append(lowerCAmelCase_   )

							_lowercase				: Optional[int]     =   torch.distributions.Bernoulli(logits=lowerCAmelCase_   )
							_lowercase				: Any     =   dist_per_token.probs * attention_mask_example.type(torch.floataa   ).to(
							    dist_per_token.probs.device   )

							_lowercase				: Tuple     =   collections.defaultdict(lowerCAmelCase_   )
							for i, p in enumerate(probabilities.squeeze().tolist()   ):
									_lowercase				: Dict     =   token_type_ids_example[:, 0].tolist()[i]
									_lowercase				: List[str]     =   token_type_ids_example[:, 1].tolist()[i] - 1
									_lowercase				: str     =   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_   )

							_lowercase				: Union[str, Any]     =   {key: np.array(coords_to_probs[key]   ).mean() > 0.5 for key in coords_to_probs}

					_lowercase				: List[Any]     =   torch.cat(tuple(lowerCAmelCase_   )				,0   )

					return (logits_batch,) if not self.aggregate else (logits_batch, torch.cat(tuple(lowerCAmelCase_   )				,0   ))
			else:
					_lowercase				: List[Any]     =   []
					_lowercase				: str     =   []
					_lowercase				: int     =   None
					_lowercase				: Union[str, Any]     =   inputs['''input_ids'''].shape[0]

					_lowercase				: Union[str, Any]     =   inputs['''input_ids''']
					_lowercase				: Dict     =   inputs['''attention_mask''']
					_lowercase				: Any     =   inputs['''token_type_ids'''].numpy()
					_lowercase				: Tuple     =   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:
									_lowercase				: Tuple     =   token_type_ids_example[:, 3]  # shape (seq_len,)
									_lowercase				: Any     =   np.zeros_like(lowerCAmelCase_				,dtype=np.intaa   )  # shape (seq_len,)

									_lowercase				: Optional[Any]     =   token_type_ids[index]  # shape (seq_len, 7)
									for i in range(model_labels.shape[0]   ):
											_lowercase				: List[Any]     =   token_type_ids_example[:, 0].tolist()[i]
											_lowercase				: int     =   token_type_ids_example[:, 1].tolist()[i] - 1
											_lowercase				: Dict     =   token_type_ids_example[:, 2].tolist()[i] - 1

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

									_lowercase				: List[Any]     =   model_labels

							_lowercase				: Tuple     =   input_ids[index]
							_lowercase				: Union[str, Any]     =   attention_mask[index]  # shape (seq_len,)
							_lowercase				: Dict     =   token_type_ids[index]  # shape (seq_len, 7)
							_lowercase				: List[Any]     =   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   )				,)
							_lowercase				: str     =   outputs.logits

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

							all_logits.append(lowerCAmelCase_   )

							_lowercase				: int     =   tfp.distributions.Bernoulli(logits=lowerCAmelCase_   )
							_lowercase				: Tuple     =   dist_per_token.probs_parameter() * tf.cast(lowerCAmelCase_				,tf.floataa   )

							_lowercase				: List[Any]     =   collections.defaultdict(lowerCAmelCase_   )
							_lowercase				: List[str]     =   token_type_ids_example
							for i, p in enumerate(tf.squeeze(lowerCAmelCase_   ).numpy().tolist()   ):
									_lowercase				: List[Any]     =   token_type_ids_example[:, 0].tolist()[i]
									_lowercase				: Tuple     =   token_type_ids_example[:, 1].tolist()[i] - 1
									_lowercase				: int     =   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_   )

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

					_lowercase				: str     =   tf.concat(tuple(lowerCAmelCase_   )				,0   )

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






	def __call__(     self				,*UpperCAmelCase_				,**UpperCAmelCase_   ):
			_lowercase				: List[str]     =   self._args_parser(*lowerCAmelCase_				,**lowerCAmelCase_   )

			_lowercase				: List[str]     =   super().__call__(lowerCAmelCase_				,**lowerCAmelCase_   )
			if len(lowerCAmelCase_   ) == 1:
					return results[0]
			return results






	def    lowerCamelCase__					(     self				,UpperCAmelCase_=None				,UpperCAmelCase_=None				,UpperCAmelCase_=None				,**UpperCAmelCase_   ):
			_lowercase				: Dict     =   {}
			if padding is not None:
					_lowercase				: str     =   padding
			if truncation is not None:
					_lowercase				: int     =   truncation

			_lowercase				: List[str]     =   {}
			if sequential is not None:
					_lowercase				: str     =   sequential
			return preprocess_params, forward_params, {}






	def    lowerCamelCase__					(     self				,UpperCAmelCase_				,UpperCAmelCase_=None				,UpperCAmelCase_=True				,UpperCAmelCase_=None   ):
			if truncation is None:
					if self.type == "tapas":
							_lowercase				: Dict     =   '''drop_rows_to_fit'''
					else:
							_lowercase				: Optional[int]     =   '''do_not_truncate'''

			_lowercase				: Optional[int]     =   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"""   )
			_lowercase				: int     =   self.tokenizer(lowerCAmelCase_				,lowerCAmelCase_				,return_tensors=self.framework				,truncation=lowerCAmelCase_				,padding=lowerCAmelCase_   )
			_lowercase				: Optional[Any]     =   table
			return inputs






	def    lowerCamelCase__					(     self				,UpperCAmelCase_				,UpperCAmelCase_=False   ):
			_lowercase				: Tuple     =   model_inputs.pop("""table"""   )

			if self.type == "tapas":
					if sequential:
							_lowercase				: Optional[Any]     =   self.sequential_inference(**lowerCAmelCase_   )
					else:
							_lowercase				: int     =   self.batch_inference(**lowerCAmelCase_   )
			else:
					_lowercase				: Optional[int]     =   self.model.generate(**lowerCAmelCase_   )
			_lowercase				: Tuple     =   {'''model_inputs''': model_inputs, '''table''': table, '''outputs''': outputs}
			return model_outputs






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

							_lowercase				: str     =   self.model.config.no_aggregation_label_index
							_lowercase				: Dict     =   {
							    i: aggregators[i] + ''' > ''' for i, pred in enumerate(lowerCAmelCase_   ) if pred != no_agg_label_index
							}
					else:
							_lowercase				: Union[str, Any]     =   outputs[0]
							_lowercase				: Optional[int]     =   self.tokenizer.convert_logits_to_predictions(lowerCAmelCase_				,lowerCAmelCase_   )
							_lowercase				: Union[str, Any]     =   predictions[0]
							_lowercase				: Any     =   {}
							_lowercase				: List[str]     =   {}
					_lowercase				: List[str]     =   []
					for index, coordinates in enumerate(lowerCAmelCase_   ):
							_lowercase				: str     =   [table.iat[coordinate] for coordinate in coordinates]
							_lowercase				: str     =   aggregators.get(lowerCAmelCase_				,""""""   )
							_lowercase				: List[str]     =   aggregators_prefix.get(lowerCAmelCase_				,""""""   )
							_lowercase				: List[str]     =   {
							    '''answer''': aggregator_prefix + ''', '''.join(lowerCAmelCase_   ),
							    '''coordinates''': coordinates,
							    '''cells''': [table.iat[coordinate] for coordinate in coordinates],
							}
							if aggregator:
									_lowercase				: int     =   aggregator

							answers.append(lowerCAmelCase_   )
					if len(lowerCAmelCase_   ) == 0:
							raise PipelineException("""Empty answer"""   )
			else:
					_lowercase				: List[Any]     =   [{'''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






def     lowerCamelCase__				(   a ) ->  Union[str, Any]:
   global graph, reversed_graph, scc, component, visit, stack
   if visit[u]:
      return
   _A:    Optional[Any]						     =			True
   for v in graph[u]:
      dfs(a )
   stack.append(a )






def     lowerCamelCase__				(   a ) ->  List[Any]:
   global graph, reversed_graph, scc, component, visit, stack
   if visit[u]:
      return
   _A:    str						     =			True
   component.append(a )
   for v in reversed_graph[u]:
      dfsa(a )






def     lowerCamelCase__				(   ) ->  str:
   global graph, reversed_graph, scc, component, visit, stack
   for i in range(a ):
      dfs(a )
   _A:    Optional[Any]						     =			[False] * n
   for i in stack[::-1]:
      if visit[i]:
         continue
      _A:    Optional[Any]						     =			[]
      dfsa(a )
      scc.append(a )
   return scc


if __name__ == "__main__":
   # n - no of nodes, m - no of edges
   UpperCAmelCase__     ,UpperCAmelCase__						:	Any	     = list(map(int, input().strip().split()))

   UpperCAmelCase__						:	list[list[int]]	     = [[] for _ in range(n)]  # graph
   UpperCAmelCase__						:	list[list[int]]	     = [[] for i in range(n)]  # reversed graph
   # input graph data (edges)
   for _ in range(m):
      UpperCAmelCase__     ,UpperCAmelCase__						:	str	     = list(map(int, input().strip().split()))
      graph[u].append(v)
      reversed_graph[v].append(u)

   UpperCAmelCase__						:	list[int]	     = []
   UpperCAmelCase__						:	list[bool]	     = [False] * n
   UpperCAmelCase__						:	list[int]	     = []
   UpperCAmelCase__						:	list[int]	     = []
   print(kosaraju())



