# using GRADIENT ASCENT to find extrema values

# t_flight = 2*u*sin( theta ) / g
# R = u*cos( theta ) * 2*u*sin( theta ) / g = u**2 * 2 *theta / g

'''
Use gradient ascent to find the angle at which the projectile has maximum range for a fixed velocity, 25m/s
'''

import math
from sympy import Derivative, Symbol, sin

def grad_ascent( x0, f1x, x ):
	epsilon = 1e-6
	step_size = 1e-4
	x_old = x0
	x_new = x_old + step_size * f1x.subs( { x: x_old } ).evalf()

	while( abs( x_old - x_new ) > epsilon ):
	   x_old = x_new
	   x_new = x_old + step_size * f1x.subs( { x: x_old } ).evalf()

	return x_new

def find_max_theta( R, theta ):
	# Calculate the first derivative
	R1theta = Derivative( R, theta ).doit()
	theta0 = 1e-3
	theta_max = grad_ascent( theta0, R1theta, theta )

	return theta_max

if __name__ == '__main__':

	g = 9.8
	# Assume initial velocity
	u = 25
	# Expression for the range
	theta = Symbol( 'theta' )
	R = u ** 2 * sin( 2 * theta ) / g

	theta_max = find_max_theta( R, theta )

	print( 'Theta: {0}'.format( math.degrees( theta_max ) ) )
	print( 'Maximum Range: {0}'.format( R.subs( { theta: theta_max } ) ) )
