import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
# Функция варианта 16
def f(x):
x1, x2 = x
return x1**2 + x2**2 + 1.1 * x1 * x2 + x1 - x2 + 1.1
# Аналитический градиент
def grad(x):
x1, x2 = x
df_dx1 = 2*x1 + 1.1*x2 + 1
df_dx2 = 2*x2 + 1.1*x1 - 1
return np.array([df_dx1, df_dx2])
# Начальное приближение (вариант 16)
x0 = np.array([1.0, 0.0])
# Поиск минимумов двумя методами
res_nm = minimize(f, x0, method='Nelder-Mead')
res_bfgs = minimize(f, x0, jac=grad, method='BFGS')
min_nm = res_nm.x
min_bfgs = res_bfgs.x
print("Точки минимумов (вариант 16):")
print(f"Nelder-Mead: ({min_nm[0]:.8f}, {min_nm[1]:.8f}), f = {res_nm.fun:.10f}")
print(f"BFGS: ({min_bfgs[0]:.8f}, {min_bfgs[1]:.8f}), f = {res_bfgs.fun:.10f}")
print(f"Разница между точками: ({abs(min_nm[0]-min_bfgs[0]):.2e}, {abs(min_nm[1]-min_bfgs[1]):.2e})")
# Сетка для графиков (диапазон подобран, чтобы был виден минимум)
x1_vals = np.linspace(-2.5, 2.5, 50)
x2_vals = np.linspace(-2.5, 2.5, 50)
X1, X2 = np.meshgrid(x1_vals, x2_vals)
Z = X1**2 + X2**2 + 1.1 * X1 * X2 + X1 - X2 + 1.1
# Численный градиент для поля направлений (стрелки)
py, px = np.gradient(Z)
# Создание фигуры с двумя подграфиками
fig = plt.figure(figsize=(10, 12))
# --- 3D поверхность ---
ax1 = fig.add_subplot(2, 1, 1, projection='3d')
surf = ax1.plot_surface(X1, X2, Z, cmap='viridis', alpha=0.8, edgecolor='none')
# Точки минимумов (оба метода дают практически одинаковый результат)
ax1.scatter(min_nm[0], min_nm[1], f(min_nm), color='red', s=80, label='Nelder-Mead', zorder=5)
ax1.scatter(min_bfgs[0], min_bfgs[1], f(min_bfgs), color='blue', s=80, label='BFGS', zorder=5)
ax1.set_xlabel('x₁')
ax1.set_ylabel('x₂')
ax1.set_zlabel('f(x₁, x₂)')
ax1.set_title('3D поверхность функции (вариант 16)')
ax1.legend()
fig.colorbar(surf, ax=ax1, shrink=0.6, aspect=20)
# --- Линии уровня и поле градиента ---
ax2 = fig.add_subplot(2, 1, 2)
contour = ax2.contour(X1, X2, Z, levels=25, cmap='viridis', linewidths=0.8)
ax2.clabel(contour, inline=True, fontsize=8, fmt='%0.2f')
# Векторное поле градиента (разреженное, для наглядности)
stride = 3
ax2.quiver(X1[::stride, ::stride], X2[::stride, ::stride],
px[::stride, ::stride], py[::stride, ::stride],
color='black', alpha=0.4, scale=25, width=0.005)
# Нанесение точек минимумов
ax2.scatter(min_nm[0], min_nm[1], color='red', s=120, zorder=5,
label=f'Nelder-Mead ({min_nm[0]:.4f}, {min_nm[1]:.4f})', edgecolors='black')
ax2.scatter(min_bfgs[0], min_bfgs[1], color='blue', s=120, zorder=5,
label=f'BFGS ({min_bfgs[0]:.4f}, {min_bfgs[1]:.4f})', edgecolors='black', marker='s')
# Подписи точек
ax2.annotate('NM', (min_nm[0], min_nm[1]),
xytext=(5, 5), textcoords='offset points', fontsize=9, color='red')
ax2.annotate('BFGS', (min_bfgs[0], min_bfgs[1]),
xytext=(5, -8), textcoords='offset points', fontsize=9, color='blue')
ax2.set_xlabel('x₁')
ax2.set_ylabel('x₂')
ax2.set_title('Линии равного уровня и поле градиента')
ax2.legend(loc='upper right')
ax2.grid(True, alpha=0.3)
ax2.axis('equal')
plt.tight_layout()
plt.show()