task1
This commit is contained in:
167
task1/golden_section_search.py
Normal file
167
task1/golden_section_search.py
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# golden_section_search.py
|
||||||
|
# Метод золотого сечения для одномерной оптимизации (10 итераций)
|
||||||
|
# Условия из задачи: f(x) = sqrt(x^2 + 9) / 4 + (5 - x) / 5, X = [-3, 8]
|
||||||
|
|
||||||
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# Глобальный счётчик обращений к оракулу
|
||||||
|
oracle_calls = 0
|
||||||
|
|
||||||
|
|
||||||
|
def f(x: float) -> float:
|
||||||
|
global oracle_calls
|
||||||
|
oracle_calls += 1
|
||||||
|
return math.sqrt(x**2 + 9) / 4 + (5 - x) / 5
|
||||||
|
|
||||||
|
|
||||||
|
# Параметры
|
||||||
|
a_init = -3.0
|
||||||
|
b_init = 8.0
|
||||||
|
num_iters = 10 # ровно 10 итераций
|
||||||
|
|
||||||
|
# Константы золотого сечения
|
||||||
|
phi = (1 + math.sqrt(5)) / 2.0 # ~1.618...
|
||||||
|
r = 1 / phi # ~0.618...
|
||||||
|
c = 1 - r # ~0.382...
|
||||||
|
|
||||||
|
# Создаём папку для графиков
|
||||||
|
Path("golden_section_plots").mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
# История итераций
|
||||||
|
history = []
|
||||||
|
|
||||||
|
# Начальные значения
|
||||||
|
a = a_init
|
||||||
|
b = b_init
|
||||||
|
|
||||||
|
# Начальные точки
|
||||||
|
y = a + c * (b - a)
|
||||||
|
z = a + r * (b - a)
|
||||||
|
fy = f(y)
|
||||||
|
fz = f(z)
|
||||||
|
|
||||||
|
print("Метод золотого сечения")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
print("\nНачальное состояние:")
|
||||||
|
print(f" Интервал: [{a:.6f}, {b:.6f}], длина = {b - a:.6f}")
|
||||||
|
print(f" y = {y:.6f}, f(y) = {fy:.6f}")
|
||||||
|
print(f" z = {z:.6f}, f(z) = {fz:.6f}")
|
||||||
|
|
||||||
|
# Основной цикл
|
||||||
|
for k in range(1, num_iters + 1):
|
||||||
|
# Сохраняем состояние до обновления
|
||||||
|
history.append(
|
||||||
|
{
|
||||||
|
"iter": k,
|
||||||
|
"a": a,
|
||||||
|
"b": b,
|
||||||
|
"y": y,
|
||||||
|
"z": z,
|
||||||
|
"fy": fy,
|
||||||
|
"fz": fz,
|
||||||
|
"interval_length": b - a,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"\nИтерация {k}:")
|
||||||
|
print(f" Интервал: [{a:.6f}, {b:.6f}], длина = {b - a:.6f}")
|
||||||
|
print(f" y = {y:.6f}, f(y) = {fy:.6f}")
|
||||||
|
print(f" z = {z:.6f}, f(z) = {fz:.6f}")
|
||||||
|
|
||||||
|
# Построение графика
|
||||||
|
x_plot = np.linspace(a_init, b_init, 500)
|
||||||
|
y_plot = [f(x) for x in x_plot]
|
||||||
|
|
||||||
|
plt.figure(figsize=(10, 6))
|
||||||
|
plt.plot(x_plot, y_plot, "b-", linewidth=2, label="f(x)")
|
||||||
|
plt.axvline(
|
||||||
|
a, color="red", linestyle="--", alpha=0.7, label=f"Интервал [{a:.3f}, {b:.3f}]"
|
||||||
|
)
|
||||||
|
plt.axvline(b, color="red", linestyle="--", alpha=0.7)
|
||||||
|
plt.plot(y, fy, "go", markersize=10, label=f"y = {y:.3f}, f(y) = {fy:.4f}")
|
||||||
|
plt.plot(z, fz, "mo", markersize=10, label=f"z = {z:.3f}, f(z) = {fz:.4f}")
|
||||||
|
|
||||||
|
plt.xlabel("x", fontsize=12)
|
||||||
|
plt.ylabel("f(x)", fontsize=12)
|
||||||
|
plt.title(f"Золотое сечение - Итерация {k}", fontsize=14, fontweight="bold")
|
||||||
|
plt.legend(fontsize=10)
|
||||||
|
plt.grid(True, alpha=0.3)
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig(f"golden_section_plots/iteration_{k:02d}.png", dpi=150)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
# Обновление интервала
|
||||||
|
if fy <= fz:
|
||||||
|
print(f" f(y) <= f(z) -> новый интервал: [{a:.6f}, {z:.6f}]")
|
||||||
|
b = z
|
||||||
|
z = y
|
||||||
|
fz = fy
|
||||||
|
y = a + c * (b - a)
|
||||||
|
fy = f(y)
|
||||||
|
else:
|
||||||
|
print(f" f(y) > f(z) -> новый интервал: [{y:.6f}, {b:.6f}]")
|
||||||
|
a = y
|
||||||
|
y = z
|
||||||
|
fy = fz
|
||||||
|
z = a + r * (b - a)
|
||||||
|
fz = f(z)
|
||||||
|
|
||||||
|
# Итоговая оценка минимума
|
||||||
|
x_star = (a + b) / 2.0
|
||||||
|
f_star = f(x_star)
|
||||||
|
|
||||||
|
# Финальный график
|
||||||
|
x_plot = np.linspace(a_init, b_init, 500)
|
||||||
|
y_plot = [f(x) for x in x_plot]
|
||||||
|
|
||||||
|
plt.figure(figsize=(10, 6))
|
||||||
|
plt.plot(x_plot, y_plot, "b-", linewidth=2, label="f(x)")
|
||||||
|
plt.axvline(
|
||||||
|
a,
|
||||||
|
color="red",
|
||||||
|
linestyle="--",
|
||||||
|
alpha=0.7,
|
||||||
|
label=f"Финальный интервал [{a:.6f}, {b:.6f}]",
|
||||||
|
)
|
||||||
|
plt.axvline(b, color="red", linestyle="--", alpha=0.7)
|
||||||
|
plt.plot(
|
||||||
|
x_star,
|
||||||
|
f_star,
|
||||||
|
"r*",
|
||||||
|
markersize=20,
|
||||||
|
label=f"x* = {x_star:.6f}, f(x*) = {f_star:.6f}",
|
||||||
|
)
|
||||||
|
|
||||||
|
plt.xlabel("x", fontsize=12)
|
||||||
|
plt.ylabel("f(x)", fontsize=12)
|
||||||
|
plt.title("Золотое сечение - Финальный результат", fontsize=14, fontweight="bold")
|
||||||
|
plt.legend(fontsize=10)
|
||||||
|
plt.grid(True, alpha=0.3)
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig("golden_section_plots/final_result.png", dpi=150)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print(f"\nИтераций выполнено: {num_iters}")
|
||||||
|
print(f"x* ~= {x_star:.6f}")
|
||||||
|
print(f"f(x*) ~= {f_star:.6f}")
|
||||||
|
print(f"Длина финального интервала: {b - a:.6f}")
|
||||||
|
# print(f"\nОбращений к оракулу (вычислений функции): {oracle_calls}")
|
||||||
|
print("\nГрафики сохранены в папке 'golden_section_plots/'")
|
||||||
|
|
||||||
|
# Таблица всех итераций
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("Сводная таблица:")
|
||||||
|
print("-" * 80)
|
||||||
|
for row in history:
|
||||||
|
print(
|
||||||
|
f"Итерация {row['iter']:2d}: "
|
||||||
|
f"[{row['a']:7.4f}, {row['b']:7.4f}] (D={row['interval_length']:7.4f}), "
|
||||||
|
f"y={row['y']:7.4f} (f={row['fy']:.4f}), "
|
||||||
|
f"z={row['z']:7.4f} (f={row['fz']:.4f})"
|
||||||
|
)
|
||||||
255
task1/uniform_search.py
Normal file
255
task1/uniform_search.py
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
"""Лекция 4 (стр. 15)
|
||||||
|
|
||||||
|
Задача. Найти пару {x*, f(x*)} для целевой функции вида
|
||||||
|
f(x) = sqrt(x^2 + 9) / 4 + (5 - x) / 5
|
||||||
|
при условии, что X = [-3, 8].
|
||||||
|
Взять N = 10, eps_x = 0.05, eps_f = 0.001.
|
||||||
|
Применить метод равномерного поиска.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# Глобальный счётчик обращений к оракулу
|
||||||
|
oracle_calls = 0
|
||||||
|
|
||||||
|
|
||||||
|
def f(x: float) -> float:
|
||||||
|
global oracle_calls
|
||||||
|
oracle_calls += 1
|
||||||
|
return math.sqrt(x**2 + 9) / 4 + (5 - x) / 5
|
||||||
|
|
||||||
|
|
||||||
|
a = -3
|
||||||
|
b = 8
|
||||||
|
N = 10
|
||||||
|
eps_x = 0.05
|
||||||
|
eps_f = 0.001
|
||||||
|
|
||||||
|
"""
|
||||||
|
Количество итераций может быть найдено из условия:
|
||||||
|
(2/N)^k * (b - a) / 2 <= eps_x
|
||||||
|
"""
|
||||||
|
print("Метод равномерного поиска")
|
||||||
|
print("=" * 80)
|
||||||
|
print(
|
||||||
|
f"Расчётное количество итераций: {math.ceil(math.log(2 * eps_x / (b - a), 2 / N))}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Создаём папку для графиков
|
||||||
|
Path("uniform_search_plots").mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
# Сохраняем начальные значения для графиков
|
||||||
|
a_init = a
|
||||||
|
b_init = b
|
||||||
|
|
||||||
|
# Метод равномерного поиска
|
||||||
|
k = 0
|
||||||
|
a_k, b_k = a, b
|
||||||
|
prev_best_f = None
|
||||||
|
best_x = None
|
||||||
|
best_fx = None
|
||||||
|
history = [] # для отладки/анализа
|
||||||
|
|
||||||
|
print("\nНачальный интервал: [{:.6f}, {:.6f}]".format(a_k, b_k))
|
||||||
|
print("-" * 80)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
k += 1
|
||||||
|
# Разбиваем [a_k, b_k] на N равных частей
|
||||||
|
Delta = (b_k - a_k) / N
|
||||||
|
xs = [a_k + i * Delta for i in range(N + 1)] # включая концы
|
||||||
|
# Считаем значения в узлах x_1..x_{N-1}
|
||||||
|
vals = [f(x) for x in xs]
|
||||||
|
# Ищем минимум среди внутренних узлов (по лекции)
|
||||||
|
i_min = min(range(1, N), key=lambda i: vals[i])
|
||||||
|
x_min = xs[i_min]
|
||||||
|
fx_min = vals[i_min]
|
||||||
|
|
||||||
|
# Сжимаем интервал к соседям минимума (x_{i-1}, x_{i+1})
|
||||||
|
a_next = xs[i_min - 1]
|
||||||
|
b_next = xs[i_min + 1]
|
||||||
|
|
||||||
|
# Обновляем лучшее известное
|
||||||
|
best_x = x_min
|
||||||
|
best_fx = fx_min
|
||||||
|
|
||||||
|
# Критерии остановки (из лекции): по точности по x и стабилизации по f
|
||||||
|
Delta_next = b_next - a_next # длина нового интервала
|
||||||
|
center_next = (a_next + b_next) / 2 # удобная оценка x*
|
||||||
|
fx_center_next = f(center_next)
|
||||||
|
|
||||||
|
# По лекции можно использовать центр нового интервала как текущую оценку x*
|
||||||
|
# и/или минимальный узел — обе оценки допустимы. Здесь — центр интервала,
|
||||||
|
# чтобы гарантировать |x - x*| <= Delta_next/2.
|
||||||
|
approx_x = center_next
|
||||||
|
approx_fx = fx_center_next
|
||||||
|
|
||||||
|
if prev_best_f is None:
|
||||||
|
prev_best_f = approx_fx
|
||||||
|
|
||||||
|
# Условия остановки
|
||||||
|
stop_by_x = (Delta_next / 2) <= eps_x
|
||||||
|
stop_by_f = abs(approx_fx - prev_best_f) <= eps_f
|
||||||
|
|
||||||
|
history.append(
|
||||||
|
{
|
||||||
|
"iter": k,
|
||||||
|
"a_k": a_k,
|
||||||
|
"b_k": b_k,
|
||||||
|
"i_min": i_min,
|
||||||
|
"x_min": x_min,
|
||||||
|
"f(x_min)": fx_min,
|
||||||
|
"a_next": a_next,
|
||||||
|
"b_next": b_next,
|
||||||
|
"Delta_next/2": Delta_next / 2,
|
||||||
|
"approx_x": approx_x,
|
||||||
|
"approx_fx": approx_fx,
|
||||||
|
"xs": xs.copy(),
|
||||||
|
"vals": vals.copy(),
|
||||||
|
# "stop_by_x": stop_by_x,
|
||||||
|
# "stop_by_f": stop_by_f,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Построение графика для текущей итерации
|
||||||
|
x_plot = np.linspace(a_init, b_init, 500)
|
||||||
|
y_plot = [f(x) for x in x_plot]
|
||||||
|
|
||||||
|
plt.figure(figsize=(12, 7))
|
||||||
|
plt.plot(x_plot, y_plot, "b-", linewidth=2, label="f(x)")
|
||||||
|
|
||||||
|
# Текущий интервал
|
||||||
|
plt.axvline(a_k, color="red", linestyle="--", alpha=0.7, linewidth=1.5)
|
||||||
|
plt.axvline(b_k, color="red", linestyle="--", alpha=0.7, linewidth=1.5)
|
||||||
|
plt.axvspan(
|
||||||
|
a_k,
|
||||||
|
b_k,
|
||||||
|
alpha=0.1,
|
||||||
|
color="red",
|
||||||
|
label=f"Текущий интервал [{a_k:.3f}, {b_k:.3f}]",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Точки разбиения
|
||||||
|
plt.plot(
|
||||||
|
xs, vals, "o", color="orange", markersize=6, alpha=0.6, label="Узлы разбиения"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Минимальная точка
|
||||||
|
plt.plot(
|
||||||
|
x_min,
|
||||||
|
fx_min,
|
||||||
|
"go",
|
||||||
|
markersize=12,
|
||||||
|
label=f"Минимум: x={x_min:.4f}, f(x)={fx_min:.4f}",
|
||||||
|
zorder=5,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Следующий интервал
|
||||||
|
plt.axvspan(
|
||||||
|
a_next,
|
||||||
|
b_next,
|
||||||
|
alpha=0.15,
|
||||||
|
color="green",
|
||||||
|
label=f"Новый интервал [{a_next:.3f}, {b_next:.3f}]",
|
||||||
|
)
|
||||||
|
|
||||||
|
plt.xlabel("x", fontsize=12)
|
||||||
|
plt.ylabel("f(x)", fontsize=12)
|
||||||
|
plt.title(
|
||||||
|
f"Равномерный поиск - Итерация {k}\nN={N}, D={Delta:.4f}, D_next/2={Delta_next / 2:.4f}",
|
||||||
|
fontsize=13,
|
||||||
|
fontweight="bold",
|
||||||
|
)
|
||||||
|
plt.legend(fontsize=9, loc="best")
|
||||||
|
plt.grid(True, alpha=0.3)
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig(f"uniform_search_plots/iteration_{k:02d}.png", dpi=150)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
# Вывод информации по итерации
|
||||||
|
print(f"\nИтерация {k}:")
|
||||||
|
print(f" Интервал: [{a_k:.6f}, {b_k:.6f}], D = {Delta:.6f}")
|
||||||
|
print(f" Минимум найден в узле i={i_min}: x = {x_min:.6f}, f(x) = {fx_min:.6f}")
|
||||||
|
print(
|
||||||
|
f" Новый интервал: [{a_next:.6f}, {b_next:.6f}], D_next/2 = {Delta_next / 2:.6f}"
|
||||||
|
)
|
||||||
|
print(f" Аппроксимация: x ~= {approx_x:.6f}, f(x) ~= {approx_fx:.6f}")
|
||||||
|
print(f" Критерии: D/2 <= eps_x? {stop_by_x}, |Df| <= eps_f? {stop_by_f}")
|
||||||
|
|
||||||
|
# Переход на следующую итерацию
|
||||||
|
a_k, b_k = a_next, b_next
|
||||||
|
prev_best_f = approx_fx
|
||||||
|
|
||||||
|
if stop_by_x and stop_by_f:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Дополнительная защита: если интервал перестал уменьшаться (численная стабильность)
|
||||||
|
if Delta_next <= 1e-12:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Финальный ответ
|
||||||
|
x_star = approx_x
|
||||||
|
f_star = approx_fx
|
||||||
|
|
||||||
|
# Финальный график
|
||||||
|
x_plot = np.linspace(a_init, b_init, 500)
|
||||||
|
y_plot = [f(x) for x in x_plot]
|
||||||
|
|
||||||
|
plt.figure(figsize=(12, 7))
|
||||||
|
plt.plot(x_plot, y_plot, "b-", linewidth=2, label="f(x)")
|
||||||
|
plt.axvline(a_k, color="red", linestyle="--", alpha=0.7, linewidth=1.5)
|
||||||
|
plt.axvline(b_k, color="red", linestyle="--", alpha=0.7, linewidth=1.5)
|
||||||
|
plt.axvspan(
|
||||||
|
a_k,
|
||||||
|
b_k,
|
||||||
|
alpha=0.15,
|
||||||
|
color="red",
|
||||||
|
label=f"Финальный интервал [{a_k:.6f}, {b_k:.6f}]",
|
||||||
|
)
|
||||||
|
plt.plot(
|
||||||
|
x_star,
|
||||||
|
f_star,
|
||||||
|
"r*",
|
||||||
|
markersize=20,
|
||||||
|
label=f"x* = {x_star:.6f}, f(x*) = {f_star:.6f}",
|
||||||
|
zorder=5,
|
||||||
|
)
|
||||||
|
|
||||||
|
plt.xlabel("x", fontsize=12)
|
||||||
|
plt.ylabel("f(x)", fontsize=12)
|
||||||
|
plt.title(
|
||||||
|
f"Равномерный поиск - Финальный результат\nВыполнено итераций: {k}",
|
||||||
|
fontsize=14,
|
||||||
|
fontweight="bold",
|
||||||
|
)
|
||||||
|
plt.legend(fontsize=10, loc="best")
|
||||||
|
plt.grid(True, alpha=0.3)
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig("uniform_search_plots/final_result.png", dpi=150)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print(f"\nИтераций выполнено: {k}")
|
||||||
|
print(f"x* ~= {x_star:.6f}")
|
||||||
|
print(f"f(x*) ~= {f_star:.6f}")
|
||||||
|
print(f"Длина конечного интервала / 2 <= eps_x? {(b_k - a_k) / 2 <= eps_x}")
|
||||||
|
print(f"|Df| <= eps_f? {abs(approx_fx - prev_best_f) <= eps_f}")
|
||||||
|
# print(f"\nОбращений к оракулу (вычислений функции): {oracle_calls}")
|
||||||
|
print("\nГрафики сохранены в папке 'uniform_search_plots/'")
|
||||||
|
|
||||||
|
# При желании выведем краткую таблицу нескольких последних итераций
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("Сводная таблица:")
|
||||||
|
print("-" * 80)
|
||||||
|
for row in history:
|
||||||
|
print(
|
||||||
|
f"Итер {row['iter']:2d}: "
|
||||||
|
f"[{row['a_k']:7.4f}, {row['b_k']:7.4f}] -> "
|
||||||
|
f"x_min={row['x_min']:7.4f} (f={row['f(x_min)']:.4f}) -> "
|
||||||
|
f"[{row['a_next']:7.4f}, {row['b_next']:7.4f}], "
|
||||||
|
f"D/2={row['Delta_next/2']:.4f}"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user