

def 					__lowercase      (     _A			)     ->						Optional[Any]:
      if upper_limit < 0:
            raise ValueError("""Limit for the Catalan sequence must be ≥ 0"""			)

      SCREAMING_SNAKE_CASE :      Any       =   [0] * (upper_limit + 1)

      # Base case: C(0) = C(1) = 1
      SCREAMING_SNAKE_CASE :      Any       =   1
      if upper_limit > 0:
            SCREAMING_SNAKE_CASE :      Dict       =   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(_A			):
                  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__ :     str				    =    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()







from __future__ import annotations

import numpy as np






def 					__lowercase      (     _A			)     ->						tuple[np.ndarray, np.ndarray]:
      SCREAMING_SNAKE_CASE     ,	SCREAMING_SNAKE_CASE :      Dict       =   np.shape(_A			)
      if rows != columns:
            SCREAMING_SNAKE_CASE :      int       =   (
                """'table' has to be of square shaped array but got a """
                F"{rows}x{columns} array:\n{table}"
            )
            raise ValueError(_A			)

      SCREAMING_SNAKE_CASE :      Union[str, Any]       =   np.zeros((rows, columns)			)
      SCREAMING_SNAKE_CASE :      Optional[Any]       =   np.zeros((rows, columns)			)
      for i in range(_A			):
            for j in range(_A			):
                  SCREAMING_SNAKE_CASE :      Tuple       =   sum(lower[i][k] * upper[k][j] for k in range(_A			)			)
                  if upper[j][j] == 0:
                        raise ArithmeticError("""No LU decomposition exists"""			)
                  SCREAMING_SNAKE_CASE :      Union[str, Any]       =   (table[i][j] - total) / upper[j][j]
            SCREAMING_SNAKE_CASE :      Optional[Any]       =   1
            for j in range(_A						,    _A			):
                  SCREAMING_SNAKE_CASE :      List[str]       =   sum(lower[i][k] * upper[k][j] for k in range(_A			)			)
                  SCREAMING_SNAKE_CASE :      Optional[Any]       =   table[i][j] - total
      return lower, upper


if __name__ == "__main__":
  import doctest

  doctest.testmod()




