# Open Ended 3 - Gradient Descent Optimization
import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return x**2 + 4*x + 4

def df(x):
    return 2*x + 4

x = 8
learning_rate = 0.1
iterations = 20

x_values = [x]

for i in range(iterations):
    x = x - learning_rate * df(x)
    x_values.append(x)

x_range = np.linspace(-10, 10, 100)
y_range = f(x_range)

plt.plot(x_range, y_range, color='black', label='Function Curve')

plt.scatter(x_values,
            [f(i) for i in x_values],
            color='red',
            label='Gradient Descent Steps')

plt.plot(x_values,
         [f(i) for i in x_values],
         color='green',
         linestyle='--',
         label='Optimization Path')

plt.xlabel("x")
plt.ylabel("f(x)")
plt.title("Gradient Descent Optimization")
plt.legend()
plt.show()

print("Local minimum found at x =", x)
