



"""simple docstring"""
from typing import Any

import numpy as np
class     lowerCamelCase  :






					'''simple docstring'''





					def __init__(	self:							List[Any]						,					snake_case:							np.ndarray						,					snake_case:							int						)       ->     None:
											# Check if RHS is negative
											if np.any(tableau[:, -1]						,					where=tableau[:, -1] < 0						):
																	raise ValueError("""RHS must be > 0"""						)

											snake_case_			:str						=      tableau
											snake_case_,	snake_case_			:Any						=      tableau.shape

											# Number of decision variables x1, x2, x3...
											snake_case_			:Optional[int]						=      n_vars

											# Number of artificial variables to be minimised
											snake_case_			:Dict						=      len(np.where(tableau[self.n_vars : -1] == -1						)[0]						)

											# 2 if there are >= or == constraints (nonstandard), 1 otherwise (std)
											snake_case_			:Dict						=      (self.n_art_vars > 0) + 1

											# Number of slack variables added to make inequalities into equalities
											snake_case_			:int						=      self.n_rows - self.n_stages

											# Objectives for each stage
											snake_case_			:List[Any]						=      ["""max"""]

											# In two stage simplex, first minimise then maximise
											if self.n_art_vars:
																	self.objectives.append("""min"""						)

											snake_case_			:List[Any]						=      [""""""]

											# Index of current pivot row and column
											snake_case_			:Union[str, Any]						=      None
											snake_case_			:List[Any]						=      None

											# Does objective row only contain (non)-negative values?
											snake_case_			:List[str]						=      False






					@staticmethod
					def        lowerCAmelCase_    (	*snake_case:							int						)       ->     list[str]:
											if len(snake_case						) != 3:
																	raise ValueError("""Must provide n_vars, n_slack, and n_art_vars"""						)

											if not all(x >= 0 and isinstance(snake_case						,					snake_case						) for x in args						):
																	raise ValueError("""All arguments must be non-negative integers"""						)

											# decision | slack | artificial
											snake_case_			:List[Any]						=      ["""x""", """s""", """a"""]
											snake_case_			:Tuple						=      []
											for i in range(3						):
																	for j in range(args[i]						):
																							titles.append(string_starts[i] + str(j + 1						)						)
											titles.append("""RHS"""						)
											return titles






					def        lowerCAmelCase_    (	self:							List[Any]						,					snake_case:							np.ndarray						)       ->     tuple[Any, Any]:
											snake_case_			:Any						=      self.objectives[-1]

											# Find entries of highest magnitude in objective rows
											snake_case_			:List[Any]						=      (objective == """min""") - (objective == """max""")
											snake_case_			:Any						=      np.argmax(sign * tableau[0, : self.n_vars]						)

											# Choice is only valid if below 0 for maximise, and above for minimise
											if sign * self.tableau[0, col_idx] <= 0:
																	snake_case_			:Union[str, Any]						=      True
																	return 0, 0

											# Pivot row is chosen as having the lowest quotient when elements of
											# the pivot column divide the right-hand side

											# Slice excluding the objective rows
											snake_case_			:Optional[Any]						=      slice(self.n_stages						,					self.n_rows						)

											# RHS
											snake_case_			:List[str]						=      tableau[s, -1]

											# Elements of pivot column within slice
											snake_case_			:Optional[int]						=      tableau[s, col_idx]

											# Array filled with nans
											snake_case_			:Union[str, Any]						=      np.full(self.n_rows - self.n_stages						,					np.nan						)

											# If element in pivot column is greater than zeron_stages, return
											# quotient or nan otherwise
											snake_case_			:int						=      np.divide(snake_case						,					snake_case						,					out=snake_case						,					where=divisor > 0						)

											# Arg of minimum quotient excluding the nan values. n_stages is added
											# to compensate for earlier exclusion of objective columns
											snake_case_			:Union[str, Any]						=      np.nanargmin(snake_case						) + self.n_stages
											return row_idx, col_idx






					def        lowerCAmelCase_    (	self:							Optional[Any]						,					snake_case:							np.ndarray						,					snake_case:							int						,					snake_case:							int						)       ->     np.ndarray:
											snake_case_			:Optional[Any]						=      tableau[row_idx].copy()

											snake_case_			:int						=      piv_row[col_idx]

											# Entry becomes 1
											piv_row *= 1 / piv_val

											# Variable in pivot column becomes basic, ie the only non-zero entry
											for idx, coeff in enumerate(tableau[:, col_idx]						):
																	tableau[idx] += -coeff * piv_row
											snake_case_			:Dict						=      piv_row
											return tableau






					def        lowerCAmelCase_    (	self:							int						,					snake_case:							np.ndarray						)       ->     np.ndarray:
											self.objectives.pop()

											if not self.objectives:
																	return tableau

											# Slice containing ids for artificial columns
											snake_case_			:int						=      slice(-self.n_art_vars - 1						,					-1						)

											# Delete the artificial variable columns
											snake_case_			:str						=      np.delete(snake_case						,					snake_case						,					axis=1						)

											# Delete the objective row of the first stage
											snake_case_			:Union[str, Any]						=      np.delete(snake_case						,					0						,					axis=0						)

											snake_case_			:Union[str, Any]						=      1
											self.n_rows -= 1
											snake_case_			:Dict						=      0
											snake_case_			:Tuple						=      False
											return tableau






					def        lowerCAmelCase_    (	self:							List[str]						)       ->     dict[Any, Any]:
											# Stop simplex algorithm from cycling.
											for _ in range(100						):
																	# Completion of each stage removes an objective. If both stages
																	# are complete, then no objectives are left
																	if not self.objectives:
																							snake_case_			:Dict						=      self.generate_col_titles(
																							    self.n_vars						,					self.n_slack						,					self.n_art_vars						)

																							# Find the values of each variable at optimal solution
																							return self.interpret_tableau(self.tableau						,					self.col_titles						)

																	snake_case_,	snake_case_			:int						=      self.find_pivot(self.tableau						)

																	# If there are no more negative values in objective row
																	if self.stop_iter:
																							# Delete artificial variable columns and rows. Update attributes
																							snake_case_			:Optional[int]						=      self.change_stage(self.tableau						)
																	else:
																							snake_case_			:Optional[int]						=      self.pivot(self.tableau						,					snake_case						,					snake_case						)
											return {}






					def        lowerCAmelCase_    (	self:							str						,					snake_case:							np.ndarray						,					snake_case:							list[str]						)       ->     dict[str, float]:
											snake_case_			:Tuple						=      {"""P""": abs(tableau[0, -1]						)}

											for i in range(self.n_vars						):
																	# Gives ids of nonzero entries in the ith column
																	snake_case_			:int						=      np.nonzero(tableau[:, i]						)
																	snake_case_			:List[Any]						=      len(nonzero[0]						)

																	# First entry in the nonzero ids
																	snake_case_			:int						=      nonzero[0][0]
																	snake_case_			:Any						=      tableau[nonzero_rowidx, i]

																	# If there is only one nonzero value in column, which is one
																	if n_nonzero == nonzero_val == 1:
																							snake_case_			:List[Any]						=      tableau[nonzero_rowidx, -1]
																							snake_case_			:Optional[Any]						=      rhs_val

        # Check for basic variables
											for title in col_titles:
																	# Don't add RHS or slack variables to output dict
																	if title[0] not in "R-s-a":
																							output_dict.setdefault(snake_case						,					0						)
											return output_dict


if __name__ == "__main__":
						import doctest

						doctest.testmod()





"""simple docstring"""
from math import radians as angle_to_radians
from math import sin

# Acceleration Constant on Earth (unit m/s^2)
__a     =    9.8_06_65
def        A_  (      _lowercase, _lowercase     ):







						'''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     ):







						'''simple docstring'''


						check_args(_lowercase, _lowercase     )
						snake_case_			:str						=      angle_to_radians(2 * angle     )
						return round(init_velocity**2 * sin(_lowercase     ) / g, 2     )
def        A_  (      _lowercase, _lowercase     ):







						'''simple docstring'''


						check_args(_lowercase, _lowercase     )
						snake_case_			:str						=      angle_to_radians(_lowercase     )
						return round(init_velocity**2 * sin(_lowercase     ) ** 2 / (2 * g), 2     )
def        A_  (      _lowercase, _lowercase     ):







						'''simple docstring'''


						check_args(_lowercase, _lowercase     )
						snake_case_			:Optional[int]						=      angle_to_radians(_lowercase     )
						return round(2 * init_velocity * sin(_lowercase     ) / g, 2     )
def        A_  (      ):







						'''simple docstring'''


						snake_case_,	snake_case_			:List[str]						=      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
						__a     =    float(input("Initial Velocity: ").strip())

						# Get input from user
						__a     =    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]""")
