





from __future__ import annotations

from math import pi, pow



def _a       (			lowerCamelCase:     int | float				)			->		float:







      '''simple docstring'''






      if side_length < 0:
            raise ValueError('''vol_cube() only accepts non-negative values'''				)
      return pow(lowerCamelCase      ,       3				)



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if height < 0 or radius < 0:
            raise ValueError('''vol_spherical_cap() only accepts non-negative values'''				)
      # Volume is 1/3 pi * height squared * (3 * radius - height)
      return 1 / 3 * pi * pow(lowerCamelCase      ,       2				) * (3 * radius - height)



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if radius_a < 0 or radius_a < 0 or centers_distance < 0:
            raise ValueError('''vol_spheres_intersect() only accepts non-negative values'''				)
      if centers_distance == 0:
            return vol_sphere(min(lowerCamelCase      ,       lowerCamelCase				)				)

      __A      =       (
          (radius_a - radius_a + centers_distance)
          * (radius_a + radius_a - centers_distance)
          / (2 * centers_distance)
      )
      __A      =       (
          (radius_a - radius_a + centers_distance)
          * (radius_a + radius_a - centers_distance)
          / (2 * centers_distance)
      )

      return vol_spherical_cap(lowerCamelCase      ,       lowerCamelCase				) + vol_spherical_cap(lowerCamelCase      ,       lowerCamelCase				)



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if radius_a <= 0 or radius_a <= 0 or centers_distance < 0:
            raise ValueError(
                '''vol_spheres_union() only accepts non-negative values, non-zero radius'''				)

      if centers_distance == 0:
            return vol_sphere(max(lowerCamelCase      ,       lowerCamelCase				)				)

      return (
          vol_sphere(lowerCamelCase				)
          + vol_sphere(lowerCamelCase				)
          - vol_spheres_intersect(lowerCamelCase      ,       lowerCamelCase      ,       lowerCamelCase				)
      )



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if width < 0 or height < 0 or length < 0:
            raise ValueError('''vol_cuboid() only accepts non-negative values'''				)
      return float(width * height * length				)



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if height < 0 or area_of_base < 0:
            raise ValueError('''vol_cone() only accepts non-negative values'''				)
      return area_of_base * height / 3.0



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if height < 0 or radius < 0:
            raise ValueError('''vol_right_circ_cone() only accepts non-negative values'''				)
      return pi * pow(lowerCamelCase      ,       2				) * height / 3.0



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if height < 0 or area_of_base < 0:
            raise ValueError('''vol_prism() only accepts non-negative values'''				)
      return float(area_of_base * height				)



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if height < 0 or area_of_base < 0:
            raise ValueError('''vol_pyramid() only accepts non-negative values'''				)
      return area_of_base * height / 3.0



def _a       (			lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if radius < 0:
            raise ValueError('''vol_sphere() only accepts non-negative values'''				)
      # Volume is 4/3 * pi * radius cubed
      return 4 / 3 * pi * pow(lowerCamelCase      ,       3				)



def _a       (			lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if radius < 0:
            raise ValueError('''vol_hemisphere() only accepts non-negative values'''				)
      # Volume is radius cubed * pi * 2/3
      return pow(lowerCamelCase      ,       3				) * pi * 2 / 3



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if height < 0 or radius < 0:
            raise ValueError('''vol_circular_cylinder() only accepts non-negative values'''				)
      # Volume is radius squared * height * pi
      return pow(lowerCamelCase      ,       2				) * height * pi



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if inner_radius < 0 or outer_radius < 0 or height < 0:
            raise ValueError(
                '''vol_hollow_circular_cylinder() only accepts non-negative values'''				)
      if outer_radius <= inner_radius:
            raise ValueError('''outer_radius must be greater than inner_radius'''				)
      return pi * (pow(lowerCamelCase      ,       2				) - pow(lowerCamelCase      ,       2				)) * height



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if radius_a < 0 or radius_a < 0 or height < 0:
            raise ValueError('''vol_conical_frustum() only accepts non-negative values'''				)
      return (
          1
          / 3
          * pi
          * height
          * (pow(lowerCamelCase      ,       2				) + pow(lowerCamelCase      ,       2				) + radius_a * radius_a)
      )



def _a       (			lowerCamelCase:     float      ,       lowerCamelCase:     float				)			->		float:







      '''simple docstring'''






      if torus_radius < 0 or tube_radius < 0:
            raise ValueError('''vol_torus() only accepts non-negative values'''				)
      return 2 * pow(lowerCamelCase      ,       2				) * torus_radius * pow(lowerCamelCase      ,       2				)



def _a       (			)			->		List[Any]:







      '''simple docstring'''






      print('''Volumes:'''				)
      print(F"""Cube: {vol_cube(2				) = }"""				)  # = 8
      print(F"""Cuboid: {vol_cuboid(2      ,       2      ,       2				) = }"""				)  # = 8
      print(F"""Cone: {vol_cone(2      ,       2				) = }"""				)  # ~= 1.33
      print(F"""Right Circular Cone: {vol_right_circ_cone(2      ,       2				) = }"""				)  # ~= 8.38
      print(F"""Prism: {vol_prism(2      ,       2				) = }"""				)  # = 4
      print(F"""Pyramid: {vol_pyramid(2      ,       2				) = }"""				)  # ~= 1.33
      print(F"""Sphere: {vol_sphere(2				) = }"""				)  # ~= 33.5
      print(F"""Hemisphere: {vol_hemisphere(2				) = }"""				)  # ~= 16.75
      print(F"""Circular Cylinder: {vol_circular_cylinder(2      ,       2				) = }"""				)  # ~= 25.1
      print(F"""Torus: {vol_torus(2      ,       2				) = }"""				)  # ~= 157.9
      print(F"""Conical Frustum: {vol_conical_frustum(2      ,       2      ,       4				) = }"""				)  # ~= 58.6
      print(F"""Spherical cap: {vol_spherical_cap(1      ,       2				) = }"""				)  # ~= 5.24
      print(F"""Spheres intersetion: {vol_spheres_intersect(2      ,       2      ,       1				) = }"""				)  # ~= 21.21
      print(F"""Spheres union: {vol_spheres_union(2      ,       2      ,       1				) = }"""				)  # ~= 45.81
      print(
          F"""Hollow Circular Cylinder: {vol_hollow_circular_cylinder(1      ,       2      ,       3				) = }"""				)  # ~= 28.3


if __name__ == "__main__":
       main()












class A_      :




   def __init__(self			:Union[str, Any]				)->      None:
         # numbermap keys are the number and its values are lists of indexes sorted
         # in ascending order
         __A      =       {}
         # indexmap keys are an index and it's values are the number at that index
         __A      =       {}




   def _lowerCAmelCase   (self			:Any					,     _UpperCamelCase			:list | str | range					,     _UpperCamelCase			:int				)->      list[int]:
         if isinstance(_UpperCamelCase					,     (range, str)				):
               __A      =       list(_UpperCamelCase				)
         elif not isinstance(_UpperCamelCase					,     _UpperCamelCase				):
               raise TypeError(
                   '''binary_search_delete() only accepts either a list, range or str'''				)

         __A      =       0
         __A      =       len(_UpperCamelCase				) - 1

         while low <= high:
               __A      =       (low + high) // 2
               if array[mid] == item:
                     array.pop(_UpperCamelCase				)
                     return array
               elif array[mid] < item:
                     __A      =       mid + 1
               else:
                     __A      =       mid - 1
         raise ValueError(
             '''Either the item is not in the array or the array was unsorted'''				)




   def _lowerCAmelCase   (self			:Optional[Any]					,     _UpperCamelCase			:list | str | range					,     _UpperCamelCase			:int				)->      list[int]:
         if isinstance(_UpperCamelCase					,     (range, str)				):
               __A      =       list(_UpperCamelCase				)
         elif not isinstance(_UpperCamelCase					,     _UpperCamelCase				):
               raise TypeError(
                   '''binary_search_insert() only accepts either a list, range or str'''				)

         __A      =       0
         __A      =       len(_UpperCamelCase				) - 1

         while low <= high:
               __A      =       (low + high) // 2
               if array[mid] == index:
                     # If the item already exists in the array,
                     # insert it after the existing item
                     array.insert(mid + 1					,     _UpperCamelCase				)
                     return array
               elif array[mid] < index:
                     __A      =       mid + 1
               else:
                     __A      =       mid - 1

        # If the item doesn't exist in the array, insert it at the appropriate position
         array.insert(_UpperCamelCase					,     _UpperCamelCase				)
         return array




   def _lowerCAmelCase   (self			:Union[str, Any]					,     _UpperCamelCase			:int					,     _UpperCamelCase			:int				)->      None:
         # Remove previous index
         if index in self.indexmap:
               __A      =       self.indexmap[index]
               if len(self.numbermap[n]				) == 1:
                     del self.numbermap[n]
               else:
                     __A      =       self.binary_search_delete(self.numbermap[n]					,     _UpperCamelCase				)

        # Set new index
         __A      =       number

         # Number not seen before or empty so insert number value
         if number not in self.numbermap:
               __A      =       [index]

         # Here we need to perform a binary search insertion in order to insert
         # The item in the correct place
         else:
               __A      =       self.binary_search_insert(
                   self.numbermap[number]					,     _UpperCamelCase				)






   def _lowerCAmelCase   (self			:List[Any]					,     _UpperCamelCase			:int				)->      int:
         return self.numbermap.get(_UpperCamelCase					,     [-1]				)[0]


if __name__ == "__main__":
       import doctest

       doctest.testmod()





