

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 	__magic_name__				(       snake_case							):






     def __call__(							self		,	_lowercase=None		,	_lowercase=None		,	**_lowercase  )->    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(_lowercase		,	_lowercase  ) and table.get("query"  ) is not None and table.get("table"  ) is not None:
                 UpperCamelCase_      =	[table]
             elif isinstance(_lowercase		,	_lowercase  ) and len(_lowercase  ) > 0:
                 if not all(isinstance(_lowercase		,	_lowercase  ) for d in table  ):
                     raise ValueError(
                         F"Keyword argument `table` should be a list of dict, but is {(type(_lowercase  ) for d in table)}"  )

                 if table[0].get("query"  ) is not None and table[0].get("table"  ) is not None:
                     UpperCamelCase_      =	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(_lowercase		,	_lowercase  ) or isinstance(_lowercase		,	types.GeneratorType  ):
                 return table
             else:
                 raise ValueError(
                     "Invalid input. Keyword argument `table` should be either of type `dict` or `list`, but "
                     F"is {type(_lowercase  )})"  )
         else:
             UpperCamelCase_      =	[{"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."  )

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

         return tqa_pipeline_inputs






@add_end_docstrings(snake_case							)
class 	__magic_name__				(       snake_case							):
     UpperCamelCase_  :int								=			"""table,query"""






     def __init__(							self		,	_lowercase=TableQuestionAnsweringArgumentHandler()		,	*_lowercase		,	**_lowercase  )->    Any:
         super().__init__(*_lowercase		,	**_lowercase  )
         UpperCamelCase_      =	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()  )  )

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






     def   UpperCAmelCase_							(							self		,	**_lowercase  )->    Any:
         return self.model(**_lowercase  )






     def   UpperCAmelCase_							(							self		,	**_lowercase  )->    Optional[int]:
         if self.framework == "pt":
             UpperCamelCase_      =	[]
             UpperCamelCase_      =	[]
             UpperCamelCase_      =	None
             UpperCamelCase_      =	inputs["input_ids"].shape[0]

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

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

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

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

                     UpperCamelCase_      =	torch.from_numpy(_lowercase  ).type(torch.long  ).to(self.device  )

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

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

                 all_logits.append(_lowercase  )

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

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

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

             UpperCamelCase_      =	torch.cat(tuple(_lowercase  )		,	0  )

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

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

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

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

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

                     UpperCamelCase_      =	model_labels

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

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

                 all_logits.append(_lowercase  )

                 UpperCamelCase_      =	tfp.distributions.Bernoulli(logits=_lowercase  )
                 UpperCamelCase_      =	dist_per_token.probs_parameter() * tf.cast(_lowercase		,	tf.floataa  )

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

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

             UpperCamelCase_      =	tf.concat(tuple(_lowercase  )		,	0  )

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






     def __call__(							self		,	*_lowercase		,	**_lowercase  )->    Optional[int]:
         UpperCamelCase_      =	self._args_parser(*_lowercase		,	**_lowercase  )

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






     def   UpperCAmelCase_							(							self		,	_lowercase=None		,	_lowercase=None		,	_lowercase=None		,	**_lowercase  )->    Any:
         UpperCamelCase_      =	{}
         if padding is not None:
             UpperCamelCase_      =	padding
         if truncation is not None:
             UpperCamelCase_      =	truncation

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






     def   UpperCAmelCase_							(							self		,	_lowercase		,	_lowercase=None		,	_lowercase=True		,	_lowercase=None  )->    Any:
         if truncation is None:
             if self.type == "tapas":
                 UpperCamelCase_      =	"drop_rows_to_fit"
             else:
                 UpperCamelCase_      =	"do_not_truncate"

         UpperCamelCase_     ,					UpperCamelCase_      =	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"  )
         UpperCamelCase_      =	self.tokenizer(_lowercase		,	_lowercase		,	return_tensors=self.framework		,	truncation=_lowercase		,	padding=_lowercase  )
         UpperCamelCase_      =	table
         return inputs






     def   UpperCAmelCase_							(							self		,	_lowercase		,	_lowercase=False  )->    List[Any]:
         UpperCamelCase_      =	model_inputs.pop("table"  )

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






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

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

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

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



from __future__ import annotations




def  lowerCAmelCase(			SCREAMING_SNAKE_CASE_ )->	str:



    """simple docstring"""






    global graph, reversed_graph, scc, component, visit, stack
    if visit[u]:
        return
    UpperCamelCase_      =	True
    for v in graph[u]:
        dfs(SCREAMING_SNAKE_CASE_ )
    stack.append(SCREAMING_SNAKE_CASE_ )




def  lowerCAmelCase(			SCREAMING_SNAKE_CASE_ )->	Dict:



    """simple docstring"""






    global graph, reversed_graph, scc, component, visit, stack
    if visit[u]:
        return
    UpperCamelCase_      =	True
    component.append(SCREAMING_SNAKE_CASE_ )
    for v in reversed_graph[u]:
        dfsa(SCREAMING_SNAKE_CASE_ )




def  lowerCAmelCase(			)->	Dict:



    """simple docstring"""






    global graph, reversed_graph, scc, component, visit, stack
    for i in range(SCREAMING_SNAKE_CASE_ ):
        dfs(SCREAMING_SNAKE_CASE_ )
    UpperCamelCase_      =	[False] * n
    for i in stack[::-1]:
        if visit[i]:
            continue
        UpperCamelCase_      =	[]
        dfsa(SCREAMING_SNAKE_CASE_ )
        scc.append(SCREAMING_SNAKE_CASE_ )
    return scc


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

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

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