'''simple docstring'''


from dataclasses import dataclass
from typing import Tuple

import numpy as np
import torch






@dataclass
class 					__SCREAMING_SNAKE_CASE						:







  '''simple docstring'''






  lowerCamelCase_		:torch.Tensor  # [batch_size x 3]
  lowerCamelCase_		:torch.Tensor  # [batch_size x 3]
  lowerCamelCase_		:torch.Tensor  # [batch_size x 3]
  lowerCamelCase_		:torch.Tensor  # [batch_size x 3]
  lowerCamelCase_		:int
  lowerCamelCase_		:int
  lowerCamelCase_		:float
  lowerCamelCase_		:float
  lowerCamelCase_		:Tuple[int]


  def _UpperCamelCase					(			self						):




       '''simple docstring'''

       assert self.x.shape[0] == self.y.shape[0] == self.z.shape[0] == self.origin.shape[0]
       assert self.x.shape[1] == self.y.shape[1] == self.z.shape[1] == self.origin.shape[1] == 3
       assert len(self.x.shape						) == len(self.y.shape						) == len(self.z.shape						) == len(self.origin.shape						) == 2


  def _UpperCamelCase					(			self						):




       '''simple docstring'''

       return torch.from_numpy(np.array([self.width, self.height]				,		dtype=np.floataa						)						)


  def _UpperCamelCase					(			self						):




       '''simple docstring'''

       return torch.from_numpy(np.array([self.x_fov, self.y_fov]				,		dtype=np.floataa						)						)


  def _UpperCamelCase					(			self						):




       '''simple docstring'''

       UpperCAmelCase_							:       List[Any]       =				torch.arange(self.height * self.width						)
       UpperCAmelCase_							:       Optional[int]       =				torch.stack(
           [
               pixel_indices % self.width,
               torch.div(UpperCamelCase_				,		self.width				,		rounding_mode='trunc'						),
           ]				,		axis=1				,		)
       return coords


  @property
  def _UpperCamelCase					(			self						):




       '''simple docstring'''

       UpperCAmelCase_       ,      *UpperCAmelCase_							:       int       =				self.shape
       UpperCAmelCase_							:       int       =				int(np.prod(UpperCamelCase_						)						)

       UpperCAmelCase_							:       List[str]       =				self.get_image_coords()
       UpperCAmelCase_							:       Union[str, Any]       =				torch.broadcast_to(coords.unsqueeze(0						)				,		[batch_size * inner_batch_size, *coords.shape]						)
       UpperCAmelCase_							:       Tuple       =				self.get_camera_rays(UpperCamelCase_						)

       UpperCAmelCase_							:       Union[str, Any]       =				rays.view(UpperCamelCase_				,		inner_batch_size * self.height * self.width				,		2				,		3						)

       return rays


  def _UpperCamelCase					(			self				,		snake_case_						):




       '''simple docstring'''

       UpperCAmelCase_       ,      *UpperCAmelCase_       ,      UpperCAmelCase_							:       Union[str, Any]       =				coords.shape
       assert n_coords == 2
       assert batch_size == self.origin.shape[0]

       UpperCAmelCase_							:       Tuple       =				coords.view(UpperCamelCase_				,		-1				,		2						)

       UpperCAmelCase_							:       Tuple       =				self.resolution()
       UpperCAmelCase_							:       str       =				self.fov()

       UpperCAmelCase_							:       List[Any]       =				(flat.float() / (res - 1)) * 2 - 1
       UpperCAmelCase_							:       Any       =				fracs * torch.tan(fov / 2						)

       UpperCAmelCase_							:       str       =				fracs.view(UpperCamelCase_				,		-1				,		2						)
       UpperCAmelCase_							:       Dict       =				(
           self.z.view(UpperCamelCase_				,		1				,		3						)
           + self.x.view(UpperCamelCase_				,		1				,		3						) * fracs[:, :, :1]
           + self.y.view(UpperCamelCase_				,		1				,		3						) * fracs[:, :, 1:]
       )
       UpperCAmelCase_							:       Tuple       =				directions / directions.norm(dim=-1				,		keepdim=UpperCamelCase_						)
       UpperCAmelCase_							:       Dict       =				torch.stack(
           [
               torch.broadcast_to(self.origin.view(UpperCamelCase_				,		1				,		3						)				,		[batch_size, directions.shape[1], 3]						),
               directions,
           ]				,		dim=2				,		)
       return rays.view(UpperCamelCase_				,		*UpperCamelCase_				,		2				,		3						)






  def _UpperCamelCase					(			self				,		snake_case_				,		snake_case_						):




       '''simple docstring'''

       assert width * self.height == height * self.width, "The aspect ratio should not change."
       return DifferentiableProjectiveCamera(
           origin=self.origin				,		x=self.x				,		y=self.y				,		z=self.z				,		width=UpperCamelCase_				,		height=UpperCamelCase_				,		x_fov=self.x_fov				,		y_fov=self.y_fov				,		)







def  _lowerCamelCase   (				lowerCamelCase_ :							List[Any]       ):



     """simple docstring"""





     UpperCAmelCase_							:       Optional[Any]       =				[]
     UpperCAmelCase_							:       List[str]       =				[]
     UpperCAmelCase_							:       str       =				[]
     UpperCAmelCase_							:       Any       =				[]
     for theta in np.linspace(0     ,					2 * np.pi     ,					num=20       ):
          UpperCAmelCase_							:       Dict       =				np.array([np.sin(lowerCamelCase_       ), np.cos(lowerCamelCase_       ), -0.5]       )
          z /= np.sqrt(np.sum(z**2       )       )
          UpperCAmelCase_							:       int       =				-z * 4
          UpperCAmelCase_							:       Tuple       =				np.array([np.cos(lowerCamelCase_       ), -np.sin(lowerCamelCase_       ), 0.0]       )
          UpperCAmelCase_							:       List[Any]       =				np.cross(lowerCamelCase_     ,					lowerCamelCase_       )
          origins.append(lowerCamelCase_       )
          xs.append(lowerCamelCase_       )
          ys.append(lowerCamelCase_       )
          zs.append(lowerCamelCase_       )
     return DifferentiableProjectiveCamera(
         origin=torch.from_numpy(np.stack(lowerCamelCase_     ,					axis=0       )       ).float()     ,					x=torch.from_numpy(np.stack(lowerCamelCase_     ,					axis=0       )       ).float()     ,					y=torch.from_numpy(np.stack(lowerCamelCase_     ,					axis=0       )       ).float()     ,					z=torch.from_numpy(np.stack(lowerCamelCase_     ,					axis=0       )       ).float()     ,					width=lowerCamelCase_     ,					height=lowerCamelCase_     ,					x_fov=0.7     ,					y_fov=0.7     ,					shape=(1, len(lowerCamelCase_       ))     ,					)







'''simple docstring'''


from manim import *






class 					__SCREAMING_SNAKE_CASE						(	lowerCamelCase_	):







  '''simple docstring'''






  def _UpperCamelCase					(			self						):




       '''simple docstring'''

       UpperCAmelCase_							:       Dict       =				Rectangle(height=0.5				,		width=0.5						)
       UpperCAmelCase_							:       Any       =				Rectangle(height=0.46				,		width=0.46						).set_stroke(width=0						)

       UpperCAmelCase_							:       List[str]       =				Rectangle(height=0.25				,		width=0.25						)

       UpperCAmelCase_							:       Any       =				[mem.copy() for i in range(6						)]
       UpperCAmelCase_							:       Union[str, Any]       =				[mem.copy() for i in range(6						)]
       UpperCAmelCase_							:       Optional[int]       =				VGroup(*snake_case_						).arrange(snake_case_				,		buff=0						)
       UpperCAmelCase_							:       Any       =				VGroup(*snake_case_						).arrange(snake_case_				,		buff=0						)
       UpperCAmelCase_							:       str       =				VGroup(snake_case_				,		snake_case_						).arrange(snake_case_				,		buff=0						)
       UpperCAmelCase_							:       Any       =				Text('CPU'				,		font_size=2_4						)
       UpperCAmelCase_							:       Tuple       =				Group(snake_case_				,		snake_case_						).arrange(snake_case_				,		buff=0.5				,		aligned_edge=snake_case_						)
       cpu.move_to([-2.5, -0.5, 0]						)
       self.add(snake_case_						)

       UpperCAmelCase_							:       str       =				[mem.copy() for i in range(4						)]
       UpperCAmelCase_							:       Dict       =				VGroup(*snake_case_						).arrange(snake_case_				,		buff=0						)
       UpperCAmelCase_							:       List[str]       =				Text('GPU'				,		font_size=2_4						)
       UpperCAmelCase_							:       Optional[int]       =				Group(snake_case_				,		snake_case_						).arrange(snake_case_				,		buff=0.5				,		aligned_edge=snake_case_						)
       gpu.move_to([-1, -1, 0]						)
       self.add(snake_case_						)

       UpperCAmelCase_							:       str       =				[mem.copy() for i in range(6						)]
       UpperCAmelCase_							:       Tuple       =				VGroup(*snake_case_						).arrange(snake_case_				,		buff=0						)

       UpperCAmelCase_							:       str       =				Text('Model'				,		font_size=2_4						)
       UpperCAmelCase_							:       Optional[int]       =				Group(snake_case_				,		snake_case_						).arrange(snake_case_				,		buff=0.5				,		aligned_edge=snake_case_						)
       model.move_to([3, -1.0, 0]						)
       self.add(snake_case_						)

       UpperCAmelCase_							:       str       =				[]
       UpperCAmelCase_							:       Optional[Any]       =				[]

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

            UpperCAmelCase_							:       int       =				Rectangle(height=0.46				,		width=0.46						).set_stroke(width=0.0						).set_fill(snake_case_				,		opacity=0.8						)
            cpu_target.move_to(cpu_left_col_base[i]						)
            model_cpu_arr.append(snake_case_						)

       self.add(*snake_case_				,		*snake_case_						)

       UpperCAmelCase_							:       List[Any]       =				[meta_mem.copy() for i in range(6						)]
       UpperCAmelCase_							:       List[str]       =				[meta_mem.copy() for i in range(6						)]
       UpperCAmelCase_							:       Tuple       =				VGroup(*snake_case_						).arrange(snake_case_				,		buff=0						)
       UpperCAmelCase_							:       Dict       =				VGroup(*snake_case_						).arrange(snake_case_				,		buff=0						)
       UpperCAmelCase_							:       Optional[Any]       =				VGroup(snake_case_				,		snake_case_						).arrange(snake_case_				,		buff=0						)
       UpperCAmelCase_							:       Tuple       =				Text('Disk'				,		font_size=2_4						)
       UpperCAmelCase_							:       Union[str, Any]       =				Group(snake_case_				,		snake_case_						).arrange(snake_case_				,		buff=0.5				,		aligned_edge=snake_case_						)
       disk.move_to([-4, -1.25, 0]						)
       self.add(snake_case_				,		snake_case_						)

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

       UpperCAmelCase_							:       Any       =				MarkupText(
           F'''<b>Key:</b>\n\n<span fgcolor=\'{YELLOW}\'>●</span> Empty Model'''				,		font_size=1_8				,		)

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

       self.add(snake_case_				,		snake_case_						)

       UpperCAmelCase_							:       Dict       =				MarkupText(
           F'''<span fgcolor=\'{BLUE}\'>●</span> Checkpoint'''				,		font_size=1_8				,		)

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

       UpperCAmelCase_							:       Optional[Any]       =				MarkupText(
           F'''Now watch as an input is passed through the model\nand how the memory is utilized and handled.'''				,		font_size=2_4				,		)
       step_a.move_to([2, 2, 0]						)

       self.play(Write(snake_case_						)						)

       UpperCAmelCase_							:       Tuple       =				Square(0.3						)
       input.set_fill(snake_case_				,		opacity=1.0						)
       input.set_stroke(width=0.0						)
       input.next_to(model_base[0]				,		snake_case_				,		buff=0.5						)

       self.play(Write(snake_case_						)						)

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

       self.play(FadeOut(snake_case_						)						)

       UpperCAmelCase_							:       Any       =				Arrow(start=snake_case_				,		end=snake_case_				,		color=snake_case_				,		buff=0.5						)
       a.next_to(model_arr[0].get_left()				,		snake_case_				,		buff=0.2						)

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

       UpperCAmelCase_							:       List[str]       =				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=2_4				,		)
       step_a.move_to([2, 2, 0]						)

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

       UpperCAmelCase_							:       List[Any]       =				{'run_time': 1, 'fade_in': True, 'fade_out': True, 'buff': 0.02}

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

       UpperCAmelCase_							:       Union[str, Any]       =				a.copy()
       for i in range(6						):
            a_c.next_to(model_arr[i].get_right() + 0.02				,		snake_case_				,		buff=0.2						)

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

            UpperCAmelCase_							:       Tuple       =				AnimationGroup(
                FadeOut(snake_case_				,		run_time=0.5						)				,		MoveToTarget(snake_case_				,		run_time=0.5						)				,		FadeIn(snake_case_				,		run_time=0.5						)				,		lag_ratio=0.2						)

            self.play(snake_case_						)

            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_							:       Any       =				0.7

                 self.play(
                     Circumscribe(model_arr[i]				,		**snake_case_						)				,		Circumscribe(cpu_left_col_base[i]				,		**snake_case_						)				,		Circumscribe(cpu_left_col_base[i + 1]				,		color=snake_case_				,		**snake_case_						)				,		Circumscribe(gpu_rect[0]				,		color=snake_case_				,		**snake_case_						)				,		Circumscribe(model_arr[i + 1]				,		color=snake_case_				,		**snake_case_						)				,		)
                 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=snake_case_				,		**snake_case_						)				,		Circumscribe(cpu_left_col_base[-1]				,		color=snake_case_				,		**snake_case_						)				,		Circumscribe(gpu_rect[0]				,		color=snake_case_				,		**snake_case_						)				,		)

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

            UpperCAmelCase_							:       Any       =				a_c
            UpperCAmelCase_							:       int       =				a_c.copy()

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

       UpperCAmelCase_							:       Optional[Any]       =				MarkupText(F'''Inference on a model too large for GPU memory\nis successfully completed.'''				,		font_size=2_4						)
       step_a.move_to([2, 2, 0]						)

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

       self.wait()






