"""simple docstring"""






from __future__ import annotations

import math


def 			UpperCAmelCase__       (				lowerCAmelCase__     :list					,		lowerCAmelCase__     :list		) ->    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"""		)
      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__     :list					,		lowerCAmelCase__     :list		) ->    Dict:
      '''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__     :list					,		lowerCAmelCase__     :list		) ->    Optional[int]:
      '''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__     :list		) ->    tuple[list, list, list, list]:
      '''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__     :list		) ->    tuple[int, int]:
      '''simple docstring'''


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


def 			UpperCAmelCase__       (				lowerCAmelCase__     :list		) ->    None:
      '''simple docstring'''


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


def 			UpperCAmelCase__       (				lowerCAmelCase__     :list					,		lowerCAmelCase__     :list		) ->    list:
      '''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__     :list					,		lowerCAmelCase__     :list		) ->    list:
      '''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    :       List[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],
       ]
       __lowerCAmelCase    :       Optional[int]					     =[[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"""






from __future__ import annotations

from scipy.special import comb  # type: ignore





class  _A						:

      def __init__(						self		,       __lowerCAmelCase						):







            """simple docstring"""



            lowercase														=	list_of_points
            # Degree determines the flexibility of the curve.
            # Degree = 1 will produce a straight line.
            lowercase														=	len(__lowerCAmelCase						) - 1

      def 				A__       (						self		,       __lowerCAmelCase						):







            """simple docstring"""



            assert 0 <= t <= 1, "Time t must be between 0 and 1."
            lowercase														=	[]
            for i in range(len(self.list_of_points						)						):
                  # basis function for each i
                  output_values.append(
                      comb(self.degree		,       __lowerCAmelCase						) * ((1 - t) ** (self.degree - i)) * (t**i)						)
            # the basis must sum up to 1 for it to produce a valid Bezier curve.
            assert round(sum(__lowerCAmelCase						)		,       5						) == 1
            return output_values

      def 				A__       (						self		,       __lowerCAmelCase						):







            """simple docstring"""



            assert 0 <= t <= 1, "Time t must be between 0 and 1."

            lowercase														=	self.basis_function(__lowerCAmelCase						)
            lowercase														=	0.0
            lowercase														=	0.0
            for i in range(len(self.list_of_points						)						):
                  # For all points, sum up the product of i-th basis function and i-th point.
                  x += basis_function[i] * self.list_of_points[i][0]
                  y += basis_function[i] * self.list_of_points[i][1]
            return (x, y)







      def 				A__       (						self		,       __lowerCAmelCase = 0.0_1						):







            """simple docstring"""



            from matplotlib import pyplot as plt  # type: ignore

            lowercase														=	[]  # x coordinates of points to plot
            lowercase														=	[]  # y coordinates of points to plot

            lowercase														=	0.0
            while t <= 1:
                  lowercase														=	self.bezier_curve_function(__lowerCAmelCase						)
                  to_plot_x.append(value[0]						)
                  to_plot_y.append(value[1]						)
                  t += step_size

            lowercase														=	[i[0] for i in self.list_of_points]
            lowercase														=	[i[1] for i in self.list_of_points]

            plt.plot(
                __lowerCAmelCase		,       __lowerCAmelCase		,       color="""blue"""		,       label="""Curve of Degree """ + str(self.degree						)		,       )
            plt.scatter(__lowerCAmelCase		,       __lowerCAmelCase		,       color="""red"""		,       label="""Control Points"""						)
            plt.legend()
            plt.show()


if __name__ == "__main__":
       import doctest

       doctest.testmod()

       BezierCurve([(1, 2), (3, 5)]).plot_curve()  # degree 1
       BezierCurve([(0, 0), (5, 5), (5, 0)]).plot_curve()  # degree 2
       BezierCurve([(0, 0), (5, 5), (5, 0), (2.5, -2.5)]).plot_curve()  # degree 3



