


from __future__ import annotations

import math


def        _UpperCamelCase							(      lowercase__    ,       lowercase__      ):
						if len(lowercase__      ) != 2 or len(a[0]      ) != 2 or len(lowercase__      ) != 2 or len(b[0]      ) != 2:
												raise Exception('''Matrices are not 2x2'''      )
						__SCREAMING_SNAKE_CASE						:     str					=		[
						    [a[0][0] * b[0][0] + a[0][1] * b[1][0], a[0][0] * b[0][1] + a[0][1] * b[1][1]],
						    [a[1][0] * b[0][0] + a[1][1] * b[1][0], a[1][0] * b[0][1] + a[1][1] * b[1][1]],
						]
						return new_matrix


def        _UpperCamelCase							(      lowercase__    ,       lowercase__      ):
						return [
						    [matrix_a[row][col] + matrix_b[row][col] for col in range(len(matrix_a[row]      )      )]
						    for row in range(len(lowercase__      )      )
						]


def        _UpperCamelCase							(      lowercase__    ,       lowercase__      ):
						return [
						    [matrix_a[row][col] - matrix_b[row][col] for col in range(len(matrix_a[row]      )      )]
						    for row in range(len(lowercase__      )      )
						]


def        _UpperCamelCase							(      lowercase__      ):
						if len(lowercase__      ) % 2 != 0 or len(a[0]      ) % 2 != 0:
												raise Exception('''Odd matrices are not supported!'''      )

						__SCREAMING_SNAKE_CASE						:     int					=		len(lowercase__      )
						__SCREAMING_SNAKE_CASE						:     List[str]					=		matrix_length // 2

						__SCREAMING_SNAKE_CASE						:     Tuple					=		[[a[i][j] for j in range(lowercase__    ,       lowercase__      )] for i in range(lowercase__      )]
						__SCREAMING_SNAKE_CASE						:     Optional[Any]					=		[
						    [a[i][j] for j in range(lowercase__    ,       lowercase__      )] for i in range(lowercase__    ,       lowercase__      )
						]

						__SCREAMING_SNAKE_CASE						:     int					=		[[a[i][j] for j in range(lowercase__      )] for i in range(lowercase__      )]
						__SCREAMING_SNAKE_CASE						:     int					=		[[a[i][j] for j in range(lowercase__      )] for i in range(lowercase__    ,       lowercase__      )]

						return top_left, top_right, bot_left, bot_right


def        _UpperCamelCase							(      lowercase__      ):
						return len(lowercase__      ), len(matrix[0]      )


def        _UpperCamelCase							(      lowercase__      ):
						print('''\n'''.join(str(lowercase__      ) for line in matrix      )      )


def        _UpperCamelCase							(      lowercase__    ,       lowercase__      ):
						if matrix_dimensions(lowercase__      ) == (2, 2):
												return default_matrix_multiplication(lowercase__    ,       lowercase__      )

						__SCREAMING_SNAKE_CASE			,			__SCREAMING_SNAKE_CASE			,			__SCREAMING_SNAKE_CASE			,			__SCREAMING_SNAKE_CASE						:     List[str]					=		split_matrix(lowercase__      )
						__SCREAMING_SNAKE_CASE			,			__SCREAMING_SNAKE_CASE			,			__SCREAMING_SNAKE_CASE			,			__SCREAMING_SNAKE_CASE						:     Optional[int]					=		split_matrix(lowercase__      )

						__SCREAMING_SNAKE_CASE						:     str					=		actual_strassen(lowercase__    ,       matrix_subtraction(lowercase__    ,       lowercase__      )      )
						__SCREAMING_SNAKE_CASE						:     List[str]					=		actual_strassen(matrix_addition(lowercase__    ,       lowercase__      )    ,       lowercase__      )
						__SCREAMING_SNAKE_CASE						:     List[str]					=		actual_strassen(matrix_addition(lowercase__    ,       lowercase__      )    ,       lowercase__      )
						__SCREAMING_SNAKE_CASE						:     int					=		actual_strassen(lowercase__    ,       matrix_subtraction(lowercase__    ,       lowercase__      )      )
						__SCREAMING_SNAKE_CASE						:     int					=		actual_strassen(matrix_addition(lowercase__    ,       lowercase__      )    ,       matrix_addition(lowercase__    ,       lowercase__      )      )
						__SCREAMING_SNAKE_CASE						:     Optional[Any]					=		actual_strassen(matrix_subtraction(lowercase__    ,       lowercase__      )    ,       matrix_addition(lowercase__    ,       lowercase__      )      )
						__SCREAMING_SNAKE_CASE						:     Optional[Any]					=		actual_strassen(matrix_subtraction(lowercase__    ,       lowercase__      )    ,       matrix_addition(lowercase__    ,       lowercase__      )      )

						__SCREAMING_SNAKE_CASE						:     Optional[int]					=		matrix_addition(matrix_subtraction(matrix_addition(lowercase__    ,       lowercase__      )    ,       lowercase__      )    ,       lowercase__      )
						__SCREAMING_SNAKE_CASE						:     Tuple					=		matrix_addition(lowercase__    ,       lowercase__      )
						__SCREAMING_SNAKE_CASE						:     Optional[int]					=		matrix_addition(lowercase__    ,       lowercase__      )
						__SCREAMING_SNAKE_CASE						:     Optional[Any]					=		matrix_subtraction(matrix_subtraction(matrix_addition(lowercase__    ,       lowercase__      )    ,       lowercase__      )    ,       lowercase__      )

						# construct the new matrix from our 4 quadrants
						__SCREAMING_SNAKE_CASE						:     int					=		[]
						for i in range(len(lowercase__      )      ):
												new_matrix.append(top_left[i] + top_right[i]      )
						for i in range(len(lowercase__      )      ):
												new_matrix.append(bot_left[i] + bot_right[i]      )
						return new_matrix


def        _UpperCamelCase							(      lowercase__    ,       lowercase__      ):
						if matrix_dimensions(lowercase__      )[1] != matrix_dimensions(lowercase__      )[0]:
												__SCREAMING_SNAKE_CASE						:     str					=		(
												    '''Unable to multiply these matrices, please check the dimensions.\n'''
												    F'''Matrix A: {matrixa}\n'''
												    F'''Matrix B: {matrixa}'''
												)
												raise Exception(lowercase__      )
						__SCREAMING_SNAKE_CASE						:     int					=		matrix_dimensions(lowercase__      )
						__SCREAMING_SNAKE_CASE						:     int					=		matrix_dimensions(lowercase__      )

						if dimensiona[0] == dimensiona[1] and dimensiona[0] == dimensiona[1]:
												return [matrixa, matrixa]

						__SCREAMING_SNAKE_CASE						:     Optional[int]					=		max(*lowercase__    ,       *lowercase__      )
						__SCREAMING_SNAKE_CASE						:     Tuple					=		int(math.pow(2    ,       math.ceil(math.loga(lowercase__      )      )      )      )
						__SCREAMING_SNAKE_CASE						:     str					=		matrixa
						__SCREAMING_SNAKE_CASE						:     List[str]					=		matrixa

						# Adding zeros to the matrices so that the arrays dimensions are the same and also
						# power of 2
						for i in range(0    ,       lowercase__      ):
												if i < dimensiona[0]:
																		for _ in range(dimensiona[1]    ,       lowercase__      ):
																								new_matrixa[i].append(0      )
												else:
																		new_matrixa.append([0] * maxim      )
												if i < dimensiona[0]:
																		for _ in range(dimensiona[1]    ,       lowercase__      ):
																								new_matrixa[i].append(0      )
												else:
																		new_matrixa.append([0] * maxim      )

						__SCREAMING_SNAKE_CASE						:     int					=		actual_strassen(lowercase__    ,       lowercase__      )

						# Removing the additional zeros
						for i in range(0    ,       lowercase__      ):
												if i < dimensiona[0]:
																		for _ in range(dimensiona[1]    ,       lowercase__      ):
																								final_matrix[i].pop()
												else:
																		final_matrix.pop()
						return final_matrix


if __name__ == "__main__":
						__lowerCAmelCase	: str  				=[
						    [2, 3, 4, 5],
						    [6, 4, 3, 1],
						    [2, 3, 6, 7],
						    [3, 1, 2, 4],
						    [2, 3, 4, 5],
						    [6, 4, 3, 1],
						    [2, 3, 6, 7],
						    [3, 1, 2, 4],
						    [2, 3, 4, 5],
						    [6, 2, 3, 1],
						]
						__lowerCAmelCase	: Any  				=[[0, 2, 1, 1], [1_6, 2, 3, 3], [2, 2, 7, 7], [1_3, 1_1, 2_2, 4]]
						print(strassen(matrixa, matrixa))




'''simple docstring'''
def 			a      (			__a   )  ->	"list[int]":



					'''simple docstring'''






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

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

					# Base case: C(0) = C(1) = 1
					UpperCamelCase__   :int												= 1
					if upper_limit > 0:
										UpperCamelCase__   :int												= 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:
						__snake_case							      =     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()