ex338.py
import numpy as np import math import matplotlib.pyplot as plt import warnings warnings.filterwarnings('ignore') def my_f(x): #$f(x_1, x_2) = e^{x_1+3x_2-0.1}+e^{x_1-3x_2-0.1}+e^{-x_1-0.1}$ x1 = x[0, 0] x2 = x[1, 0] return math.exp(x1+3*x2-0.1)+math.exp(x1-3*x2-0.1)+math.exp(-x1-0.1) def my_gradient_f(x): #$\nabla f(x_1, x_2)$ x1 = x[0, 0] x2 = x[1, 0] gradient_1=1*math.exp(x1+3*x2-0.1)+1*math.exp(x1-3*x2-0.1)-math.exp(-x1-0.1) gradient_2=3*math.exp(x1+3*x2-0.1)-3*math.exp(x1-3*x2-0.1) return np.array([[gradient_1], [gradient_2]]) def my_hessian_f(x): #$\nabla^2 f(x_1, x_2)$ x1 = x[0, 0] x2 = x[1, 0] x11 = math.exp(x1 + 3 * x2 - 0.1) + math.exp(x1 - 3 * x2 - 0.1) + math.exp(-x1 - 0.1) x12 = 3 * math.exp(x1 + 3 * x2 - 0.1) - 3 * math.exp(x1 - 3 * x2 - 0.1) x21 = 3 * math.exp(x1 + 3 * x2 - 0.1) - 3 * math.exp(x1 - 3 * x2 - 0.1) x22 = 9 * math.exp(x1 + 3 * x2 - 0.1) + 9 * math.exp(x1 - 3 * x2 - 0.1) return np.array([[x11, x12], [x21, x22]]) def my_newton_step_decrement(x): # calculate newton step $\Delta x_{nt} = -[\nabla^2 f(x)]^{-1}\nabla f(x) $ gradient = my_gradient_f(x) hessian = my_hessian_f(x) hessian_inv = np.linalg.inv(hessian) x_nt = -1 * hessian_inv @ gradient decrement = -1 * gradient.T @ x_nt return x_nt, decrement.item() def backtracking_line_search(f, df, x, delta_x, alpha, beta): # backtracking line search t = 1 while f(x + delta_x * t) > f(x) + alpha * t * ((df(x).T @ delta_x).item()): t = beta * t return t def plot_ellipse_by_matrix(P, N): # Plot a 2D ellipse according to the $X^TPX=1$ W, V = np.linalg.eig(P) a = 1 / np.sqrt(W[0]) b = 1 / np.sqrt(W[1]) n_p = N y = np.zeros((n_p + 1, 2, 1), dtype='complex_') for i in range(n_p + 1): omega = i * 2 * np.pi / n_p y[i, 0, 0] = a * np.cos(omega) y[i, 1, 0] = b * np.sin(omega) x = np.zeros((n_p + 1, 2, 1), dtype='complex_') for i in range(n_p+1): x[i] = V @ y[i] return x def plot_convergence_Newton_method_non_quadratic_problem(ax1, ax2): # Plot the convergence of the Newton's method on the non-quadratic problem min_x1 = -6 max_x1 = 5 min_x2 = -4 max_x2 = 4 delta = 0.1 x = np.arange(min_x1, max_x1, delta) y = np.arange(min_x2, max_x2, delta) X, Y = np.meshgrid(x, y) Z = np.zeros(X.shape) f_min = my_f(np.array([[0.5 * math.log(0.5)], [0]])) for x1_i in range(len(x)): for x2_i in range(len(y)): x1 = x[x1_i] x2 = y[x2_i] Z[x2_i][x1_i] = my_f(np.array([[x1], [x2]])) levels = np.arange(0, 200, 1) CS = ax1.contour(X, Y, Z, linestyles='dashed', levels=levels, vmin=0,vmax=100) ax1.clabel(CS, fontsize=4, inline=True) alpha = 0.1 beta = 0.7 x0 = np.array([[-2], [2]]) x = x0 epsilon = 1e-10 x_nt, decrement = my_newton_step_decrement(x) x_points = [x] fx = [my_f(x)] iter = 0 while decrement/2 > epsilon: if iter < 4: hessian = my_hessian_f(x) v = plot_ellipse_by_matrix(hessian, 100) if iter == 0: ax1.plot(v[:,0, 0] + x[0, 0], v[:, 1, 0] + x[1, 0],color='red', label=r'ellipsoid {$x^{(k)}$+x||$x^T\nabla^2f(x) x$|=1}') else: ax1.plot(v[:, 0, 0] + x[0, 0], v[:, 1, 0] + x[1, 0],color='red') print('Info: decrement = {}, fx={}'.format(decrement, fx[-1])) t = backtracking_line_search(my_f, my_gradient_f, x, x_nt, alpha, beta) x_next = x + t * x_nt x = x_next x_nt, decrement = my_newton_step_decrement(x) x_points.append(x) fx.append(my_f(x)) iter = iter + 1 x_points_arr = np.array(x_points) ax1.plot(x_points_arr[:, 0], x_points_arr[:, 1], color='black',marker='o', label='Newton descent') ax1.set_aspect('auto', adjustable='box') ax1.legend() ax1.set_xlabel(r'$x_1$') ax1.set_ylabel(r'$x_2$') ax1.set_title('f(x)') ax1.grid() ax2.semilogy(np.array(fx) - f_min, marker='o', label=r"Newton's method") ax2.grid() ax2.legend() ax2.set_xlabel('iteration') ax2.set_title(r'$f(x)-p^*$') if __name__ == "__main__": plt.figure(figsize=(16, 8)) ax1 = plt.subplot(1, 2, 1) ax2 = plt.subplot(1, 2, 2) plot_convergence_Newton_method_non_quadratic_problem(ax1, ax2) plt.savefig('ex338.png', dpi=100) plt.show()
Recent Comments