


'''simple docstring'''
import logging
from pathlib import Path

import numpy as np
import pytorch_lightning as pl
import torch
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
from pytorch_lightning.utilities import rank_zero_only
from utils_rag import save_json


def 			a      (			__a   )  ->	Tuple:



					'''simple docstring'''






					UpperCamelCase__   :List[Any]												= filter(lambda __a   : p.requires_grad ,					model.parameters()   )
					UpperCamelCase__   :Any												= sum([np.prod(p.size()   ) for p in model_parameters]   )
					return params


__snake_case							      =     logging.getLogger(__name__)


def 			a      (			__a ,					__a   )  ->	Tuple:



					'''simple docstring'''






					if metric == "rouge2":
										UpperCamelCase__   :Tuple												= '''{val_avg_rouge2:.4f}-{step_count}'''
					elif metric == "bleu":
										UpperCamelCase__   :Dict												= '''{val_avg_bleu:.4f}-{step_count}'''
					elif metric == "em":
										UpperCamelCase__   :Optional[int]												= '''{val_avg_em:.4f}-{step_count}'''
					else:
										raise NotImplementedError(
										    f'''seq2seq callbacks only support rouge2 and bleu, got {metric}, You can make your own by adding to this'''
										    ''' function.'''   )

					UpperCamelCase__   :Union[str, Any]												= ModelCheckpoint(
					    dirpath=__a ,					filename=__a ,					monitor=f'''val_{metric}''' ,					mode='''max''' ,					save_top_k=3 ,					every_n_epochs=1 ,					)
					return checkpoint_callback


def 			a      (			__a ,					__a   )  ->	Any:



					'''simple docstring'''






					return EarlyStopping(
					    monitor=f'''val_{metric}''' ,					mode='''min''' if '''loss''' in metric else '''max''' ,					patience=__a ,					verbose=__a ,					)







class    lowercase	(							pl.Callback					):

		"""simple docstring"""

		def     lowerCAmelCase__				(		self    ,   UpperCamelCase_    ,   UpperCamelCase_							):

							'''simple docstring'''


							UpperCamelCase__   :Dict												= {F'''lr_group_{i}''': param['''lr'''] for i, param in enumerate(pl_module.trainer.optimizers[0].param_groups							)}
							pl_module.logger.log_metrics(UpperCamelCase_							)




		@rank_zero_only
		def     lowerCAmelCase__				(		self    ,   UpperCamelCase_    ,   UpperCamelCase_    ,   UpperCamelCase_    ,   UpperCamelCase_=True							):

							'''simple docstring'''


							logger.info(F'''***** {type_path} results at step {trainer.global_step:05d} *****'''							)
							UpperCamelCase__   :int												= trainer.callback_metrics
							trainer.logger.log_metrics({k: v for k, v in metrics.items() if k not in ['''log''', '''progress_bar''', '''preds''']}							)
							# Log results
							UpperCamelCase__   :Any												= Path(pl_module.hparams.output_dir							)
							if type_path == "test":
												UpperCamelCase__   :str												= od / '''test_results.txt'''
												UpperCamelCase__   :Dict												= od / '''test_generations.txt'''
							else:
												# this never gets hit. I prefer not to save intermediate generations, and results are in metrics.json
												# If people want this it will be easy enough to add back.
												UpperCamelCase__   :str												= od / F'''{type_path}_results/{trainer.global_step:05d}.txt'''
												UpperCamelCase__   :List[str]												= od / F'''{type_path}_generations/{trainer.global_step:05d}.txt'''
												results_file.parent.mkdir(exist_ok=UpperCamelCase_							)
												generations_file.parent.mkdir(exist_ok=UpperCamelCase_							)
							with open(UpperCamelCase_    ,   '''a+'''							) as writer:
												for key in sorted(UpperCamelCase_							):
																	if key in ["log", "progress_bar", "preds"]:
																						continue
																	UpperCamelCase__   :Union[str, Any]												= metrics[key]
																	if isinstance(UpperCamelCase_    ,   torch.Tensor							):
																						UpperCamelCase__   :Tuple												= val.item()
																	UpperCamelCase__   :int												= F'''{key}: {val:.6f}\n'''
																	writer.write(UpperCamelCase_							)

							if not save_generations:
												return

							if "preds" in metrics:
												UpperCamelCase__   :List[Any]												= '''\n'''.join(metrics['''preds''']							)
												generations_file.open('''w+'''							).write(UpperCamelCase_							)




		@rank_zero_only
		def     lowerCAmelCase__				(		self    ,   UpperCamelCase_    ,   UpperCamelCase_							):

							'''simple docstring'''


							try:
												UpperCamelCase__   :Dict												= pl_module.model.model.num_parameters()
							except AttributeError:
												UpperCamelCase__   :str												= pl_module.model.num_parameters()

							UpperCamelCase__   :Optional[Any]												= count_trainable_parameters(UpperCamelCase_							)
							# mp stands for million parameters
							trainer.logger.log_metrics({'''n_params''': npars, '''mp''': npars / 1e6, '''grad_mp''': n_trainable_pars / 1e6}							)




		@rank_zero_only
		def     lowerCAmelCase__				(		self    ,   UpperCamelCase_    ,   UpperCamelCase_							):

							'''simple docstring'''


							save_json(pl_module.metrics    ,   pl_module.metrics_save_path							)
							return self._write_logs(UpperCamelCase_    ,   UpperCamelCase_    ,   '''test'''							)




		@rank_zero_only
		def     lowerCAmelCase__				(		self    ,   UpperCamelCase_    ,   UpperCamelCase_							):

							'''simple docstring'''


							save_json(pl_module.metrics    ,   pl_module.metrics_save_path							)
							# Uncommenting this will save val generations
							# return self._write_logs(trainer, pl_module, "valid")



'''simple docstring'''
def 			a      (			)  ->	Union[str, Any]:



					'''simple docstring'''






					UpperCamelCase__   :Optional[int]												= []
					UpperCamelCase__   :int												= 1

					while len(__a   ) < 1e6:
										constant.append(str(__a   )   )
										i += 1

					UpperCamelCase__   :Union[str, Any]												= ''''''.join(__a   )

					return (
					    int(constant[0]   )
					    * int(constant[9]   )
					    * int(constant[99]   )
					    * int(constant[999]   )
					    * int(constant[9999]   )
					    * int(constant[99999]   )
					    * int(constant[999999]   )
					)


if __name__ == "__main__":
		print(solution())