






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				(							UpperCAmelCase				):
					_snake_case       :					Union[str, Any]				       =   filter(lambda UpperCAmelCase				: p.requires_grad  ,  model.parameters()				)
					_snake_case       :					Optional[int]				       =   sum([np.prod(p.size()				) for p in model_parameters]				)
					return params


__lowerCAmelCase :List[Any]     =    logging.getLogger(__name__)







def    A				(							UpperCAmelCase  ,  UpperCAmelCase				):
					if metric == "rouge2":
										_snake_case       :					Union[str, Any]				       =   """{val_avg_rouge2:.4f}-{step_count}"""
					elif metric == "bleu":
										_snake_case       :					List[Any]				       =   """{val_avg_bleu:.4f}-{step_count}"""
					elif metric == "em":
										_snake_case       :					Optional[int]				       =   """{val_avg_em:.4f}-{step_count}"""
					elif metric == "loss":
										_snake_case       :					Union[str, Any]				       =   """{val_avg_loss:.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."				)

					_snake_case       :					List[str]				       =   ModelCheckpoint(
					    dirpath=UpperCAmelCase  ,  filename=UpperCAmelCase  ,  monitor=F"""val_{metric}"""  ,  mode="max"  ,  save_top_k=1  ,  every_n_epochs=1  ,  )

					return checkpoint_callback







def    A				(							UpperCAmelCase  ,  UpperCAmelCase				):
					return EarlyStopping(
					    monitor=F"""val_{metric}"""  ,  mode="min" if "loss" in metric else "max"  ,  patience=UpperCAmelCase  ,  verbose=UpperCAmelCase  ,  )






class        _a(    pl.Callback    ):







		def        lowercase       (    self ,						__snake_case ,						__snake_case				)      ->      int:


							'''simple docstring'''

							_snake_case       :					List[Any]				       =   {f"""lr_group_{i}""": param["""lr"""] for i, param in enumerate(pl_module.trainer.optimizers[0].param_groups				)}
							pl_module.logger.log_metrics(_a				)







		@rank_zero_only
		def        lowercase       (    self ,						__snake_case ,						__snake_case ,						__snake_case ,						__snake_case=True				)      ->      str:


							'''simple docstring'''

							logger.info(f"""***** {type_path} results at step {trainer.global_step:05d} *****"""				)
							_snake_case       :					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
							_snake_case       :					str				       =   Path(pl_module.hparams.output_dir				)
							if type_path == "test":
												_snake_case       :					Optional[Any]				       =   od / """test_results.txt"""
												_snake_case       :					Any				       =   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.
												_snake_case       :					Dict				       =   od / f"""{type_path}_results/{trainer.global_step:05d}.txt"""
												_snake_case       :					Dict				       =   od / f"""{type_path}_generations/{trainer.global_step:05d}.txt"""
												results_file.parent.mkdir(exist_ok=_a				)
												generations_file.parent.mkdir(exist_ok=_a				)
							with open(_a ,						"a+"				) as writer:
												for key in sorted(_a				):
																	if key in ["log", "progress_bar", "preds"]:
																						continue
																	_snake_case       :					Dict				       =   metrics[key]
																	if isinstance(_a ,						torch.Tensor				):
																						_snake_case       :					Any				       =   val.item()
																	_snake_case       :					Optional[int]				       =   f"""{key}: {val:.6f}\n"""
																	writer.write(_a				)

							if not save_generations:
												return

							if "preds" in metrics:
												_snake_case       :					List[str]				       =   """\n""".join(metrics["preds"]				)
												generations_file.open("w+"				).write(_a				)







		@rank_zero_only
		def        lowercase       (    self ,						__snake_case ,						__snake_case				)      ->      str:


							'''simple docstring'''

							try:
												_snake_case       :					Union[str, Any]				       =   pl_module.model.model.num_parameters()
							except AttributeError:
												_snake_case       :					str				       =   pl_module.model.num_parameters()

							_snake_case       :					Dict				       =   count_trainable_parameters(_a				)
							# 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        lowercase       (    self ,						__snake_case ,						__snake_case				)      ->      List[Any]:


							'''simple docstring'''

							save_json(pl_module.metrics ,						pl_module.metrics_save_path				)
							return self._write_logs(_a ,						_a ,						"test"				)







		@rank_zero_only
		def        lowercase       (    self ,						__snake_case ,						__snake_case				)      ->      str:


							'''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")






def    A				(							UpperCAmelCase				):
					if n == 1 or not isinstance(UpperCAmelCase  ,  UpperCAmelCase				):
										return 0
					elif n == 2:
										return 1
					else:
										_snake_case       :					List[Any]				       =   [0, 1]
										for i in range(2  ,  n + 1				):
															sequence.append(sequence[i - 1] + sequence[i - 2]				)

										return sequence[n]







def    A				(							UpperCAmelCase				):
					_snake_case       :					Tuple				       =   0
					_snake_case       :					Optional[Any]				       =   2

					while digits < n:
										index += 1
										_snake_case       :					str				       =   len(str(fibonacci(UpperCAmelCase				)				)				)

					return index







def    A				(							UpperCAmelCase = 1_000				):
					return fibonacci_digits_index(UpperCAmelCase				)


if __name__ == "__main__":
							print(solution(int(str(input()).strip())))