






from __future__ import annotations

import math



def 					_lowerCamelCase(			lowerCAmelCase__				:		list    ,    lowerCAmelCase__				:		list      ):





				'''simple docstring'''







				if len(lowerCAmelCase__      ) != 2 or len(a[0]      ) != 2 or len(lowerCAmelCase__      ) != 2 or len(b[0]      ) != 2:
								raise Exception('Matrices are not 2x2'      )
				SCREAMING_SNAKE_CASE_   :	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 					_lowerCamelCase(			lowerCAmelCase__				:		list    ,    lowerCAmelCase__				:		list      ):





				'''simple docstring'''







				return [
				    [matrix_a[row][col] + matrix_b[row][col] for col in range(len(matrix_a[row]      )      )]
				    for row in range(len(lowerCAmelCase__      )      )
				]



def 					_lowerCamelCase(			lowerCAmelCase__				:		list    ,    lowerCAmelCase__				:		list      ):





				'''simple docstring'''







				return [
				    [matrix_a[row][col] - matrix_b[row][col] for col in range(len(matrix_a[row]      )      )]
				    for row in range(len(lowerCAmelCase__      )      )
				]



def 					_lowerCamelCase(			lowerCAmelCase__				:		list      ):





				'''simple docstring'''







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

				SCREAMING_SNAKE_CASE_   :	Tuple													=   len(lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	Optional[Any]													=   matrix_length // 2

				SCREAMING_SNAKE_CASE_   :	int													=   [[a[i][j] for j in range(lowerCAmelCase__    ,    lowerCAmelCase__      )] for i in range(lowerCAmelCase__      )]
				SCREAMING_SNAKE_CASE_   :	str													=   [
				    [a[i][j] for j in range(lowerCAmelCase__    ,    lowerCAmelCase__      )] for i in range(lowerCAmelCase__    ,    lowerCAmelCase__      )
				]

				SCREAMING_SNAKE_CASE_   :	str													=   [[a[i][j] for j in range(lowerCAmelCase__      )] for i in range(lowerCAmelCase__      )]
				SCREAMING_SNAKE_CASE_   :	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 					_lowerCamelCase(			lowerCAmelCase__				:		list      ):





				'''simple docstring'''







				return len(lowerCAmelCase__      ), len(matrix[0]      )



def 					_lowerCamelCase(			lowerCAmelCase__				:		list      ):





				'''simple docstring'''







				print('\n'.join(str(lowerCAmelCase__      ) for line in matrix      )      )



def 					_lowerCamelCase(			lowerCAmelCase__				:		list    ,    lowerCAmelCase__				:		list      ):





				'''simple docstring'''







				if matrix_dimensions(lowerCAmelCase__      ) == (2, 2):
								return default_matrix_multiplication(lowerCAmelCase__    ,    lowerCAmelCase__      )

				SCREAMING_SNAKE_CASE_   :	Tuple													=   split_matrix(lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	Any													=   split_matrix(lowerCAmelCase__      )

				SCREAMING_SNAKE_CASE_   :	List[Any]													=   actual_strassen(lowerCAmelCase__    ,    matrix_subtraction(lowerCAmelCase__    ,    lowerCAmelCase__      )      )
				SCREAMING_SNAKE_CASE_   :	Any													=   actual_strassen(matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )    ,    lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	Union[str, Any]													=   actual_strassen(matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )    ,    lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	Tuple													=   actual_strassen(lowerCAmelCase__    ,    matrix_subtraction(lowerCAmelCase__    ,    lowerCAmelCase__      )      )
				SCREAMING_SNAKE_CASE_   :	List[Any]													=   actual_strassen(matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )    ,    matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )      )
				SCREAMING_SNAKE_CASE_   :	Dict													=   actual_strassen(matrix_subtraction(lowerCAmelCase__    ,    lowerCAmelCase__      )    ,    matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )      )
				SCREAMING_SNAKE_CASE_   :	int													=   actual_strassen(matrix_subtraction(lowerCAmelCase__    ,    lowerCAmelCase__      )    ,    matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )      )

				SCREAMING_SNAKE_CASE_   :	int													=   matrix_addition(matrix_subtraction(matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )    ,    lowerCAmelCase__      )    ,    lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	int													=   matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	str													=   matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	Optional[int]													=   matrix_subtraction(matrix_subtraction(matrix_addition(lowerCAmelCase__    ,    lowerCAmelCase__      )    ,    lowerCAmelCase__      )    ,    lowerCAmelCase__      )

				# construct the new matrix from our 4 quadrants
				SCREAMING_SNAKE_CASE_   :	int													=   []
				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 					_lowerCamelCase(			lowerCAmelCase__				:		list    ,    lowerCAmelCase__				:		list      ):





				'''simple docstring'''







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

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

				SCREAMING_SNAKE_CASE_   :	List[str]													=   max(*lowerCAmelCase__    ,    *lowerCAmelCase__      )
				SCREAMING_SNAKE_CASE_   :	str													=   int(math.pow(2    ,    math.ceil(math.loga(lowerCAmelCase__      )      )      )      )
				SCREAMING_SNAKE_CASE_   :	List[str]													=   matrixa
				SCREAMING_SNAKE_CASE_   :	Dict													=   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      )

				SCREAMING_SNAKE_CASE_   :	List[Any]													=   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__":
				A        =			[
				    [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],
				]
				A        =			[[0, 2, 1, 1], [16, 2, 3, 3], [2, 2, 7, 7], [13, 11, 22, 4]]
				print(strassen(matrixa, matrixa))










import copy
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, Optional, Union


@dataclass
class 							__a							:





		'''simple docstring'''



		UpperCAmelCase__      :				Optional[Union[str, Path]]				    =						None
		UpperCAmelCase__      :				bool				    =						False
		UpperCAmelCase__      :				bool				    =						False
		UpperCAmelCase__      :				bool				    =						False
		UpperCAmelCase__      :				Optional[Dict]				    =						None
		UpperCAmelCase__      :				Optional[str]				    =						None
		UpperCAmelCase__      :				bool				    =						False
		UpperCAmelCase__      :				bool				    =						False
		UpperCAmelCase__      :				bool				    =						False
		UpperCAmelCase__      :				bool				    =						True
		UpperCAmelCase__      :				Optional[int]				    =						None
		UpperCAmelCase__      :				int				    =						1
		UpperCAmelCase__      :				Optional[Union[str, bool]]				    =						None
		UpperCAmelCase__      :				bool				    =						False
		UpperCAmelCase__      :				Optional[Dict]				    =						None
		UpperCAmelCase__      :				Optional[str]				    =						None


		def   __snake_case			(						self       ):
						return self.__class__(**{k: copy.deepcopy(UpperCamelCase__       ) for k, v in self.__dict__.items()}       )