%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import scipy.optimize as opt

"""
Explanation: Optimization Exercise 1
Imports
End of explanation
"""


# YOUR CODE HERE
def hat(x, a, b):
    return (-a * x**2) + (b * x**4)

assert hat(0.0, 1.0, 1.0)==0.0
assert hat(0.0, 1.0, 1.0)==0.0
assert hat(1.0, 10.0, 1.0)==-9.0

"""
Explanation: Hat potential
The following potential is often used in Physics and other fields to describe symmetry breaking and is often known as the "hat potential":
$$ V(x) = -a x^2 + b x^4 $$
Write a function hat(x,a,b) that returns the value of this function:
End of explanation
"""


a = 5.0
b = 1.0
x = np.linspace(-3, 3, 100)
plt.plot(x, hat(x, a, b))

# YOUR CODE HERE
raise NotImplementedError()

assert True # leave this to grade the plot

"""
Explanation: Plot this function over the range $x\in\left[-3,3\right]$ with $b=1.0$ and $a=5.0$:
End of explanation
"""


# YOUR CODE HERE
#specifies a number of divisions which the function will look for a minimum on each.
#more divisions = more accurate
def minima(divisions, function, a, b):
    critpoints = []
    for n in range(0, divisions):
        sectionx = np.linspace(n*(6/divisions) - 3, (n+1)*(6/divisions) - 3, 100)
        sectiony = function(np.linspace(n*(6/divisions) - 3, (n+1)*(6/divisions) - 3, 100), a, b)
        #make sure the minimum is not on the ends
        if np.amin(sectiony) != sectiony[0] and np.amin(sectiony) != sectiony[-1]:
            minpt = np.argmin(sectiony)
            critpoints.append(sectionx[minpt])
            
    return critpoints
        

minpts = minima(100, hat, a, b)

x = np.linspace(-3, 3, 100)
plt.plot(x, hat(x, a, b))
plt.scatter(minpts[0], hat(minpts[0], a, b), color = "r")
plt.scatter(minpts[1], hat(minpts[1], a, b), color = "r")
plt.xlabel("X")
plt.ylabel("V(x)")
print("Minimums: ", minpts)

assert True # leave this for grading the plot

"""
Explanation: Write code that finds the two local minima of this function for $b=1.0$ and $a=5.0$.

Use scipy.optimize.minimize to find the minima. You will have to think carefully about how to get this function to find both minima.
Print the x values of the minima.
Plot the function as a blue line.
On the same axes, show the minima as red circles.
Customize your visualization to make it beatiful and effective.
End of explanation
"""


