

from __future__ import annotations

import math






def        snake_case__		(    lowerCamelCase_     ,				lowerCamelCase_		):
							if len(lowerCamelCase_		) != 2 or len(a[0]		) != 2 or len(lowerCamelCase_		) != 2 or len(b[0]		) != 2:
														raise Exception('''Matrices are not 2x2'''		)
							A      :					List[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        snake_case__		(    lowerCamelCase_     ,				lowerCamelCase_		):
							return [
							    [matrix_a[row][col] + matrix_b[row][col] for col in range(len(matrix_a[row]		)		)]
							    for row in range(len(lowerCamelCase_		)		)
							]






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






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

							A      :					Optional[Any]      		=					len(lowerCamelCase_		)
							A      :					str      		=					matrix_length // 2

							A      :					Dict      		=					[[a[i][j] for j in range(lowerCamelCase_     ,				lowerCamelCase_		)] for i in range(lowerCamelCase_		)]
							A      :					str      		=					[
							    [a[i][j] for j in range(lowerCamelCase_     ,				lowerCamelCase_		)] for i in range(lowerCamelCase_     ,				lowerCamelCase_		)
							]

							A      :					Union[str, Any]      		=					[[a[i][j] for j in range(lowerCamelCase_		)] for i in range(lowerCamelCase_		)]
							A      :					Tuple      		=					[[a[i][j] for j in range(lowerCamelCase_		)] for i in range(lowerCamelCase_     ,				lowerCamelCase_		)]

							return top_left, top_right, bot_left, bot_right






def        snake_case__		(    lowerCamelCase_		):
							return len(lowerCamelCase_		), len(matrix[0]		)






def        snake_case__		(    lowerCamelCase_		):
							print('''\n'''.join(str(lowerCamelCase_		) for line in matrix		)		)






def        snake_case__		(    lowerCamelCase_     ,				lowerCamelCase_		):
							if matrix_dimensions(lowerCamelCase_		) == (2, 2):
														return default_matrix_multiplication(lowerCamelCase_     ,				lowerCamelCase_		)

							A		,		A		,		A		,		A      :					str      		=					split_matrix(lowerCamelCase_		)
							A		,		A		,		A		,		A      :					List[str]      		=					split_matrix(lowerCamelCase_		)

							A      :					Tuple      		=					actual_strassen(lowerCamelCase_     ,				matrix_subtraction(lowerCamelCase_     ,				lowerCamelCase_		)		)
							A      :					str      		=					actual_strassen(matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)     ,				lowerCamelCase_		)
							A      :					List[Any]      		=					actual_strassen(matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)     ,				lowerCamelCase_		)
							A      :					List[Any]      		=					actual_strassen(lowerCamelCase_     ,				matrix_subtraction(lowerCamelCase_     ,				lowerCamelCase_		)		)
							A      :					str      		=					actual_strassen(matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)     ,				matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)		)
							A      :					Union[str, Any]      		=					actual_strassen(matrix_subtraction(lowerCamelCase_     ,				lowerCamelCase_		)     ,				matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)		)
							A      :					List[str]      		=					actual_strassen(matrix_subtraction(lowerCamelCase_     ,				lowerCamelCase_		)     ,				matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)		)

							A      :					Optional[Any]      		=					matrix_addition(matrix_subtraction(matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)     ,				lowerCamelCase_		)     ,				lowerCamelCase_		)
							A      :					int      		=					matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)
							A      :					Union[str, Any]      		=					matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)
							A      :					Optional[Any]      		=					matrix_subtraction(matrix_subtraction(matrix_addition(lowerCamelCase_     ,				lowerCamelCase_		)     ,				lowerCamelCase_		)     ,				lowerCamelCase_		)

							# construct the new matrix from our 4 quadrants
							A      :					Union[str, Any]      		=					[]
							for i in range(len(lowerCamelCase_		)		):
														new_matrix.append(top_left[i] + top_right[i]		)
							for i in range(len(lowerCamelCase_		)		):
														new_matrix.append(bot_left[i] + bot_right[i]		)
							return new_matrix






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

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

							A      :					List[str]      		=					max(*lowerCamelCase_     ,				*lowerCamelCase_		)
							A      :					Tuple      		=					int(math.pow(2     ,				math.ceil(math.loga(lowerCamelCase_		)		)		)		)
							A      :					int      		=					matrixa
							A      :					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     ,				lowerCamelCase_		):
														if i < dimensiona[0]:
																					for _ in range(dimensiona[1]     ,				lowerCamelCase_		):
																												new_matrixa[i].append(0		)
														else:
																					new_matrixa.append([0] * maxim		)
														if i < dimensiona[0]:
																					for _ in range(dimensiona[1]     ,				lowerCamelCase_		):
																												new_matrixa[i].append(0		)
														else:
																					new_matrixa.append([0] * maxim		)

							A      :					Dict      		=					actual_strassen(lowerCamelCase_     ,				lowerCamelCase_		)

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


if __name__ == "__main__":
		lowercase			:				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],
		]
		lowercase			:				str   =     [[0, 2, 1, 1], [16, 2, 3, 3], [2, 2, 7, 7], [13, 11, 22, 4]]
		print(strassen(matrixa, matrixa))









def        snake_case__		(    lowerCamelCase_ = 1000		):
							return sum(e for e in range(3     ,				lowerCamelCase_		) if e % 3 == 0 or e % 5 == 0		)


if __name__ == "__main__":
		print(F"{solution() = }")






