

'''simple docstring'''

# We ignore warnings about stepping the scheduler since we step it ourselves during gradient accumulation

import warnings

from .state import AcceleratorState, GradientState


warnings.filterwarnings('''ignore''', category=UserWarning, module='''torch.optim.lr_scheduler''')


class 	lowerCAmelCase  :







       def __init__(				self      :			Dict    ,   __lowercase      :			List[Any]    ,   __lowercase      :			List[Any]    ,   __lowercase      :			bool = True    ,   __lowercase      :			bool = False   ):







            """simple docstring"""







            __lowercase      		=scheduler
            __lowercase      		=optimizers if isinstance(__lowercase    ,   (list, tuple)   ) else [optimizers]
            __lowercase      		=split_batches
            __lowercase      		=step_with_optimizer
            __lowercase      		=GradientState()







       def       snake_case (				self      :			Any    ,   *__lowercase      :			Union[str, Any]    ,   **__lowercase      :			List[str]   ):







            """simple docstring"""







            if not self.step_with_optimizer:
                 # No link between scheduler and optimizer -> just step
                 self.scheduler.step(*__lowercase    ,   **__lowercase   )
                 return

            # Otherwise, first make sure the optimizer was stepped.
            if not self.gradient_state.sync_gradients:
                 if self.gradient_state.adjust_scheduler:
                      self.scheduler._step_count += 1
                 return

            for opt in self.optimizers:
                 if opt.step_was_skipped:
                      return
            if self.split_batches:
                 # Split batches -> the training dataloader batch size is not changed so one step per training step
                 self.scheduler.step(*__lowercase    ,   **__lowercase   )
            else:
                 # Otherwise the training dataloader batch size was multiplied by `num_processes`, so we need to do
                 # num_processes steps per training step
                 __lowercase      		=AcceleratorState().num_processes
                 for _ in range(__lowercase   ):
                      # Special case when using OneCycle and `drop_last` was not used
                      if hasattr(self.scheduler    ,   'total_steps'   ):
                           if self.scheduler._step_count <= self.scheduler.total_steps:
                                self.scheduler.step(*__lowercase    ,   **__lowercase   )
                      else:
                           self.scheduler.step(*__lowercase    ,   **__lowercase   )







       def       snake_case (				self      :			Tuple   ):







            """simple docstring"""







            return self.scheduler.get_last_lr()







       def       snake_case (				self      :			str   ):







            """simple docstring"""







            return self.scheduler.state_dict()







       def       snake_case (				self      :			List[str]    ,   __lowercase      :			int   ):







            """simple docstring"""







            self.scheduler.load_state_dict(__lowercase   )







       def       snake_case (				self      :			Union[str, Any]   ):







            """simple docstring"""







            return self.scheduler.get_lr()







       def       snake_case (				self      :			List[Any]    ,   *__lowercase      :			List[Any]    ,   **__lowercase      :			Tuple   ):







            """simple docstring"""







            return self.scheduler.print_lr(*__lowercase    ,   **__lowercase   )





'''simple docstring'''

def 					__UpperCamelCase				(						lowercase__    :	int			):






     '''simple docstring'''





     if upper_limit < 0:
          raise ValueError('Limit for the Catalan sequence must be ≥ 0'			)

     __lowercase      		=[0] * (upper_limit + 1)

     # Base case: C(0) = C(1) = 1
     __lowercase      		=1
     if upper_limit > 0:
          __lowercase      		=1

     # Recurrence relation: C(i) = sum(C(j).C(i-j-1)), from j = 0 to i
     for i in range(2,       upper_limit + 1			):
          for j in range(lowercase__			):
               catalan_list[i] += catalan_list[j] * catalan_list[i - j - 1]

     return catalan_list


if __name__ == "__main__":
       print('''\n********* Catalan Numbers Using Dynamic Programming ************\n''')
       print('''\n*** Enter -1 at any time to quit ***''')
       print('''\nEnter the upper limit (≥ 0) for the Catalan number sequence: ''', end='''''')
       try:
              while True:
                     UpperCAmelCase					 =	int(input().strip())
                     if N < 0:
                            print('''\n********* Goodbye!! ************''')
                            break
                     else:
                            print(F'''The Catalan numbers from 0 through {N} are:''')
                            print(catalan_numbers(N))
                            print('''Try another upper limit for the sequence: ''', end='''''')
       except (NameError, ValueError):
              print('''\n********* Invalid input, goodbye! ************\n''')

       import doctest

       doctest.testmod()


