
'''simple docstring'''







from collections.abc import Iterable
from typing import Generic, TypeVar

lowercase					:							Optional[Any]   =      TypeVar("_T")


class 		__UpperCAmelCase   (      Generic[_T]		):


							def __init__( self					,     lowerCAmelCase_ = None						):





								"""simple docstring"""






								_snake_case     		=	list(iterable or []						)
								_snake_case     		=	[]


							def __len__( self						):





								"""simple docstring"""






								return len(self._stacka						) + len(self._stacka						)


							def __repr__( self						):





								"""simple docstring"""






								return F'Queue({tuple(self._stacka[::-1] + self._stacka						)})'


							def 				lowerCamelCase       ( self					,     lowerCAmelCase_						):





								"""simple docstring"""






								self._stacka.append(lowerCAmelCase_						)




							def 				lowerCamelCase       ( self						):





								"""simple docstring"""






								_snake_case     		=	self._stacka.pop
								_snake_case     		=	self._stacka.append

								if not self._stacka:
									while self._stacka:
										stacka_append(stacka_pop()						)

								if not self._stacka:
									raise IndexError('Queue is empty'						)
								return self._stacka.pop()


if __name__ == "__main__":
					from doctest import testmod

					testmod()



'''simple docstring'''







from __future__ import annotations

import math







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







def        SCREAMING_SNAKE_CASE__			(     __A    ,       __A			) ->			Dict:
	return [
	    [matrix_a[row][col] - matrix_b[row][col] for col in range(len(matrix_a[row]			)			)]
	    for row in range(len(__A			)			)
	]







def        SCREAMING_SNAKE_CASE__			(     __A			) ->			tuple[list, list, list, list]:
	if len(__A			) % 2 != 0 or len(a[0]			) % 2 != 0:
		raise Exception('Odd matrices are not supported!'			)

	_snake_case     		=	len(__A			)
	_snake_case     		=	matrix_length // 2

	_snake_case     		=	[[a[i][j] for j in range(__A    ,       __A			)] for i in range(__A			)]
	_snake_case     		=	[
	    [a[i][j] for j in range(__A    ,       __A			)] for i in range(__A    ,       __A			)
	]

	_snake_case     		=	[[a[i][j] for j in range(__A			)] for i in range(__A			)]
	_snake_case     		=	[[a[i][j] for j in range(__A			)] for i in range(__A    ,       __A			)]

	return top_left, top_right, bot_left, bot_right







def        SCREAMING_SNAKE_CASE__			(     __A			) ->			tuple[int, int]:
	return len(__A			), len(matrix[0]			)







def        SCREAMING_SNAKE_CASE__			(     __A			) ->			None:
	print('\n'.join(str(__A			) for line in matrix			)			)







def        SCREAMING_SNAKE_CASE__			(     __A    ,       __A			) ->			list:
	if matrix_dimensions(__A			) == (2, 2):
		return default_matrix_multiplication(__A    ,       __A			)

	_snake_case		,				_snake_case		,				_snake_case		,				_snake_case     		=	split_matrix(__A			)
	_snake_case		,				_snake_case		,				_snake_case		,				_snake_case     		=	split_matrix(__A			)

	_snake_case     		=	actual_strassen(__A    ,       matrix_subtraction(__A    ,       __A			)			)
	_snake_case     		=	actual_strassen(matrix_addition(__A    ,       __A			)    ,       __A			)
	_snake_case     		=	actual_strassen(matrix_addition(__A    ,       __A			)    ,       __A			)
	_snake_case     		=	actual_strassen(__A    ,       matrix_subtraction(__A    ,       __A			)			)
	_snake_case     		=	actual_strassen(matrix_addition(__A    ,       __A			)    ,       matrix_addition(__A    ,       __A			)			)
	_snake_case     		=	actual_strassen(matrix_subtraction(__A    ,       __A			)    ,       matrix_addition(__A    ,       __A			)			)
	_snake_case     		=	actual_strassen(matrix_subtraction(__A    ,       __A			)    ,       matrix_addition(__A    ,       __A			)			)

	_snake_case     		=	matrix_addition(matrix_subtraction(matrix_addition(__A    ,       __A			)    ,       __A			)    ,       __A			)
	_snake_case     		=	matrix_addition(__A    ,       __A			)
	_snake_case     		=	matrix_addition(__A    ,       __A			)
	_snake_case     		=	matrix_subtraction(matrix_subtraction(matrix_addition(__A    ,       __A			)    ,       __A			)    ,       __A			)

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







def        SCREAMING_SNAKE_CASE__			(     __A    ,       __A			) ->			list:
	if matrix_dimensions(__A			)[1] != matrix_dimensions(__A			)[0]:
		_snake_case     		=	(
		    'Unable to multiply these matrices, please check the dimensions.\n'
		    F'Matrix A: {matrixa}\n'
		    F'Matrix B: {matrixa}'
		)
		raise Exception(__A			)
	_snake_case     		=	matrix_dimensions(__A			)
	_snake_case     		=	matrix_dimensions(__A			)

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

	_snake_case     		=	max(*__A    ,       *__A			)
	_snake_case     		=	int(math.pow(2    ,       math.ceil(math.loga(__A			)			)			)			)
	_snake_case     		=	matrixa
	_snake_case     		=	matrixa

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

	_snake_case     		=	actual_strassen(__A    ,       __A			)

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


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

