






'''simple docstring'''


from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

SCREAMING_SNAKE_CASE_				      =							TypeVar("T")
SCREAMING_SNAKE_CASE_				      =							TypeVar("U")




class 							lowerCAmelCase					(							Generic[T, U]   ):







   """simple docstring"""







   def __init__( self   ,   _A   ,   _A			)    ->   List[Any]:
    __a    :	Tuple									=						key
    __a    :	Dict									=						val
    __a    :	int									=						0
    __a    :	DoubleLinkedListNode[T, U] | None									=						None
    __a    :	DoubleLinkedListNode[T, U] | None									=						None



   def __repr__( self			)    ->   str:
    return "Node: key: {}, val: {}, freq: {}, has next: {}, has prev: {}".format(
        self.key   ,   self.val   ,   self.freq   ,   self.next is not None   ,   self.prev is not None			)




class 							lowerCAmelCase					(							Generic[T, U]   ):







   """simple docstring"""







   def __init__( self			)    ->   None:
    __a    :	DoubleLinkedListNode[T, U]									=						DoubleLinkedListNode(_A   ,   _A			)
    __a    :	DoubleLinkedListNode[T, U]									=						DoubleLinkedListNode(_A   ,   _A			)
    __a			,    __a    :	Any									=						self.rear, self.head



   def __repr__( self			)    ->   str:
    __a    :	Tuple									=						['DoubleLinkedList']
    __a    :	int									=						self.head
    while node.next is not None:
     rep.append(str(_A			)			)
     __a    :	Dict									=						node.next
    rep.append(str(self.rear			)			)
    return ",\n    ".join(_A			)



   def    __magic_name__    ( self   ,   _A			)    ->   None:
    __a    :	str									=						self.rear.prev

    # All nodes other than self.head are guaranteed to have non-None previous
    assert previous is not None

    __a    :	List[str]									=						node
    __a    :	int									=						previous
    __a    :	Optional[int]									=						node
    __a    :	int									=						self.rear
    node.freq += 1
    self._position_node(_A			)



   def    __magic_name__    ( self   ,   _A			)    ->   None:

    while node.prev is not None and node.prev.freq > node.freq:
     # swap node with previous node
     __a    :	Any									=						node.prev

     __a    :	Union[str, Any]									=						previous_node.prev
     __a    :	Dict									=						node.prev
     __a    :	Any									=						previous_node
     __a    :	Optional[int]									=						node



   def    __magic_name__    ( self   ,   _A			)    ->   DoubleLinkedListNode[T, U] | None:

    if node.prev is None or node.next is None:
     return None

    __a    :	Union[str, Any]									=						node.next
    __a    :	Tuple									=						node.prev
    __a    :	str									=						None
    __a    :	int									=						None
    return node




class 							lowerCAmelCase					(							Generic[T, U]   ):







   """simple docstring"""







   _A						=   {}



   def __init__( self   ,   _A			)    ->   Any:
    __a    :	DoubleLinkedList[T, U]									=						DoubleLinkedList()
    __a    :	Optional[int]									=						capacity
    __a    :	Tuple									=						0
    __a    :	List[str]									=						0
    __a    :	Tuple									=						0
    __a    :	dict[T, DoubleLinkedListNode[T, U]]									=						{}



   def __repr__( self			)    ->   str:
    return (
        f'''CacheInfo(hits={self.hits}, misses={self.miss}, '''
        f'''capacity={self.capacity}, current_size={self.num_keys})'''
    )



   def __contains__( self   ,   _A			)    ->   bool:
    return key in self.cache



   def    __magic_name__    ( self   ,   _A			)    ->   U | None:

    if key in self.cache:
     self.hits += 1
     __a    :	DoubleLinkedListNode[T, U]									=						self.cache[key]
     __a    :	List[str]									=						self.list.remove(self.cache[key]			)
     assert node == value_node

     # node is guaranteed not None because it is in self.cache
     assert node is not None
     self.list.add(_A			)
     return node.val
    self.miss += 1
    return None



   def    __magic_name__    ( self   ,   _A   ,   _A			)    ->   None:

    if key not in self.cache:
     if self.num_keys >= self.capacity:
      # delete first node when over capacity
      __a    :	Union[str, Any]									=						self.list.head.next

      # guaranteed to have a non-None first node when num_keys > 0
      # explain to type checker via assertions
      assert first_node is not None
      assert first_node.key is not None
      assert self.list.remove(_A			) is not None
      # first_node guaranteed to be in list

      del self.cache[first_node.key]
      self.num_keys -= 1
     __a    :	Dict									=						DoubleLinkedListNode(_A   ,   _A			)
     self.list.add(self.cache[key]			)
     self.num_keys += 1

    else:
     __a    :	Optional[Any]									=						self.list.remove(self.cache[key]			)
     assert node is not None  # node guaranteed to be in list
     __a    :	Optional[Any]									=						value
     self.list.add(_A			)



   @classmethod
   def    __magic_name__    ( cls   ,   _A = 128			)    ->   Callable[[Callable[[T], U]], Callable[..., U]]:

    def cache_decorator_inner(_A			) -> Callable[..., U]:
     def cache_decorator_wrapper(*_A			) -> U:
      if func not in cls.decorator_function_to_instance_map:
       __a    :	List[str]									=						LFUCache(_A			)

      __a    :	Optional[int]									=						cls.decorator_function_to_instance_map[func].get(args[0]			)
      if result is None:
       __a    :	Optional[int]									=						func(*_A			)
       cls.decorator_function_to_instance_map[func].put(args[0]   ,   _A			)
      return result

     def cache_info() -> LFUCache[T, U]:
      return cls.decorator_function_to_instance_map[func]

     setattr(_A   ,   'cache_info'   ,   _A			)  # noqa: B010

     return cache_decorator_wrapper

    return cache_decorator_inner


if __name__ == "__main__":
  import doctest

  doctest.testmod()












'''simple docstring'''


from __future__ import annotations

import random

from matplotlib import animation
from matplotlib import pyplot as plt

# Frame rate of the animation
SCREAMING_SNAKE_CASE_				      =							2_0

# Time between time steps in seconds
SCREAMING_SNAKE_CASE_				      =							INTERVAL / 1_0_0_0




class 							lowerCAmelCase					:







   """simple docstring"""







   def __init__( self   ,   _A   ,   _A   ,   _A   ,   _A   ,   _A = 1.0   ,   _A = 1.0   ,   _A = "blue"   ,   )    ->   None:
    __a    :	str									=						position_x
    __a    :	Optional[Any]									=						position_y
    __a    :	List[Any]									=						velocity_x
    __a    :	Tuple									=						velocity_y
    __a    :	Dict									=						mass
    __a    :	int									=						size
    __a    :	Tuple									=						color



   @property
   def    __magic_name__    ( self			)    ->   tuple[float, float]:
    return self.position_x, self.position_y



   @property
   def    __magic_name__    ( self			)    ->   tuple[float, float]:
    return self.velocity_x, self.velocity_y



   def    __magic_name__    ( self   ,   _A   ,   _A   ,   _A			)    ->   None:
    self.velocity_x += force_x * delta_time
    self.velocity_y += force_y * delta_time



   def    __magic_name__    ( self   ,   _A			)    ->   None:
    self.position_x += self.velocity_x * delta_time
    self.position_y += self.velocity_y * delta_time




class 							lowerCAmelCase					:







   """simple docstring"""







   def __init__( self   ,   _A   ,   _A = 1.0   ,   _A = 1.0   ,   _A = 0.0   ,   )    ->   None:
    __a    :	List[str]									=						bodies
    __a    :	List[str]									=						gravitation_constant
    __a    :	int									=						time_factor
    __a    :	List[str]									=						softening_factor



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



   def    __magic_name__    ( self   ,   _A			)    ->   None:
    for bodya in self.bodies:
     __a    :	Any									=						0.0
     __a    :	str									=						0.0
     for bodya in self.bodies:
      if bodya != bodya:
       __a    :	Optional[Any]									=						bodya.position_x - bodya.position_x
       __a    :	Dict									=						bodya.position_y - bodya.position_y

       # Calculation of the distance using Pythagoras's theorem
       # Extra factor due to the softening technique
       __a    :	Optional[Any]									=						(dif_x**2 + dif_y**2 + self.softening_factor) ** (
           1 / 2
       )

       # Newton's law of universal gravitation.
       force_x += (
           self.gravitation_constant * bodya.mass * dif_x / distance**3
       )
       force_y += (
           self.gravitation_constant * bodya.mass * dif_y / distance**3
       )

            # Update the body's velocity once all the force components have been added
     bodya.update_velocity(_A   ,   _A   ,   delta_time * self.time_factor			)

    # Update the positions only after all the velocities have been updated
    for body in self.bodies:
     body.update_position(delta_time * self.time_factor			)






def   lowerCAmelCase__			(					SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__		):
 body_system.update_system(SCREAMING_SNAKE_CASE__		)

 # Update the positions of the patches
 for patch, body in zip(SCREAMING_SNAKE_CASE__       ,		body_system.bodies		):
  __a    :	Dict									=						(body.position_x, body.position_y)






def   lowerCAmelCase__			(					SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__ = -1       ,		SCREAMING_SNAKE_CASE__ = 1       ,		SCREAMING_SNAKE_CASE__ = -1       ,		SCREAMING_SNAKE_CASE__ = 1       ,		):
 __a    :	int									=						plt.figure()
 fig.canvas.set_window_title(SCREAMING_SNAKE_CASE__		)
 __a    :	int									=						plt.axes(
     xlim=(x_start, x_end)       ,		ylim=(y_start, y_end)		)  # Set section to be plotted
 plt.gca().set_aspect('equal'		)  # Fix aspect ratio

 # Each body is drawn as a patch by the plt-function
 __a    :	str									=						[
     plt.Circle((body.position_x, body.position_y)       ,		body.size       ,		fc=body.color		)
     for body in body_system.bodies
 ]

 for patch in patches:
  ax.add_patch(SCREAMING_SNAKE_CASE__		)

 # Function called at each step of the animation
 def update(SCREAMING_SNAKE_CASE__		) -> list[plt.Circle]:
  update_step(SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__		)
  return patches

 __a    :	Dict									=						animation.FuncAnimation(  # noqa: F841
     SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		interval=SCREAMING_SNAKE_CASE__       ,		blit=SCREAMING_SNAKE_CASE__		)

 plt.show()






def   lowerCAmelCase__			(					):
 __a    :	Dict									=						0.970_0436
 __a    :	List[Any]									=						-0.2430_8753
 __a    :	Union[str, Any]									=						0.4_6620_3685
 __a    :	Any									=						0.4323_6573

 __a    :	Optional[int]									=						[
     Body(SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		size=0.2       ,		color='red'		),
     Body(-position_x       ,		-position_y       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		size=0.2       ,		color='green'		),
     Body(0       ,		0       ,		-2 * velocity_x       ,		-2 * velocity_y       ,		size=0.2       ,		color='blue'		),
 ]
 return BodySystem(SCREAMING_SNAKE_CASE__       ,		time_factor=3		)






def   lowerCAmelCase__			(					):
 __a    :	Optional[int]									=						7.34_76E22
 __a    :	List[Any]									=						5.9_72E24
 __a    :	List[Any]									=						1022
 __a    :	str									=						384399000
 __a    :	Optional[int]									=						6.6_74E-11

 # Calculation of the respective velocities so that total impulse is zero,
 # i.e. the two bodies together don't move
 __a    :	str									=						earth_mass * velocity_dif / (earth_mass + moon_mass)
 __a    :	Optional[int]									=						moon_velocity - velocity_dif

 __a    :	Union[str, Any]									=						Body(-earth_moon_distance       ,		0       ,		0       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		10000000       ,		'grey'		)
 __a    :	Union[str, Any]									=						Body(0       ,		0       ,		0       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		50000000       ,		'blue'		)
 return BodySystem([earth, moon]       ,		SCREAMING_SNAKE_CASE__       ,		time_factor=1000000		)






def   lowerCAmelCase__			(					):
 __a    :	Tuple									=						[]
 for _ in range(10		):
  __a    :	Dict									=						random.uniform(-0.5       ,		0.5		)
  __a    :	Optional[int]									=						random.uniform(-0.5       ,		0.5		)

  # Bodies are created pairwise with opposite velocities so that the
  # total impulse remains zero
  bodies.append(
      Body(
          random.uniform(-0.5       ,		0.5		)       ,		random.uniform(-0.5       ,		0.5		)       ,		SCREAMING_SNAKE_CASE__       ,		SCREAMING_SNAKE_CASE__       ,		size=0.05       ,		)		)
  bodies.append(
      Body(
          random.uniform(-0.5       ,		0.5		)       ,		random.uniform(-0.5       ,		0.5		)       ,		-velocity_x       ,		-velocity_y       ,		size=0.05       ,		)		)
 return BodySystem(SCREAMING_SNAKE_CASE__       ,		0.01       ,		10       ,		0.1		)


if __name__ == "__main__":
  plot("Figure-8 solution to the 3-body-problem", example_a(), -2, 2, -2, 2)
  plot(
      "Moon's orbit around the earth",
      example_a(),
      -4_3_0_0_0_0_0_0_0,
      4_3_0_0_0_0_0_0_0,
      -4_3_0_0_0_0_0_0_0,
      4_3_0_0_0_0_0_0_0,
  )
  plot("Random system with many bodies", example_a(), -1.5, 1.5, -1.5, 1.5)




