


"""simple docstring"""


import re
from typing import Callable, List, Optional, Union

import tensorflow as tf


try:
   from tensorflow.keras.optimizers.legacy import Adam
except ImportError:
   from tensorflow.keras.optimizers import Adam



class 	_a   (   tf.keras.optimizers.schedules.LearningRateSchedule			):
    def __init__(			self				:       Union[str, Any]				,       SCREAMING_SNAKE_CASE__				:       float				,       SCREAMING_SNAKE_CASE__				:       Callable				,       SCREAMING_SNAKE_CASE__				:       int				,       SCREAMING_SNAKE_CASE__				:       float = 1.0				,       SCREAMING_SNAKE_CASE__				:       str = None				,       ):
          super().__init__()
          lowerCamelCase__							     =		initial_learning_rate
          lowerCamelCase__							     =		warmup_steps
          lowerCamelCase__							     =		power
          lowerCamelCase__							     =		decay_schedule_fn
          lowerCamelCase__							     =		name
    def __call__(			self				:       Any				,       SCREAMING_SNAKE_CASE__				:       int					):
          with tf.name_scope(self.name or 'WarmUp'					) as name:
                # Implements polynomial warmup. i.e., if global_step < warmup_steps, the
                # learning rate will be `global_step/num_warmup_steps * init_lr`.
                lowerCamelCase__							     =		tf.cast(_lowerCAmelCase				,       tf.floataa					)
                lowerCamelCase__							     =		tf.cast(self.warmup_steps				,       tf.floataa					)
                lowerCamelCase__							     =		global_step_float / warmup_steps_float
                lowerCamelCase__							     =		self.initial_learning_rate * tf.math.pow(_lowerCAmelCase				,       self.power					)
                return tf.cond(
                    global_step_float < warmup_steps_float				,       lambda: warmup_learning_rate				,       lambda: self.decay_schedule_fn(step - self.warmup_steps					)				,       name=_lowerCAmelCase				,       )


    def   _UpperCamelCase							(			self				:       Optional[Any]					):
          return {
              "initial_learning_rate": self.initial_learning_rate,
              "decay_schedule_fn": self.decay_schedule_fn,
              "warmup_steps": self.warmup_steps,
              "power": self.power,
              "name": self.name,
          }





def 	snake_case    (					_a:  float		, _a:  int		, _a:  int		, _a:  float = 0.0		, _a:  float = 0.9		, _a:  float = 0.999		, _a:  float = 1E-8		, _a:  Optional[float] = None		, _a:  Optional[float] = None		, _a:  float = 0.0		, _a:  float = 1.0		, _a:  Optional[List[str]] = None		, )->		Optional[Any]:
      '''simple docstring'''


      lowerCamelCase__							     =		tf.keras.optimizers.schedules.PolynomialDecay(
          initial_learning_rate=lowerCAmelCase_		, decay_steps=num_train_steps - num_warmup_steps		, end_learning_rate=init_lr * min_lr_ratio		, power=lowerCAmelCase_		, )
      if num_warmup_steps:
            lowerCamelCase__							     =		WarmUp(
                initial_learning_rate=lowerCAmelCase_		, decay_schedule_fn=lowerCAmelCase_		, warmup_steps=lowerCAmelCase_		, )
      if weight_decay_rate > 0.0:
            lowerCamelCase__							     =		AdamWeightDecay(
                learning_rate=lowerCAmelCase_		, weight_decay_rate=lowerCAmelCase_		, beta_a=lowerCAmelCase_		, beta_a=lowerCAmelCase_		, epsilon=lowerCAmelCase_		, clipnorm=lowerCAmelCase_		, global_clipnorm=lowerCAmelCase_		, exclude_from_weight_decay=['LayerNorm', 'layer_norm', 'bias']		, include_in_weight_decay=lowerCAmelCase_		, )
      else:
            lowerCamelCase__							     =		tf.keras.optimizers.Adam(
                learning_rate=lowerCAmelCase_		, beta_a=lowerCAmelCase_		, beta_a=lowerCAmelCase_		, epsilon=lowerCAmelCase_		, clipnorm=lowerCAmelCase_		, global_clipnorm=lowerCAmelCase_		, )
      # We return the optimizer and the LR scheduler in order to better track the
      # evolution of the LR independently of the optimizer.
      return optimizer, lr_schedule



class 	_a   (   SCREAMING_SNAKE_CASE_			):
    def __init__(			self				:       Dict				,       SCREAMING_SNAKE_CASE__				:       Union[float, tf.keras.optimizers.schedules.LearningRateSchedule] = 0.0_01				,       SCREAMING_SNAKE_CASE__				:       float = 0.9				,       SCREAMING_SNAKE_CASE__				:       float = 0.9_99				,       SCREAMING_SNAKE_CASE__				:       float = 1e-7				,       SCREAMING_SNAKE_CASE__				:       bool = False				,       SCREAMING_SNAKE_CASE__				:       float = 0.0				,       SCREAMING_SNAKE_CASE__				:       Optional[List[str]] = None				,       SCREAMING_SNAKE_CASE__				:       Optional[List[str]] = None				,       SCREAMING_SNAKE_CASE__				:       str = "AdamWeightDecay"				,       **SCREAMING_SNAKE_CASE__				:       Union[str, Any]				,       ):
          super().__init__(_lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase				,       **_lowerCAmelCase					)
          lowerCamelCase__							     =		weight_decay_rate
          lowerCamelCase__							     =		include_in_weight_decay
          lowerCamelCase__							     =		exclude_from_weight_decay
    @classmethod
    def   _UpperCamelCase							(			cls				:       Dict				,       SCREAMING_SNAKE_CASE__				:       Optional[Any]					):
          lowerCamelCase__							     =		{'WarmUp': WarmUp}
          return super(_lowerCAmelCase				,       cls					).from_config(_lowerCAmelCase				,       custom_objects=_lowerCAmelCase					)
    def   _UpperCamelCase							(			self				:       List[Any]				,       SCREAMING_SNAKE_CASE__				:       Union[str, Any]				,       SCREAMING_SNAKE_CASE__				:       int				,       SCREAMING_SNAKE_CASE__				:       Optional[int]					):
          super(_lowerCAmelCase				,       self					)._prepare_local(_lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase					)
          lowerCamelCase__							     =		tf.constant(
              self.weight_decay_rate				,       name='adam_weight_decay_rate'					)
    def   _UpperCamelCase							(			self				:       Optional[Any]				,       SCREAMING_SNAKE_CASE__				:       List[Any]				,       SCREAMING_SNAKE_CASE__				:       Optional[Any]				,       SCREAMING_SNAKE_CASE__				:       List[Any]					):
          lowerCamelCase__							     =		self._do_use_weight_decay(var.name					)
          if do_decay:
                return var.assign_sub(
                    learning_rate * var * apply_state[(var.device, var.dtype.base_dtype)]['weight_decay_rate']				,       use_locking=self._use_locking				,       )
          return tf.no_op()
    def   _UpperCamelCase							(			self				:       List[str]				,       SCREAMING_SNAKE_CASE__				:       str				,       SCREAMING_SNAKE_CASE__				:       Optional[int]=None				,       **SCREAMING_SNAKE_CASE__				:       Dict					):
          lowerCamelCase__     ,	lowerCamelCase__							     =		list(zip(*_lowerCAmelCase					)					)
          return super(_lowerCAmelCase				,       self					).apply_gradients(zip(_lowerCAmelCase				,       _lowerCAmelCase					)				,       name=_lowerCAmelCase				,       **_lowerCAmelCase					)
    def   _UpperCamelCase							(			self				:       List[str]				,       SCREAMING_SNAKE_CASE__				:       Union[str, Any]				,       SCREAMING_SNAKE_CASE__				:       Optional[Any]				,       SCREAMING_SNAKE_CASE__				:       Optional[int]					):
          if apply_state is None:
                return self._decayed_lr_t[var_dtype], {}

          lowerCamelCase__							     =		apply_state or {}
          lowerCamelCase__							     =		apply_state.get((var_device, var_dtype)					)
          if coefficients is None:
                lowerCamelCase__							     =		self._fallback_apply_state(_lowerCAmelCase				,       _lowerCAmelCase					)
                lowerCamelCase__							     =		coefficients

          return coefficients["lr_t"], {"apply_state": apply_state}
    def   _UpperCamelCase							(			self				:       int				,       SCREAMING_SNAKE_CASE__				:       List[Any]				,       SCREAMING_SNAKE_CASE__				:       Optional[int]				,       SCREAMING_SNAKE_CASE__				:       Tuple=None					):
          lowerCamelCase__     ,	lowerCamelCase__							     =		self._get_lr(var.device				,       var.dtype.base_dtype				,       _lowerCAmelCase					)
          lowerCamelCase__							     =		self._decay_weights_op(_lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase					)
          with tf.control_dependencies([decay]					):
                return super(_lowerCAmelCase				,       self					)._resource_apply_dense(_lowerCAmelCase				,       _lowerCAmelCase				,       **_lowerCAmelCase					)
    def   _UpperCamelCase							(			self				:       List[Any]				,       SCREAMING_SNAKE_CASE__				:       Any				,       SCREAMING_SNAKE_CASE__				:       str				,       SCREAMING_SNAKE_CASE__				:       Any				,       SCREAMING_SNAKE_CASE__				:       Tuple=None					):
          lowerCamelCase__     ,	lowerCamelCase__							     =		self._get_lr(var.device				,       var.dtype.base_dtype				,       _lowerCAmelCase					)
          lowerCamelCase__							     =		self._decay_weights_op(_lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase					)
          with tf.control_dependencies([decay]					):
                return super(_lowerCAmelCase				,       self					)._resource_apply_sparse(_lowerCAmelCase				,       _lowerCAmelCase				,       _lowerCAmelCase				,       **_lowerCAmelCase					)
    def   _UpperCamelCase							(			self				:       Union[str, Any]					):
          lowerCamelCase__							     =		super().get_config()
          config.update({'weight_decay_rate': self.weight_decay_rate}					)
          return config


    def   _UpperCamelCase							(			self				:       Union[str, Any]				,       SCREAMING_SNAKE_CASE__				:       List[str]					):
          if self.weight_decay_rate == 0:
                return False

          if self._include_in_weight_decay:
                for r in self._include_in_weight_decay:
                      if re.search(_lowerCAmelCase				,       _lowerCAmelCase					) is not None:
                            return True

          if self._exclude_from_weight_decay:
                for r in self._exclude_from_weight_decay:
                      if re.search(_lowerCAmelCase				,       _lowerCAmelCase					) is not None:
                            return False
          return True





class 	_a   (   SCREAMING_SNAKE_CASE_			):
    def __init__(			self				:       str					):
          lowerCamelCase__							     =		[]
          lowerCamelCase__							     =		None
    @property
    def   _UpperCamelCase							(			self				:       Dict					):
          if self._accum_steps is None:
                lowerCamelCase__							     =		tf.Variable(
                    tf.constant(0				,       dtype=tf.intaa					)				,       trainable=_lowerCAmelCase				,       synchronization=tf.VariableSynchronization.ON_READ				,       aggregation=tf.VariableAggregation.ONLY_FIRST_REPLICA				,       )

          return self._accum_steps.value()
    @property
    def   _UpperCamelCase							(			self				:       Tuple					):
          if not self._gradients:
                raise ValueError('The accumulator should be called first to initialize the gradients'					)
          return [gradient.value() if gradient is not None else gradient for gradient in self._gradients]
    def __call__(			self				:       List[Any]				,       SCREAMING_SNAKE_CASE__				:       Union[str, Any]					):
          if not self._gradients:
                lowerCamelCase__							     =		self.step  # Create the step variable.
                self._gradients.extend(
                    [
                        tf.Variable(
                            tf.zeros_like(_lowerCAmelCase					)				,       trainable=_lowerCAmelCase				,       synchronization=tf.VariableSynchronization.ON_READ				,       aggregation=tf.VariableAggregation.ONLY_FIRST_REPLICA				,       )
                        if gradient is not None
                        else gradient
                        for gradient in gradients
                    ]					)
          if len(_lowerCAmelCase					) != len(self._gradients					):
                raise ValueError(F'Expected {len(self._gradients					)} gradients, but got {len(_lowerCAmelCase					)}'					)

          for accum_gradient, gradient in zip(self._gradients				,       _lowerCAmelCase					):
                if accum_gradient is not None and gradient is not None:
                      accum_gradient.assign_add(_lowerCAmelCase					)

          self._accum_steps.assign_add(1					)


    def   _UpperCamelCase							(			self				:       Union[str, Any]					):
          if not self._gradients:
                return
          self._accum_steps.assign(0					)
          for gradient in self._gradients:
                if gradient is not None:
                      gradient.assign(tf.zeros_like(_lowerCAmelCase					)					)







from math import factorial



def       _lowerCAmelCase    (				lowerCAmelCase_				:int = 20				)->int:
   '''simple docstring'''






   snake_case_            =       2 * n  # middle entry of odd rows starting at row 3 is the solution for n = 1,
   # 2, 3,...
   snake_case_            =       n // 2

   return int(factorial(lowerCAmelCase_				) / (factorial(lowerCAmelCase_				) * factorial(n - k				))				)


if __name__ == "__main__":
   import sys

   if len(sys.argv) == 1:
      print(solution(20))
   else:
      try:
         SCREAMING_SNAKE_CASE						:Any			=  int(sys.argv[1])
         print(solution(n))
      except ValueError:
         print('''Invalid entry - please enter a number.''')




