



"""simple docstring"""







from manim import *





class   UpperCamelCase	(     snake_case       ):




	"""simple docstring"""






	def    lowerCamelCase__					(     self   ):
			_lowercase				: Optional[int]     =   Rectangle(height=0.5				,width=0.5   )
			_lowercase				: int     =   Rectangle(height=0.46				,width=0.46   ).set_stroke(width=0   )
			_lowercase				: Optional[int]     =   Rectangle(height=0.25				,width=0.25   )

			_lowercase				: str     =   [mem.copy() for i in range(6   )]
			_lowercase				: Dict     =   [mem.copy() for i in range(6   )]
			_lowercase				: Optional[int]     =   VGroup(*UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )
			_lowercase				: List[str]     =   VGroup(*UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )
			_lowercase				: str     =   VGroup(UpperCAmelCase_				,UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )
			_lowercase				: Any     =   Text("""CPU"""				,font_size=24   )
			_lowercase				: List[Any]     =   Group(UpperCAmelCase_				,UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0.5				,aligned_edge=UpperCAmelCase_   )
			cpu.move_to([-2.5, -0.5, 0]   )
			self.add(UpperCAmelCase_   )

			_lowercase				: str     =   [mem.copy() for i in range(4   )]
			_lowercase				: Optional[Any]     =   VGroup(*UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )
			_lowercase				: Tuple     =   Text("""GPU"""				,font_size=24   )
			_lowercase				: str     =   Group(UpperCAmelCase_				,UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0.5				,aligned_edge=UpperCAmelCase_   )
			gpu.move_to([-1, -1, 0]   )
			self.add(UpperCAmelCase_   )

			_lowercase				: Union[str, Any]     =   [mem.copy() for i in range(6   )]
			_lowercase				: Optional[int]     =   VGroup(*UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )

			_lowercase				: Any     =   Text("""Model"""				,font_size=24   )
			_lowercase				: str     =   Group(UpperCAmelCase_				,UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0.5				,aligned_edge=UpperCAmelCase_   )
			model.move_to([3, -1.0, 0]   )
			self.add(UpperCAmelCase_   )

			_lowercase				: List[str]     =   []
			_lowercase				: int     =   []

			for i, rect in enumerate(UpperCAmelCase_   ):
					rect.set_stroke(UpperCAmelCase_   )

					_lowercase				: str     =   Rectangle(height=0.46 / 4				,width=0.46 / 3   ).set_stroke(width=0.0   ).set_fill(UpperCAmelCase_				,opacity=0.7   )

					if i == 0:
							cpu_target.next_to(cpu_left_col_base[0].get_corner(DOWN + LEFT   )				,buff=0.02				,direction=UpperCAmelCase_   )
							cpu_target.set_x(cpu_target.get_x() + 0.1   )
					elif i == 3:
							cpu_target.next_to(model_cpu_arr[0]				,direction=UpperCAmelCase_				,buff=0.0   )
					else:
							cpu_target.next_to(model_cpu_arr[i - 1]				,direction=UpperCAmelCase_				,buff=0.0   )
					self.add(UpperCAmelCase_   )
					model_cpu_arr.append(UpperCAmelCase_   )

			self.add(*UpperCAmelCase_				,*UpperCAmelCase_   )

			_lowercase				: Dict     =   [meta_mem.copy() for i in range(6   )]
			_lowercase				: List[Any]     =   [meta_mem.copy() for i in range(6   )]
			_lowercase				: Optional[Any]     =   VGroup(*UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )
			_lowercase				: int     =   VGroup(*UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )
			_lowercase				: Any     =   VGroup(UpperCAmelCase_				,UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0   )
			_lowercase				: List[Any]     =   Text("""Disk"""				,font_size=24   )
			_lowercase				: Optional[Any]     =   Group(UpperCAmelCase_				,UpperCAmelCase_   ).arrange(UpperCAmelCase_				,buff=0.5				,aligned_edge=UpperCAmelCase_   )
			disk.move_to([-4.0, -1.25, 0]   )
			self.add(UpperCAmelCase_				,UpperCAmelCase_   )

			_lowercase				: Any     =   []

			for i in range(6   ):
					_lowercase				: Union[str, Any]     =   fill.copy().set_fill(UpperCAmelCase_				,opacity=0.8   )
					target.move_to(disk_left_col_base[i]   ).scale(0.5   )
					cpu_disk_arr.append(UpperCAmelCase_   )

			self.add(*UpperCAmelCase_   )

			_lowercase				: List[Any]     =   Square(side_length=2.2   )
			key.move_to([-5, 2, 0]   )

			_lowercase				: Any     =   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(UpperCAmelCase_				,UpperCAmelCase_   )

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

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

			_lowercase				: Any     =   MarkupText(f"""The offloaded weights are all sent to the CPU."""				,font_size=24   )
			step_a.move_to([2, 2, 0]   )

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

			for i in range(6   ):
					_lowercase				: Dict     =   cpu_disk_arr[i]
					_lowercase				: Optional[int]     =   rect.copy().set_fill(UpperCAmelCase_				,opacity=0.8   ).scale(2.0   )
					cpa.generate_target()
					cpa.target.move_to(model_base[i]   )

					if i == 0:
							rect.set_fill(UpperCAmelCase_				,opacity=0.8   )
							rect.generate_target()
							rect.target.move_to(cpu_left_col_base[0]   ).scale(2.0   )

							self.remove(
							    *UpperCAmelCase_				,*UpperCAmelCase_				,)

					else:
							rect.generate_target()
							rect.target.move_to(cpu_left_col_base[i]   ).scale(2.0   )
					self.play(MoveToTarget(UpperCAmelCase_   )				,MoveToTarget(UpperCAmelCase_   )				,model_base[i].animate.set_stroke(UpperCAmelCase_   )   )
			self.play(FadeOut(UpperCAmelCase_   )   )

			_lowercase				: List[Any]     =   MarkupText(
			    f"""Finally, hooks are added to each weight in the model\nto transfer the weights from CPU to GPU\n\t\tand back when needed."""				,font_size=24				,)
			step_a.move_to([2, 2, 0]   )

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

			_lowercase				: Any     =   []
			_lowercase				: Tuple     =   []
			for i in range(6   ):
					_lowercase				: List[str]     =   Arrow(start=UpperCAmelCase_				,end=UpperCAmelCase_				,color=UpperCAmelCase_				,buff=0.5   )
					a.next_to(model_base[i].get_left()				,UpperCAmelCase_				,buff=0.2   )
					arrows.append(UpperCAmelCase_   )
					animations.append(Write(UpperCAmelCase_   )   )
			self.play(*UpperCAmelCase_   )
			self.wait()










from __future__ import annotations

from collections import deque
from enum import Enum
from math import atana, degrees
from sys import maxsize







class        __snake_case			(				__lowerCamelCase     ):





       '''simple docstring'''







       lowerCAmelCase__ 						=	1
       lowerCAmelCase__ 						=	2
       lowerCAmelCase__ 						=	3




       def __repr__(    self					:       Optional[int]						):
         return f'''{self.__class__.__name__}.{self.name}'''







def      A__				(       SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__)  ->       float:
  __snake_case    ,  __snake_case:		Union[str, Any]					    =		point
  return degrees(atana(y - miny   ,   x - minx))







def      A__				(       SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__)  ->       Direction:
  __snake_case    ,  __snake_case:		Dict					    =		starting
  __snake_case    ,  __snake_case:		List[str]					    =		via
  __snake_case    ,  __snake_case:		Optional[int]					    =		target
  __snake_case:		int					    =		degrees(atana(ya - ya   ,   xa - xa))
  via_angle %= 360
  __snake_case:		List[Any]					    =		degrees(atana(ya - ya   ,   xa - xa))
  target_angle %= 360
  # t-
  #  \ \
  #   \ v
  #    \|
  #     s
  # via_angle is always lower than target_angle, if direction is left.
  # If they are same, it means they are on a same line of convex hull.
  if target_angle > via_angle:
    return Direction.left
  elif target_angle == via_angle:
    return Direction.straight
  else:
    return Direction.right







def      A__				(       SCREAMING_SNAKE_CASE__)  ->       list[tuple[int, int]]:

  if len(SCREAMING_SNAKE_CASE__) <= 2:
    # There is no convex hull
    raise ValueError("""graham_scan: argument must contain more than 3 points.""")
  if len(SCREAMING_SNAKE_CASE__) == 3:
    return points
  # find the lowest and the most left point
  __snake_case:		Optional[int]					    =		0
  __snake_case    ,  __snake_case:		Optional[int]					    =		maxsize, maxsize
  for i, point in enumerate(SCREAMING_SNAKE_CASE__):
    __snake_case:		Tuple					    =		point[0]
    __snake_case:		Optional[Any]					    =		point[1]
    if y < miny:
      __snake_case:		Optional[Any]					    =		y
      __snake_case:		Union[str, Any]					    =		x
      __snake_case:		Any					    =		i
    if y == miny and x < minx:
      __snake_case:		Optional[Any]					    =		x
      __snake_case:		str					    =		i

    # remove the lowest and the most left point from points for preparing for sort
  points.pop(SCREAMING_SNAKE_CASE__)

  __snake_case:		Optional[int]					    =		sorted(SCREAMING_SNAKE_CASE__   ,   key=lambda SCREAMING_SNAKE_CASE__: angle_comparer(SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__))
  # This insert actually costs complexity,
  # and you should instead add (minx, miny) into stack later.
  # I'm using insert just for easy understanding.
  sorted_points.insert(0   ,   (minx, miny))

  __snake_case:		deque[tuple[int, int]]					    =		deque()
  stack.append(sorted_points[0])
  stack.append(sorted_points[1])
  stack.append(sorted_points[2])
  # In any ways, the first 3 points line are towards left.
  # Because we sort them the angle from minx, miny.
  __snake_case:		Optional[Any]					    =		Direction.left

  for i in range(3   ,   len(SCREAMING_SNAKE_CASE__)):
    while True:
      __snake_case:		Optional[Any]					    =		stack[-2]
      __snake_case:		List[Any]					    =		stack[-1]
      __snake_case:		int					    =		sorted_points[i]
      __snake_case:		Union[str, Any]					    =		check_direction(SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__   ,   SCREAMING_SNAKE_CASE__)

      if next_direction == Direction.left:
        __snake_case:		Dict					    =		Direction.left
        break
      if next_direction == Direction.straight:
        if current_direction == Direction.left:
          # We keep current_direction as left.
          # Because if the straight line keeps as straight,
          # we want to know if this straight line is towards left.
          break
        elif current_direction == Direction.right:
          # If the straight line is towards right,
          # every previous points on those straigh line is not convex hull.
          stack.pop()
      if next_direction == Direction.right:
        stack.pop()
    stack.append(sorted_points[i])
  return list(SCREAMING_SNAKE_CASE__)






