
"""simple docstring"""







import bisect
import copy
from collections import defaultdict

import numpy as np
from torch.utils.data import BatchSampler, Sampler

from utils import logger




def 			A_			(					lowercase						, lowercase      )     ->							Tuple:


     """simple docstring"""







     UpperCAmelCase_						:    Optional[Any]    					=  copy.deepcopy(_UpperCAmelCase      )
     UpperCAmelCase_						:    List[Any]    					=  sorted(_UpperCAmelCase      )
     UpperCAmelCase_						:    Optional[Any]    					=  [bisect.bisect_right(_UpperCAmelCase						, _UpperCAmelCase      ) for y in x]
     return quantized




def 			A_			(					lowercase						, lowercase=0      )     ->							Dict:


     """simple docstring"""







     UpperCAmelCase_						:    Tuple    					=  np.arange(start=3						, stop=_UpperCAmelCase						, step=4      ).tolist() if k > 0 else [10]
     UpperCAmelCase_						:    Optional[Any]    					=  _quantize(_UpperCAmelCase						, _UpperCAmelCase      )
     # count number of elements per group
     UpperCAmelCase_						:    int    					=  np.unique(_UpperCAmelCase						, return_counts=_UpperCAmelCase      )[1]
     UpperCAmelCase_						:    Union[str, Any]    					=  [0] + bins + [np.inf]
     logger.info("""Using {} as bins for aspect lengths quantization""".format(_UpperCAmelCase      )      )
     logger.info("""Count of instances per bin: {}""".format(_UpperCAmelCase      )      )
     return groups



class 		UpperCAmelCase_	(lowerCamelCase_						):
       """simple docstring"""




       def __init__( self       : Union[str, Any]     ,   a_       : Tuple     ,   a_       : List[str]     ,   a_       : int )->					List[str]:



            """simple docstring"""

            if not isinstance(UpperCAmelCase_     ,   UpperCAmelCase_ ):
                 raise ValueError(
                     """sampler should be an instance of torch.utils.data.Sampler, but got sampler={}""".format(UpperCAmelCase_ ) )
            UpperCAmelCase_						:    Optional[int]    					=  sampler
            UpperCAmelCase_						:    List[str]    					=  group_ids
            UpperCAmelCase_						:    List[Any]    					=  batch_size




       def __iter__( self       : Union[str, Any] )->					List[Any]:



            """simple docstring"""

            UpperCAmelCase_						:    Dict    					=  defaultdict(UpperCAmelCase_ )
            UpperCAmelCase_						:    List[str]    					=  defaultdict(UpperCAmelCase_ )

            UpperCAmelCase_						:    Optional[Any]    					=  0
            for idx in self.sampler:
                 UpperCAmelCase_						:    str    					=  self.group_ids[idx]
                 buffer_per_group[group_id].append(UpperCAmelCase_ )
                 samples_per_group[group_id].append(UpperCAmelCase_ )
                 if len(buffer_per_group[group_id] ) == self.batch_size:
                      yield buffer_per_group[group_id]  # TODO
                      num_batches += 1
                      del buffer_per_group[group_id]
                 assert len(buffer_per_group[group_id] ) < self.batch_size

            # now we have run out of elements that satisfy
            # the group criteria, let's return the remaining
            # elements so that the size of the sampler is
            # deterministic
            UpperCAmelCase_						:    List[Any]    					=  len(self )
            UpperCAmelCase_						:    Tuple    					=  expected_num_batches - num_batches
            if num_remaining > 0:
                 # for the remaining batches, group the batches by similar lengths
                 UpperCAmelCase_						:    Tuple    					=  []
                 for group_id, idxs in sorted(buffer_per_group.items()     ,   key=lambda a_ : x[0] ):
                      batch_idx.extend(UpperCAmelCase_ )
                      if len(UpperCAmelCase_ ) >= self.batch_size:
                           yield batch_idx[: self.batch_size]
                           UpperCAmelCase_						:    Tuple    					=  batch_idx[self.batch_size :]
                           num_remaining -= 1
                 if len(UpperCAmelCase_ ) > 0:
                      yield batch_idx
                      num_remaining -= 1
            assert num_remaining == 0






       def __len__( self       : Optional[int] )->					Optional[Any]:



            """simple docstring"""

            return (len(self.sampler ) + self.batch_size - 1) // self.batch_size



"""simple docstring"""







from math import radians as angle_to_radians
from math import sin

# Acceleration Constant on Earth (unit m/s^2)
lowercase_						    =					9.8_0665




def 			A_			(					lowercase						, lowercase      )     ->							None:


     """simple docstring"""







     if not isinstance(lowercase						, (int, float)      ):
          raise TypeError("""Invalid velocity. Should be a positive number."""      )

     if not isinstance(lowercase						, (int, float)      ):
          raise TypeError("""Invalid angle. Range is 1-90 degrees."""      )

     # Ensure valid angle
     if angle > 90 or angle < 1:
          raise ValueError("""Invalid angle. Range is 1-90 degrees."""      )

     # Ensure valid velocity
     if init_velocity < 0:
          raise ValueError("""Invalid velocity. Should be a positive number."""      )




def 			A_			(					lowercase						, lowercase      )     ->							float:


     """simple docstring"""







     check_args(lowercase						, lowercase      )
     UpperCAmelCase_						:    Any    					=  angle_to_radians(2 * angle      )
     return round(init_velocity**2 * sin(lowercase      ) / g						, 2      )




def 			A_			(					lowercase						, lowercase      )     ->							float:


     """simple docstring"""







     check_args(lowercase						, lowercase      )
     UpperCAmelCase_						:    Union[str, Any]    					=  angle_to_radians(lowercase      )
     return round(init_velocity**2 * sin(lowercase      ) ** 2 / (2 * g)						, 2      )




def 			A_			(					lowercase						, lowercase      )     ->							float:


     """simple docstring"""







     check_args(lowercase						, lowercase      )
     UpperCAmelCase_						:    Optional[int]    					=  angle_to_radians(lowercase      )
     return round(2 * init_velocity * sin(lowercase      ) / g						, 2      )




def 			A_			(					)     ->							None:


     """simple docstring"""







     UpperCAmelCase_					,UpperCAmelCase_						:    Optional[int]    					=  25, 20
     assert horizontal_distance(lowercase						, lowercase      ) == 40.97
     assert max_height(lowercase						, lowercase      ) == 3.73
     assert total_time(lowercase						, lowercase      ) == 1.74


if __name__ == "__main__":
       from doctest import testmod

       testmod()

       # Get input from user
       lowercase_						    =					float(input("Initial Velocity: ").strip())

       # Get input from user
       lowercase_						    =					float(input("angle: ").strip())

       # Print results
       print()
       print("Results: ")
       print(f"""Horizontal Distance: {horizontal_distance(init_vel, angle)!s} [m]""")
       print(f"""Maximum Height: {max_height(init_vel, angle)!s} [m]""")
       print(f"""Total Time: {total_time(init_vel, angle)!s} [s]""")

