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()
Last Updated on 2023-01-16 by gantovnik

Recent Comments