





'''simple docstring'''

from __future__ import annotations

import math







def 							UpperCAmelCase_    (	lowerCAmelCase_		,							lowerCAmelCase_							):

				"""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"							)
				lowercase         = [
				    [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_    (	lowerCAmelCase_		,							lowerCAmelCase_							):

				"""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 							UpperCAmelCase_    (	lowerCAmelCase_		,							lowerCAmelCase_							):

				"""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 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






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

				lowercase         = len(lowerCAmelCase_							)
				lowercase         = matrix_length // 2

				lowercase         = [[a[i][j] for j in range(lowerCAmelCase_		,							lowerCAmelCase_							)] for i in range(lowerCAmelCase_							)]
				lowercase         = [
				    [a[i][j] for j in range(lowerCAmelCase_		,							lowerCAmelCase_							)] for i in range(lowerCAmelCase_		,							lowerCAmelCase_							)
				]

				lowercase         = [[a[i][j] for j in range(lowerCAmelCase_							)] for i in range(lowerCAmelCase_							)]
				lowercase         = [[a[i][j] for j in range(lowerCAmelCase_							)] for i in range(lowerCAmelCase_		,							lowerCAmelCase_							)]

				return top_left, top_right, bot_left, bot_right







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






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







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






				print("\n".join(str(lowerCAmelCase_							) for line in matrix							)							)







def 							UpperCAmelCase_    (	lowerCAmelCase_		,							lowerCAmelCase_							):

				"""simple docstring"""






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

				lowercase   ,							lowercase   ,							lowercase   ,							lowercase         = split_matrix(lowerCAmelCase_							)
				lowercase   ,							lowercase   ,							lowercase   ,							lowercase         = split_matrix(lowerCAmelCase_							)

				lowercase         = actual_strassen(lowerCAmelCase_		,							matrix_subtraction(lowerCAmelCase_		,							lowerCAmelCase_							)							)
				lowercase         = actual_strassen(matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)		,							lowerCAmelCase_							)
				lowercase         = actual_strassen(matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)		,							lowerCAmelCase_							)
				lowercase         = actual_strassen(lowerCAmelCase_		,							matrix_subtraction(lowerCAmelCase_		,							lowerCAmelCase_							)							)
				lowercase         = actual_strassen(matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)		,							matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)							)
				lowercase         = actual_strassen(matrix_subtraction(lowerCAmelCase_		,							lowerCAmelCase_							)		,							matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)							)
				lowercase         = actual_strassen(matrix_subtraction(lowerCAmelCase_		,							lowerCAmelCase_							)		,							matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)							)

				lowercase         = matrix_addition(matrix_subtraction(matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)		,							lowerCAmelCase_							)		,							lowerCAmelCase_							)
				lowercase         = matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)
				lowercase         = matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)
				lowercase         = matrix_subtraction(matrix_subtraction(matrix_addition(lowerCAmelCase_		,							lowerCAmelCase_							)		,							lowerCAmelCase_							)		,							lowerCAmelCase_							)

				# construct the new matrix from our 4 quadrants
				lowercase         = []
				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 							UpperCAmelCase_    (	lowerCAmelCase_		,							lowerCAmelCase_							):

				"""simple docstring"""






				if matrix_dimensions(lowerCAmelCase_							)[1] != matrix_dimensions(lowerCAmelCase_							)[0]:
								lowercase         = (
								    "Unable to multiply these matrices, please check the dimensions.\n"
								    f'Matrix A: {matrixa}\n'
								    f'Matrix B: {matrixa}'
								)
								raise Exception(lowerCAmelCase_							)
				lowercase         = matrix_dimensions(lowerCAmelCase_							)
				lowercase         = matrix_dimensions(lowerCAmelCase_							)

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

				lowercase         = max(*lowerCAmelCase_		,							*lowerCAmelCase_							)
				lowercase         = int(math.pow(2		,							math.ceil(math.loga(lowerCAmelCase_							)							)							)							)
				lowercase         = matrixa
				lowercase         = 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							)

				lowercase         = 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__":
			__lowerCamelCase : Tuple											=			[
			    [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 : Optional[int]											=			[[0, 2, 1, 1], [16, 2, 3, 3], [2, 2, 7, 7], [13, 11, 22, 4]]
			print(strassen(matrixa, matrixa))











'''simple docstring'''

from __future__ import annotations

from collections import deque
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Any

@dataclass
class       UpperCAmelCase :
		UpperCAmelCase					:	int
		UpperCAmelCase					:	Node | None 			=		None
		UpperCAmelCase					:	Node | None 			=		None







def 							UpperCAmelCase_    (	):

				"""simple docstring"""






				lowercase         = Node(1							)
				lowercase         = Node(2							)
				lowercase         = Node(3							)
				lowercase         = Node(4							)
				lowercase         = Node(5							)
				return tree







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






				return [root.data, *preorder(root.left							), *preorder(root.right							)] if root else []







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






				return postorder(root.left							) + postorder(root.right							) + [root.data] if root else []







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






				return [*inorder(root.left							), root.data, *inorder(root.right							)] if root else []







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






				return (max(height(root.left							)		,							height(root.right							)							) + 1) if root else 0







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






				lowercase         = []

				if root is None:
								return output

				lowercase         = deque([root]							)

				while process_queue:
								lowercase         = process_queue.popleft()
								output.append(node.data							)

								if node.left:
												process_queue.append(node.left							)
								if node.right:
												process_queue.append(node.right							)
				return output







def 							UpperCAmelCase_    (	lowerCAmelCase_		,							lowerCAmelCase_							):

				"""simple docstring"""






				lowercase         = []

				def populate_output(lowerCAmelCase_		,							lowerCAmelCase_							) -> None:
								if not root:
												return
								if level == 1:
												output.append(root.data							)
								elif level > 1:
												populate_output(root.left		,							level - 1							)
												populate_output(root.right		,							level - 1							)

				populate_output(lowerCAmelCase_		,							lowerCAmelCase_							)
				return output







def 							UpperCAmelCase_    (	lowerCAmelCase_		,							lowerCAmelCase_							):

				"""simple docstring"""






				lowercase         = []

				def populate_output(lowerCAmelCase_		,							lowerCAmelCase_							) -> None:
								if root is None:
												return
								if level == 1:
												output.append(root.data							)
								elif level > 1:
												populate_output(root.right		,							level - 1							)
												populate_output(root.left		,							level - 1							)

				populate_output(lowerCAmelCase_		,							lowerCAmelCase_							)
				return output







def 							UpperCAmelCase_    (	lowerCAmelCase_							):

				"""simple docstring"""






				if root is None:
								return []

				lowercase         = []

				lowercase         = 0
				lowercase         = height(lowerCAmelCase_							)

				for h in range(1		,							height_tree + 1							):
								if not flag:
												output.append(get_nodes_from_left_to_right(lowerCAmelCase_		,							lowerCAmelCase_							)							)
												lowercase         = 1
								else:
												output.append(get_nodes_from_right_to_left(lowerCAmelCase_		,							lowerCAmelCase_							)							)
												lowercase         = 0

				return output







def 							UpperCAmelCase_    (	):  # Main function for testing.

				"""simple docstring"""






				lowercase         = make_tree()
				print(f'In-order Traversal: {inorder(lowerCAmelCase_							)}'							)
				print(f'Pre-order Traversal: {preorder(lowerCAmelCase_							)}'							)
				print(f'Post-order Traversal: {postorder(lowerCAmelCase_							)}'		,							"\n"							)

				print(f'Height of Tree: {height(lowerCAmelCase_							)}'		,							"\n"							)

				print("Complete Level Order Traversal: "							)
				print(level_order(lowerCAmelCase_							)		,							"\n"							)

				print("Level-wise order Traversal: "							)

				for level in range(1		,							height(lowerCAmelCase_							) + 1							):
								print(f'Level {level}:'		,							get_nodes_from_left_to_right(lowerCAmelCase_		,							level=lowerCAmelCase_							)							)

				print("\nZigZag order Traversal: "							)
				print(zigzag(lowerCAmelCase_							)							)


if __name__ == "__main__":
			import doctest

			doctest.testmod()
			main()




