# Программа 3: Поверхность, линии уровня, стрелки градиентов, точки минимумов (вариант 16)
import numpy as np
import matplotlib.pyplot as plt
# ----- Функция и её аналитический градиент -----
def f(x):
return x[0]**2 + x[1]**2 + 1.1*x[0]*x[1] + x[0] - x[1] + 1.1
def grad(x):
return np.array([2*x[0] + 1.1*x[1] + 1, 2*x[1] + 1.1*x[0] - 1])
# ----- Точки минимума, полученные из первых двух программ (результат с консоли) -----
x_nm = np.array([-1.1111369, 1.11114087]) # из scipy Nelder-Mead
x_gd = np.array([-1.11111044, 1.11111044]) # из вашего градиентного метода
# (можно взять точное аналитическое: [-1.11111111, 1.11111111], но оставим ваши значения)
# ----- Сетка для графиков -----
x_range = np.linspace(-2.5, 2.5, 60) # чуть шире, чтобы был виден минимум
X, Y = np.meshgrid(x_range, x_range)
Z = X**2 + Y**2 + 1.1*X*Y + X - Y + 1.1
# ----- Рисуем два подграфика: 3D поверхность и контур со стрелками -----
fig = plt.figure(figsize=(14, 6))
# --- 1) 3D поверхность (проекция '3d' работает без дополнительных импортов в новых версиях matplotlib) ---
ax1 = fig.add_subplot(1, 2, 1, projection='3d')
surf = ax1.plot_surface(X, Y, Z, cmap='viridis', edgecolor='none', alpha=0.9)
ax1.scatter(x_nm[0], x_nm[1], f(x_nm), color='red', s=70, label='Нелдер-Мид')
ax1.scatter(x_gd[0], x_gd[1], f(x_gd), color='blue', marker='^', s=70, label='Градиентный')
ax1.set_xlabel('x1')
ax1.set_ylabel('x2')
ax1.set_zlabel('f(x1, x2)')
ax1.set_title('Поверхность функции')
ax1.legend()
fig.colorbar(surf, ax=ax1, shrink=0.5, aspect=10)
# --- 2) Контур + линии уровня + стрелки градиентов ---
ax2 = fig.add_subplot(1, 2, 2)
contour = ax2.contour(X, Y, Z, levels=20, cmap='viridis')
ax2.clabel(contour, inline=True, fontsize=8)
ax2.set_title('Линии уровня и градиенты')
# Стрелки градиентов (редкая сетка)
Xq, Yq = np.meshgrid(np.linspace(-2.5, 2.5, 12), np.linspace(-2.5, 2.5, 12))
U, V = np.zeros_like(Xq), np.zeros_like(Yq)
for i in range(Xq.shape[0]):
for j in range(Xq.shape[1]):
g = grad([Xq[i,j], Yq[i,j]])
U[i,j], V[i,j] = g[0], g[1]
# Нормируем стрелки для наглядности (чтобы они не были огромными)
norm = np.sqrt(U**2 + V**2) + 1e-8
U /= norm
V /= norm
ax2.quiver(Xq, Yq, U, V, alpha=0.6, width=0.004, scale=25)
# Наносим две точки минимума
ax2.plot(x_nm[0], x_nm[1], 'ro', markersize=8, label='Нелдер-Мид')
ax2.plot(x_gd[0], x_gd[1], 'b^', markersize=8, label='Градиентный')
ax2.set_xlabel('x1')
ax2.set_ylabel('x2')
ax2.legend()
ax2.grid(alpha=0.3)
ax2.axis('equal')
plt.tight_layout()
plt.show() # ОБЯЗАТЕЛЬНО: без этого окно не появится