diff --git a/exercise_1.py b/exercise_1.py index f2e6912..7ce77e2 100644 --- a/exercise_1.py +++ b/exercise_1.py @@ -1,39 +1,40 @@ """ EXERCISE 1 Find the minimizer of a scalar function of 2 variables. """ import numpy as np import plot import optimizer # The function to be minimized def f(x): # x can be an array of coordinate [x1, y1] A = np.array([[4., 0.], [1., 3.]]) b = np.array([0., 1.]) - # f(x)=xAX-bx - return np.einsum('i,i->', x, A @ x.transpose()) - np.einsum('i,i->', x, b) + # f(x)=xAx-bx + Ax = np.einsum('ik,k->i', A, x) + return np.einsum('i,i->', x, Ax) - np.einsum('i,i->', x, b) # methods : e.g. "CG" or "BFGS" -method = "CG" +method = 'BFGS' -# initial solution : +# initial guess : x0 = np.array([3., 3.]) # exit tolerance for the method : -toll = 10 ^ -9 +tol = 1e-9 # call the optimizer function : -minimizer, resultINFO, points = optimizer.optimizer(f, method, x0, toll) +minimizer, resultINFO, points = optimizer.optimizer(f, method, x0, tol) # Print the results : -print("__________________________________________________________________________________") +print("_________________________________________") print("Find the minimizer of a scalar function of 2 variables using the method: "+method) print(resultINFO.message) -print(" coordinates x,y : "+repr(resultINFO.x)) +print(" solution x,y : "+repr(resultINFO.x)) print(" number of iterations : "+repr(resultINFO.nit)) print(" value of the function at the minimizer : "+repr(f(resultINFO.x))) plot.plotminimizer(f, points, method) diff --git a/optimizer.py b/optimizer.py index 41364e5..5b07fe4 100644 --- a/optimizer.py +++ b/optimizer.py @@ -1,55 +1,55 @@ import scipy.optimize import numpy as np -def optimizer(f, method, x0, toll): +def optimizer(f, method, x0, tol): """ Find the minimizer of a scalar function of 2 variables. Parameters ---------- f : scalar function of a vector of 2 variables. method : strig e.g. "CG" for Conjigate gradient, "BFGS" for quasi-Newton method of Broyden, Fletcher, Goldfarb, and Shanno x0 : ndarray array of 2 elements with the initial guess of the minimizer. - toll : float + tol : float exit tollerance for the method e.g. 10^-8 Returns ------- minimizer : ndarray The solution of the optimization resultINFO: OptimizeResult object Important attributes are: x: ndarray - The solution of the optimization. success: bool - Whether or not the optimizer exited successfully. message: str - Description of the cause of the termination. nit: int - Number of iterations performed by the optimizer. points : numpy ndarray - 2-D array of shape (number of iterations, 2) containing the successive approximations + 2-D array of shape (number of iterations + 1, 2) containing the successive approximations for the solution obtained with the iterations """ points = [[x0[0], x0[1]]] # Define function to store iteration points when calling scipy.optimize.minimize def store_iterations(x): points.append([x[0], x[1]]) # Compute optimizer and store iterations by using callback resultINFO = scipy.optimize.minimize(f, x0, method=method, callback=store_iterations, - options={'gtol': 10^-9}) + options={'gtol': tol}) minimizer = resultINFO.x return minimizer, resultINFO, np.asarray(points) diff --git a/plot.py b/plot.py index e3c1521..813817b 100644 --- a/plot.py +++ b/plot.py @@ -1,67 +1,67 @@ import numpy as np import matplotlib.pyplot as plt from matplotlib import cm -from mpl_toolkits.mplot3d import Axes3D -from matplotlib.ticker import LinearLocator, FormatStrFormatter -import itertools def plotminimizer(f,points,method): """ Plot the function f and the successive approximations of the minimizer Parameters ---------- f : scalar function of a vector of 2 variables. points : numpy ndarray - 2-D array of shape (number of iterations, 2) containing the successive approximations + 2-D array of shape (number of iterations + 1, 2) containing the successive approximations for the solution obtained with the iterations method : strig e.g. "CG" for Conjigate gradient, "BFGS" for quasi-Newton method of Broyden, Fletcher, Goldfarb, and Shanno """ fig = plt.figure(1) ax = fig.gca(projection='3d') # Remove grid lines (dotted lines inside plot) ax.grid(False) - # plotting points pair - for p in points: - ax.scatter(p[0], p[1], f(p), zdir='z', c='r') - # plotting lines for each point pair - for a in range(len(points)-1): - x = np.linspace(points[a][0], points[a+1][0], 100) - y = np.linspace(points[a][1], points[a+1][1], 100) - z = np.linspace(f(points[a]), f(points[a+1]), 100) - ax.plot(x, y, z,color="red",dashes=[2, 2]) + + + # evaluating the functions at the points + fp = np.zeros(points.shape[0]) + i = 0 + for p in points: + fp[i] = f(p) + i = i + 1 + + # plotting points and lines for each point pair + ax.plot(points[:,0], points[:,1], fp, 'ro--', linewidth=2, markersize=5) + # Plot the surface - X = np.arange(-3, 3, 0.15) - Y = np.arange(-3, 3, 0.15) + X = np.linspace(-3, 3, 50) + Y = np.linspace(-3, 3, 50) X, Y = np.meshgrid(X, Y) Z = np.zeros((X.shape[0], X.shape[1])) for i in range(X.shape[0]): for j in range(X.shape[1]): Z[i, j] = f(np.array([X[i, j], Y[i, j]])) ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,linewidth=0, antialiased=False, alpha=0.2) # Plot the contour lines ax.contour(X, Y, Z, colors="black") # Add title and axis names - plt.title('Convergence to the solution of the '+method+' method') + plt.title('Convergence of '+method+' method') plt.xlabel('x') plt.ylabel('y') plt.show()