



"""simple docstring"""


from manim import *







class       A_			(     SCREAMING_SNAKE_CASE_				):



						"""simple docstring"""






						def 	UpperCAmelCase__     (					self :List[Any]					)				->			Tuple:
												UpperCAmelCase             = Rectangle(height=0.5   ,  width=0.5					)
												UpperCAmelCase             = Rectangle(height=0.46   ,  width=0.46					).set_stroke(width=0					)

												UpperCAmelCase             = Rectangle(height=0.25   ,  width=0.25					)

												UpperCAmelCase             = [mem.copy() for i in range(6					)]
												UpperCAmelCase             = [mem.copy() for i in range(6					)]
												UpperCAmelCase             = VGroup(*lowercase_					).arrange(lowercase_   ,  buff=0					)
												UpperCAmelCase             = VGroup(*lowercase_					).arrange(lowercase_   ,  buff=0					)
												UpperCAmelCase             = VGroup(lowercase_   ,  lowercase_					).arrange(lowercase_   ,  buff=0					)
												UpperCAmelCase             = Text('CPU'   ,  font_size=24					)
												UpperCAmelCase             = Group(lowercase_   ,  lowercase_					).arrange(lowercase_   ,  buff=0.5   ,  aligned_edge=lowercase_					)
												cpu.move_to([-2.5, -0.5, 0]					)
												self.add(lowercase_					)

												UpperCAmelCase             = [mem.copy() for i in range(4					)]
												UpperCAmelCase             = VGroup(*lowercase_					).arrange(lowercase_   ,  buff=0					)
												UpperCAmelCase             = Text('GPU'   ,  font_size=24					)
												UpperCAmelCase             = Group(lowercase_   ,  lowercase_					).arrange(lowercase_   ,  buff=0.5   ,  aligned_edge=lowercase_					)
												gpu.move_to([-1, -1, 0]					)
												self.add(lowercase_					)

												UpperCAmelCase             = [mem.copy() for i in range(6					)]
												UpperCAmelCase             = VGroup(*lowercase_					).arrange(lowercase_   ,  buff=0					)

												UpperCAmelCase             = Text('Model'   ,  font_size=24					)
												UpperCAmelCase             = Group(lowercase_   ,  lowercase_					).arrange(lowercase_   ,  buff=0.5   ,  aligned_edge=lowercase_					)
												model.move_to([3, -1.0, 0]					)
												self.add(lowercase_					)

												UpperCAmelCase             = []
												UpperCAmelCase             = []

												for i, rect in enumerate(lowercase_					):
																		UpperCAmelCase             = fill.copy().set_fill(lowercase_   ,  opacity=0.8					)
																		target.move_to(lowercase_					)
																		model_arr.append(lowercase_					)

																		UpperCAmelCase             = Rectangle(height=0.46   ,  width=0.46					).set_stroke(width=0.0					).set_fill(lowercase_   ,  opacity=0.8					)
																		cpu_target.move_to(cpu_left_col_base[i]					)
																		model_cpu_arr.append(lowercase_					)

												self.add(*lowercase_   ,  *lowercase_					)

												UpperCAmelCase             = [meta_mem.copy() for i in range(6					)]
												UpperCAmelCase             = [meta_mem.copy() for i in range(6					)]
												UpperCAmelCase             = VGroup(*lowercase_					).arrange(lowercase_   ,  buff=0					)
												UpperCAmelCase             = VGroup(*lowercase_					).arrange(lowercase_   ,  buff=0					)
												UpperCAmelCase             = VGroup(lowercase_   ,  lowercase_					).arrange(lowercase_   ,  buff=0					)
												UpperCAmelCase             = Text('Disk'   ,  font_size=24					)
												UpperCAmelCase             = Group(lowercase_   ,  lowercase_					).arrange(lowercase_   ,  buff=0.5   ,  aligned_edge=lowercase_					)
												disk.move_to([-4, -1.25, 0]					)
												self.add(lowercase_   ,  lowercase_					)

												UpperCAmelCase             = Square(side_length=2.2					)
												key.move_to([-5, 2, 0]					)

												UpperCAmelCase             = MarkupText(
												    f"""<b>Key:</b>\n\n<span fgcolor='{YELLOW}'>●</span> Empty Model"""   ,  font_size=18   ,  )

												key_text.move_to([-5, 2.4, 0]					)

												self.add(lowercase_   ,  lowercase_					)

												UpperCAmelCase             = MarkupText(
												    f"""<span fgcolor='{BLUE}'>●</span> Checkpoint"""   ,  font_size=18   ,  )

												blue_text.next_to(lowercase_   ,  DOWN * 2.4   ,  aligned_edge=key_text.get_left()					)
												self.add(lowercase_					)

												UpperCAmelCase             = MarkupText(
												    f"""Now watch as an input is passed through the model\nand how the memory is utilized and handled."""   ,  font_size=24   ,  )
												step_a.move_to([2, 2, 0]					)

												self.play(Write(lowercase_					)					)

												UpperCAmelCase             = Square(0.3					)
												input.set_fill(lowercase_   ,  opacity=1.0					)
												input.set_stroke(width=0.0					)
												input.next_to(model_base[0]   ,  lowercase_   ,  buff=0.5					)

												self.play(Write(lowercase_					)					)

												input.generate_target()
												input.target.next_to(model_arr[0]   ,  direction=lowercase_   ,  buff=0.02					)
												self.play(MoveToTarget(lowercase_					)					)

												self.play(FadeOut(lowercase_					)					)

												UpperCAmelCase             = Arrow(start=lowercase_   ,  end=lowercase_   ,  color=lowercase_   ,  buff=0.5					)
												a.next_to(model_arr[0].get_left()   ,  lowercase_   ,  buff=0.2					)

												model_cpu_arr[0].generate_target()
												model_cpu_arr[0].target.move_to(gpu_rect[0]					)

												UpperCAmelCase             = MarkupText(
												    f"""As the input reaches a layer, the hook triggers\nand weights are moved from the CPU\nto the GPU and back."""   ,  font_size=24   ,  )
												step_a.move_to([2, 2, 0]					)

												self.play(Write(lowercase_   ,  run_time=3					)					)

												UpperCAmelCase             = {'run_time': 1, 'fade_in': True, 'fade_out': True, 'buff': 0.02}

												self.play(
												    Write(lowercase_					)   ,  Circumscribe(model_arr[0]   ,  color=lowercase_   ,  **lowercase_					)   ,  Circumscribe(model_cpu_arr[0]   ,  color=lowercase_   ,  **lowercase_					)   ,  Circumscribe(gpu_rect[0]   ,  color=lowercase_   ,  **lowercase_					)   ,  )
												self.play(MoveToTarget(model_cpu_arr[0]					)					)

												UpperCAmelCase             = a.copy()
												for i in range(6					):
																		a_c.next_to(model_arr[i].get_right() + 0.02   ,  lowercase_   ,  buff=0.2					)

																		input.generate_target()
																		input.target.move_to(model_arr[i].get_right() + 0.02					)

																		UpperCAmelCase             = AnimationGroup(
																		    FadeOut(lowercase_   ,  run_time=0.5					)   ,  MoveToTarget(lowercase_   ,  run_time=0.5					)   ,  FadeIn(lowercase_   ,  run_time=0.5					)   ,  lag_ratio=0.2					)

																		self.play(lowercase_					)

																		model_cpu_arr[i].generate_target()
																		model_cpu_arr[i].target.move_to(cpu_left_col_base[i]					)

																		if i < 5:
																								model_cpu_arr[i + 1].generate_target()
																								model_cpu_arr[i + 1].target.move_to(gpu_rect[0]					)
																								if i >= 1:
																														UpperCAmelCase             = 0.7

																								self.play(
																								    Circumscribe(model_arr[i]   ,  **lowercase_					)   ,  Circumscribe(cpu_left_col_base[i]   ,  **lowercase_					)   ,  Circumscribe(cpu_left_col_base[i + 1]   ,  color=lowercase_   ,  **lowercase_					)   ,  Circumscribe(gpu_rect[0]   ,  color=lowercase_   ,  **lowercase_					)   ,  Circumscribe(model_arr[i + 1]   ,  color=lowercase_   ,  **lowercase_					)   ,  )
																								if i < 1:
																														self.play(
																														    MoveToTarget(model_cpu_arr[i]					)   ,  MoveToTarget(model_cpu_arr[i + 1]					)   ,  )
																								else:
																														self.play(
																														    MoveToTarget(model_cpu_arr[i]   ,  run_time=0.7					)   ,  MoveToTarget(model_cpu_arr[i + 1]   ,  run_time=0.7					)   ,  )
																		else:
																								model_cpu_arr[i].generate_target()
																								model_cpu_arr[i].target.move_to(cpu_left_col_base[-1]					)
																								input.generate_target()
																								input.target.next_to(model_arr[-1].get_right()   ,  RIGHT + 0.02   ,  buff=0.2					)

																								self.play(
																								    Circumscribe(model_arr[-1]   ,  color=lowercase_   ,  **lowercase_					)   ,  Circumscribe(cpu_left_col_base[-1]   ,  color=lowercase_   ,  **lowercase_					)   ,  Circumscribe(gpu_rect[0]   ,  color=lowercase_   ,  **lowercase_					)   ,  )

																								self.play(MoveToTarget(model_cpu_arr[i]					)					)

																		UpperCAmelCase             = a_c
																		UpperCAmelCase             = a_c.copy()

												input.generate_target()
												input.target.next_to(model_base[-1]   ,  RIGHT + 0.02   ,  buff=0.5					)
												self.play(
												    FadeOut(lowercase_					)   ,  FadeOut(lowercase_   ,  run_time=0.5					)   ,  )

												UpperCAmelCase             = MarkupText(f"""Inference on a model too large for GPU memory\nis successfully completed."""   ,  font_size=24					)
												step_a.move_to([2, 2, 0]					)

												self.play(Write(lowercase_   ,  run_time=3					)   ,  MoveToTarget(lowercase_					)					)

												self.wait()









"""simple docstring"""




from __future__ import annotations

import math
import random
from collections.abc import Collection
from typing import overload
class 					lowerCAmelCase	:




		'''simple docstring'''







		def __init__(	self						,       lowerCAmelCase__ = None				)     ->							None:
								if components is None:
														SCREAMING_SNAKE_CASE													=					[]
								SCREAMING_SNAKE_CASE													=					list(lowerCAmelCase__				)







		def __len__(	self				)     ->							int:
								return len(self.__components				)







		def __str__(	self				)     ->							str:
								return "(" + ",".join(map(lowerCAmelCase__						,       self.__components				)				) + ")"







		def __add__(	self						,       lowerCAmelCase__				)     ->							Vector:
								SCREAMING_SNAKE_CASE													=					len(self				)
								if size == len(lowerCAmelCase__				):
														SCREAMING_SNAKE_CASE													=					[self.__components[i] + other.component(lowerCAmelCase__				) for i in range(lowerCAmelCase__				)]
														return Vector(lowerCAmelCase__				)
								else:
														raise Exception('must have the same size'				)







		def __sub__(	self						,       lowerCAmelCase__				)     ->							Vector:
								SCREAMING_SNAKE_CASE													=					len(self				)
								if size == len(lowerCAmelCase__				):
														SCREAMING_SNAKE_CASE													=					[self.__components[i] - other.component(lowerCAmelCase__				) for i in range(lowerCAmelCase__				)]
														return Vector(lowerCAmelCase__				)
								else:  # error case
														raise Exception('must have the same size'				)







		@overload
		def __mul__(	self						,       lowerCAmelCase__				)     ->							Vector:
								...







		@overload
		def __mul__(	self						,       lowerCAmelCase__				)     ->							float:
								...







		def __mul__(	self						,       lowerCAmelCase__				)     ->							float | Vector:
								if isinstance(lowerCAmelCase__						,       (float, int)				):
														SCREAMING_SNAKE_CASE													=					[c * other for c in self.__components]
														return Vector(lowerCAmelCase__				)
								elif isinstance(lowerCAmelCase__						,       lowerCAmelCase__				) and len(self				) == len(lowerCAmelCase__				):
														SCREAMING_SNAKE_CASE													=					len(self				)
														SCREAMING_SNAKE_CASE													=					[self.__components[i] * other.component(lowerCAmelCase__				) for i in range(lowerCAmelCase__				)]
														return sum(lowerCAmelCase__				)
								else:  # error case
														raise Exception('invalid operand!'				)







		def 							__A						(	self				)     ->							Vector:
								return Vector(self.__components				)







		def 							__A						(	self						,       lowerCAmelCase__				)     ->							float:
								if isinstance(lowerCAmelCase__						,       lowerCAmelCase__				) and -len(self.__components				) <= i < len(self.__components				):
														return self.__components[i]
								else:
														raise Exception('index out of range'				)







		def 							__A						(	self						,       lowerCAmelCase__						,       lowerCAmelCase__				)     ->							None:
								assert -len(self.__components				) <= pos < len(self.__components				)
								SCREAMING_SNAKE_CASE													=					value







		def 							__A						(	self				)     ->							float:
								if len(self.__components				) == 0:
														raise Exception('Vector is empty'				)
								SCREAMING_SNAKE_CASE													=					[c**2 for c in self.__components]
								return math.sqrt(sum(lowerCAmelCase__				)				)







		def 							__A						(	self						,       lowerCAmelCase__						,       lowerCAmelCase__ = False				)     ->							float:
								SCREAMING_SNAKE_CASE													=					self * other
								SCREAMING_SNAKE_CASE													=					self.euclidean_length() * other.euclidean_length()
								if deg:
														return math.degrees(math.acos(num / den				)				)
								else:
														return math.acos(num / den				)





def     lowercase			(SCREAMING_SNAKE_CASE_		:				int  )   ->						Vector:
						assert isinstance(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  )
						return Vector([0] * dimension  )


def     lowercase			(SCREAMING_SNAKE_CASE_		:				int ,			SCREAMING_SNAKE_CASE_		:				int  )   ->						Vector:
						assert isinstance(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  ) and (isinstance(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  ))
						SCREAMING_SNAKE_CASE													=					[0] * dimension
						SCREAMING_SNAKE_CASE													=					1
						return Vector(SCREAMING_SNAKE_CASE_  )


def     lowercase			(SCREAMING_SNAKE_CASE_		:				float ,			SCREAMING_SNAKE_CASE_		:				Vector ,			SCREAMING_SNAKE_CASE_		:				Vector  )   ->						Vector:
						assert (
						    isinstance(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  )
						    and isinstance(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  )
						    and (isinstance(SCREAMING_SNAKE_CASE_ ,			(int, float)  ))
						)
						return x * scalar + y


def     lowercase			(SCREAMING_SNAKE_CASE_		:				int ,			SCREAMING_SNAKE_CASE_		:				int ,			SCREAMING_SNAKE_CASE_		:				int  )   ->						Vector:
						random.seed(SCREAMING_SNAKE_CASE_  )
						SCREAMING_SNAKE_CASE													=					[random.randint(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  ) for _ in range(SCREAMING_SNAKE_CASE_  )]
						return Vector(SCREAMING_SNAKE_CASE_  )
class 					lowerCAmelCase	:




		'''simple docstring'''







		def __init__(	self						,       lowerCAmelCase__						,       lowerCAmelCase__						,       lowerCAmelCase__				)     ->							None:
								SCREAMING_SNAKE_CASE													=					matrix
								SCREAMING_SNAKE_CASE													=					w
								SCREAMING_SNAKE_CASE													=					h







		def __str__(	self				)     ->							str:
								SCREAMING_SNAKE_CASE													=					''
								for i in range(self.__height				):
														ans += "|"
														for j in range(self.__width				):
																				if j < self.__width - 1:
																										ans += str(self.__matrix[i][j]				) + ","
																				else:
																										ans += str(self.__matrix[i][j]				) + "|\n"
								return ans







		def __add__(	self						,       lowerCAmelCase__				)     ->							Matrix:
								if self.__width == other.width() and self.__height == other.height():
														SCREAMING_SNAKE_CASE													=					[]
														for i in range(self.__height				):
																				SCREAMING_SNAKE_CASE													=					[
																				    self.__matrix[i][j] + other.component(lowerCAmelCase__						,       lowerCAmelCase__				)
																				    for j in range(self.__width				)
																				]
																				matrix.append(lowerCAmelCase__				)
														return Matrix(lowerCAmelCase__						,       self.__width						,       self.__height				)
								else:
														raise Exception('matrix must have the same dimension!'				)







		def __sub__(	self						,       lowerCAmelCase__				)     ->							Matrix:
								if self.__width == other.width() and self.__height == other.height():
														SCREAMING_SNAKE_CASE													=					[]
														for i in range(self.__height				):
																				SCREAMING_SNAKE_CASE													=					[
																				    self.__matrix[i][j] - other.component(lowerCAmelCase__						,       lowerCAmelCase__				)
																				    for j in range(self.__width				)
																				]
																				matrix.append(lowerCAmelCase__				)
														return Matrix(lowerCAmelCase__						,       self.__width						,       self.__height				)
								else:
														raise Exception('matrices must have the same dimension!'				)







		@overload
		def __mul__(	self						,       lowerCAmelCase__				)     ->							Matrix:
								...







		@overload
		def __mul__(	self						,       lowerCAmelCase__				)     ->							Vector:
								...







		def __mul__(	self						,       lowerCAmelCase__				)     ->							Vector | Matrix:
								if isinstance(lowerCAmelCase__						,       lowerCAmelCase__				):  # matrix-vector
														if len(lowerCAmelCase__				) == self.__width:
																				SCREAMING_SNAKE_CASE													=					zero_vector(self.__height				)
																				for i in range(self.__height				):
																										SCREAMING_SNAKE_CASE													=					[
																										    self.__matrix[i][j] * other.component(lowerCAmelCase__				)
																										    for j in range(self.__width				)
																										]
																										ans.change_component(lowerCAmelCase__						,       sum(lowerCAmelCase__				)				)
																				return ans
														else:
																				raise Exception(
																				    'vector must have the same size as the '
																				    'number of columns of the matrix!'				)
								elif isinstance(lowerCAmelCase__						,       (int, float)				):  # matrix-scalar
														SCREAMING_SNAKE_CASE													=					[
														    [self.__matrix[i][j] * other for j in range(self.__width				)]
														    for i in range(self.__height				)
														]
														return Matrix(lowerCAmelCase__						,       self.__width						,       self.__height				)
								return None







		def 							__A						(	self				)     ->							int:
								return self.__height







		def 							__A						(	self				)     ->							int:
								return self.__width







		def 							__A						(	self						,       lowerCAmelCase__						,       lowerCAmelCase__				)     ->							float:
								if 0 <= x < self.__height and 0 <= y < self.__width:
														return self.__matrix[x][y]
								else:
														raise Exception('change_component: indices out of bounds'				)







		def 							__A						(	self						,       lowerCAmelCase__						,       lowerCAmelCase__						,       lowerCAmelCase__				)     ->							None:
								if 0 <= x < self.__height and 0 <= y < self.__width:
														SCREAMING_SNAKE_CASE													=					value
								else:
														raise Exception('change_component: indices out of bounds'				)







		def 							__A						(	self						,       lowerCAmelCase__						,       lowerCAmelCase__				)     ->							float:
								if self.__height != self.__width:
														raise Exception('Matrix is not square'				)
								SCREAMING_SNAKE_CASE													=					self.__matrix[:x] + self.__matrix[x + 1 :]
								for i in range(len(lowerCAmelCase__				)				):
														SCREAMING_SNAKE_CASE													=					minor[i][:y] + minor[i][y + 1 :]
								return Matrix(lowerCAmelCase__						,       self.__width - 1						,       self.__height - 1				).determinant()







		def 							__A						(	self						,       lowerCAmelCase__						,       lowerCAmelCase__				)     ->							float:
								if self.__height != self.__width:
														raise Exception('Matrix is not square'				)
								if 0 <= x < self.__height and 0 <= y < self.__width:
														return (-1) ** (x + y) * self.minor(lowerCAmelCase__						,       lowerCAmelCase__				)
								else:
														raise Exception('Indices out of bounds'				)







		def 							__A						(	self				)     ->							float:
								if self.__height != self.__width:
														raise Exception('Matrix is not square'				)
								if self.__height < 1:
														raise Exception('Matrix has no element'				)
								elif self.__height == 1:
														return self.__matrix[0][0]
								elif self.__height == 2:
														return (
														    self.__matrix[0][0] * self.__matrix[1][1]
														    - self.__matrix[0][1] * self.__matrix[1][0]
														)
								else:
														SCREAMING_SNAKE_CASE													=					[
														    self.__matrix[0][y] * self.cofactor(0						,       lowerCAmelCase__				) for y in range(self.__width				)
														]
														return sum(lowerCAmelCase__				)





def     lowercase			(SCREAMING_SNAKE_CASE_		:				int  )   ->						Matrix:
						SCREAMING_SNAKE_CASE													=					[[0] * n for _ in range(SCREAMING_SNAKE_CASE_  )]
						return Matrix(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  )


def     lowercase			(SCREAMING_SNAKE_CASE_		:				int ,			SCREAMING_SNAKE_CASE_		:				int ,			SCREAMING_SNAKE_CASE_		:				int ,			SCREAMING_SNAKE_CASE_		:				int  )   ->						Matrix:
						random.seed(SCREAMING_SNAKE_CASE_  )
						SCREAMING_SNAKE_CASE													=					[
						    [random.randint(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  ) for _ in range(SCREAMING_SNAKE_CASE_  )] for _ in range(SCREAMING_SNAKE_CASE_  )
						]
						return Matrix(SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_ ,			SCREAMING_SNAKE_CASE_  )


