



'''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 	lowerCAmelCase_(    tf.keras.optimizers.schedules.LearningRateSchedule					):
  '''simple docstring'''




  def __init__(   self  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase = 1.0  ,__UpperCAmelCase = None  ,)   ->		Any:
      super().__init__()
      lowerCAmelCase__			:  str											= initial_learning_rate
      lowerCAmelCase__			:  Any											= warmup_steps
      lowerCAmelCase__			:  Dict											= power
      lowerCAmelCase__			:  int											= decay_schedule_fn
      lowerCAmelCase__			:  Optional[Any]											= name




  def __call__(   self  ,__UpperCAmelCase				)   ->		str:
      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__			:  Union[str, Any]											= tf.cast(__UpperCAmelCase  ,tf.floataa				)
          lowerCAmelCase__			:  str											= tf.cast(self.warmup_steps  ,tf.floataa				)
          lowerCAmelCase__			:  str											= global_step_float / warmup_steps_float
          lowerCAmelCase__			:  Dict											= self.initial_learning_rate * tf.math.pow(__UpperCAmelCase  ,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=__UpperCAmelCase  ,)






  def 							UpperCAmelCase_     (   self				)   ->		int:
      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        _SCREAMING_SNAKE_CASE  (	UpperCamelCase							,   UpperCamelCase							,   UpperCamelCase							,   UpperCamelCase = 0.0							,   UpperCamelCase = 0.9							,   UpperCamelCase = 0.999							,   UpperCamelCase = 1e-8							,   UpperCamelCase = None							,   UpperCamelCase = None							,   UpperCamelCase = 0.0							,   UpperCamelCase = 1.0							,   UpperCamelCase = None							,   ):



    """simple docstring"""





    lowerCAmelCase__			:  Dict											= tf.keras.optimizers.schedules.PolynomialDecay(
        initial_learning_rate=UpperCamelCase							,   decay_steps=num_train_steps - num_warmup_steps							,   end_learning_rate=init_lr * min_lr_ratio							,   power=UpperCamelCase							,   )
    if num_warmup_steps:
        lowerCAmelCase__			:  Dict											= WarmUp(
            initial_learning_rate=UpperCamelCase							,   decay_schedule_fn=UpperCamelCase							,   warmup_steps=UpperCamelCase							,   )
    if weight_decay_rate > 0.0:
        lowerCAmelCase__			:  Optional[Any]											= AdamWeightDecay(
            learning_rate=UpperCamelCase							,   weight_decay_rate=UpperCamelCase							,   beta_a=UpperCamelCase							,   beta_a=UpperCamelCase							,   epsilon=UpperCamelCase							,   clipnorm=UpperCamelCase							,   global_clipnorm=UpperCamelCase							,   exclude_from_weight_decay=["""LayerNorm""", """layer_norm""", """bias"""]							,   include_in_weight_decay=UpperCamelCase							,   )
    else:
        lowerCAmelCase__			:  List[str]											= tf.keras.optimizers.Adam(
            learning_rate=UpperCamelCase							,   beta_a=UpperCamelCase							,   beta_a=UpperCamelCase							,   epsilon=UpperCamelCase							,   clipnorm=UpperCamelCase							,   global_clipnorm=UpperCamelCase							,   )
    # 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 	lowerCAmelCase_(    SCREAMING_SNAKE_CASE_					):
  '''simple docstring'''




  def __init__(   self  ,__UpperCAmelCase = 0.0_0_1  ,__UpperCAmelCase = 0.9  ,__UpperCAmelCase = 0.9_9_9  ,__UpperCAmelCase = 1E-7  ,__UpperCAmelCase = False  ,__UpperCAmelCase = 0.0  ,__UpperCAmelCase = None  ,__UpperCAmelCase = None  ,__UpperCAmelCase = "AdamWeightDecay"  ,**__UpperCAmelCase  ,)   ->		Union[str, Any]:
      super().__init__(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,**__UpperCAmelCase				)
      lowerCAmelCase__			:  Optional[Any]											= weight_decay_rate
      lowerCAmelCase__			:  Optional[Any]											= include_in_weight_decay
      lowerCAmelCase__			:  Any											= exclude_from_weight_decay




  @classmethod
  def 							UpperCAmelCase_     (   cls  ,__UpperCAmelCase				)   ->		Any:
      lowerCAmelCase__			:  str											= {"""WarmUp""": WarmUp}
      return super(__UpperCAmelCase  ,cls				).from_config(__UpperCAmelCase  ,custom_objects=__UpperCAmelCase				)




  def 							UpperCAmelCase_     (   self  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase				)   ->		Optional[int]:
      super(__UpperCAmelCase  ,self				)._prepare_local(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase				)
      lowerCAmelCase__			:  str											= tf.constant(
          self.weight_decay_rate  ,name="""adam_weight_decay_rate"""				)




  def 							UpperCAmelCase_     (   self  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase				)   ->		Any:
      lowerCAmelCase__			:  str											= 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  ,__UpperCAmelCase  ,__UpperCAmelCase=None  ,**__UpperCAmelCase				)   ->		Any:
      lowerCAmelCase__			:  List[Any]											= list(zip(*__UpperCAmelCase				)				)
      return super(__UpperCAmelCase  ,self				).apply_gradients(zip(__UpperCAmelCase  ,__UpperCAmelCase				)  ,name=__UpperCAmelCase  ,**__UpperCAmelCase				)




  def 							UpperCAmelCase_     (   self  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase				)   ->		str:
      if apply_state is None:
          return self._decayed_lr_t[var_dtype], {}

      lowerCAmelCase__			:  Any											= apply_state or {}
      lowerCAmelCase__			:  Union[str, Any]											= apply_state.get((var_device, var_dtype)				)
      if coefficients is None:
          lowerCAmelCase__			:  List[Any]											= self._fallback_apply_state(__UpperCAmelCase  ,__UpperCAmelCase				)
          lowerCAmelCase__			:  Union[str, Any]											= coefficients

      return coefficients["lr_t"], {"apply_state": apply_state}




  def 							UpperCAmelCase_     (   self  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase=None				)   ->		Dict:
      lowerCAmelCase__			:  Any											= self._get_lr(var.device  ,var.dtype.base_dtype  ,__UpperCAmelCase				)
      lowerCAmelCase__			:  Dict											= self._decay_weights_op(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase				)
      with tf.control_dependencies([decay]				):
          return super(__UpperCAmelCase  ,self				)._resource_apply_dense(__UpperCAmelCase  ,__UpperCAmelCase  ,**__UpperCAmelCase				)




  def 							UpperCAmelCase_     (   self  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase=None				)   ->		List[str]:
      lowerCAmelCase__			:  Tuple											= self._get_lr(var.device  ,var.dtype.base_dtype  ,__UpperCAmelCase				)
      lowerCAmelCase__			:  Tuple											= self._decay_weights_op(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase				)
      with tf.control_dependencies([decay]				):
          return super(__UpperCAmelCase  ,self				)._resource_apply_sparse(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,**__UpperCAmelCase				)




  def 							UpperCAmelCase_     (   self				)   ->		str:
      lowerCAmelCase__			:  List[Any]											= super().get_config()
      config.update({"""weight_decay_rate""": self.weight_decay_rate}				)
      return config






  def 							UpperCAmelCase_     (   self  ,__UpperCAmelCase				)   ->		Any:
      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(__UpperCAmelCase  ,__UpperCAmelCase				) is not None:
                  return True

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







class 	lowerCAmelCase_(    SCREAMING_SNAKE_CASE_					):
  '''simple docstring'''




  def __init__(   self				)   ->		int:
      lowerCAmelCase__			:  str											= []
      lowerCAmelCase__			:  Tuple											= None




  @property
  def 							UpperCAmelCase_     (   self				)   ->		Any:
      if self._accum_steps is None:
          lowerCAmelCase__			:  List[str]											= tf.Variable(
              tf.constant(0  ,dtype=tf.intaa				)  ,trainable=__UpperCAmelCase  ,synchronization=tf.VariableSynchronization.ON_READ  ,aggregation=tf.VariableAggregation.ONLY_FIRST_REPLICA  ,)

      return self._accum_steps.value()




  @property
  def 							UpperCAmelCase_     (   self				)   ->		str:
      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  ,__UpperCAmelCase				)   ->		List[str]:
      if not self._gradients:
          lowerCAmelCase__			:  str											= self.step  # Create the step variable.
          self._gradients.extend(
              [
                  tf.Variable(
                      tf.zeros_like(__UpperCAmelCase				)  ,trainable=__UpperCAmelCase  ,synchronization=tf.VariableSynchronization.ON_READ  ,aggregation=tf.VariableAggregation.ONLY_FIRST_REPLICA  ,)
                  if gradient is not None
                  else gradient
                  for gradient in gradients
              ]				)
      if len(__UpperCAmelCase				) != len(self._gradients				):
          raise ValueError(F"""Expected {len(self._gradients				)} gradients, but got {len(__UpperCAmelCase				)}"""				)

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

      self._accum_steps.assign_add(1				)






  def 							UpperCAmelCase_     (   self				)   ->		Tuple:
      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(__UpperCAmelCase				)				)







'''simple docstring'''





import os
def        _SCREAMING_SNAKE_CASE  (	UpperCamelCase      ):



    """simple docstring"""





    lowerCAmelCase__			:  List[str]											= len(grid[0]      )
    lowerCAmelCase__			:  int											= len(UpperCamelCase      )

    lowerCAmelCase__			:  Optional[int]											= 0
    lowerCAmelCase__			:  Tuple											= 0
    lowerCAmelCase__			:  Optional[Any]											= 0

    # Check vertically, horizontally, diagonally at the same time (only works
    # for nxn grid)
    for i in range(UpperCamelCase      ):
        for j in range(n_rows - 3      ):
            lowerCAmelCase__			:  str											= grid[j][i] * grid[j + 1][i] * grid[j + 2][i] * grid[j + 3][i]
            lowerCAmelCase__			:  Optional[int]											= grid[i][j] * grid[i][j + 1] * grid[i][j + 2] * grid[i][j + 3]

            # Left-to-right diagonal (\) product
            if i < n_columns - 3:
                lowerCAmelCase__			:  Optional[int]											= (
                    grid[i][j]
                    * grid[i + 1][j + 1]
                    * grid[i + 2][j + 2]
                    * grid[i + 3][j + 3]
                )

            # Right-to-left diagonal(/) product
            if i > 2:
                lowerCAmelCase__			:  Tuple											= (
                    grid[i][j]
                    * grid[i - 1][j + 1]
                    * grid[i - 2][j + 2]
                    * grid[i - 3][j + 3]
                )

            lowerCAmelCase__			:  Dict											= max(
                UpperCamelCase							,   UpperCamelCase							,   UpperCamelCase							,   UpperCamelCase      )
            if max_product > largest:
                lowerCAmelCase__			:  Any											= max_product

    return largest
def        _SCREAMING_SNAKE_CASE  (	):



    """simple docstring"""





    lowerCAmelCase__			:  List[str]											= []
    with open(os.path.dirname(UpperCamelCase      ) + """/grid.txt"""      ) as file:
        for line in file:
            grid.append(line.strip("""\n"""      ).split(""" """      )      )

    lowerCAmelCase__			:  Dict											= [[int(UpperCamelCase      ) for i in grid[j]] for j in range(len(UpperCamelCase      )      )]

    return largest_product(UpperCamelCase      )


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


