Метод золотого сечения

Золотое сечение находит минимум унимодальной функции, сужая интервал с фиксированным коэффициентом и переиспользуя одну пробную точку.

Метод золотого сечения — алгоритм одномерной минимизации, на каждом шаге сужающий интервал неопределённости в $\varphi\approx 1.618$ раза, требуя лишь одного нового вычисления функции на итерацию.

Идея

Держим отрезок $[a,b]$ с минимумом внутри. Поставим две внутренние точки $c<d$. Если $f(c)<f(d)$, минимум не может быть правее $d$ (функция унимодальна), значит отбрасываем $(d,b]$ и новый отрезок — $[a,d]$. Иначе отбрасываем $[a,c)$. Отрезок сжимается. Вопрос: где ставить $c,d$, чтобы при сжатии одну из старых точек можно было переиспользовать и не считать $f$ заново?

Магия числа $\varphi$

Ответ даёт золотое сечение $\varphi=\dfrac{1+\sqrt5}{2}\approx 1.618$. Если ставить точки на расстоянии $\rho=1/\varphi\approx 0.618$ от концов:

$$c=b-\rho(b-a),\qquad d=a+\rho(b-a),$$

то после отбрасывания одна из новых пробных точек уже совпадает со старой, и на каждой итерации нужно лишь одно новое вычисление $f$. Интервал стабильно умножается на $\rho\approx 0.618$, то есть за каждые $\sim 5$ итераций сокращается на порядок.

Реализация

import math

def phi_fun(x):
    return (x - 2) ** 2 + math.sin(3 * x)

def golden(f, a, b, tol=1e-5):
    invphi = (math.sqrt(5) - 1) / 2          # 1/φ ≈ 0.618
    c = b - invphi * (b - a)
    d = a + invphi * (b - a)
    fc, fd = f(c), f(d)
    step = 0
    while (b - a) > tol:
        step += 1
        if fc < fd:
            b, d, fd = d, c, fc
            c = b - invphi * (b - a)
            fc = f(c)
        else:
            a, c, fc = c, d, fd
            d = a + invphi * (b - a)
            fd = f(d)
        if step <= 5 or step % 5 == 0:
            print(f"шаг {step:2d}: интервал=[{a:.4f}, {b:.4f}] ширина={b-a:.5f}")
    return (a + b) / 2

x_star = golden(phi_fun, 0.0, 4.0)
print("Минимум x* ≈", round(x_star, 5))
print("f(x*)    ≈", round(phi_fun(x_star), 5))

Вывод:

шаг  1: интервал=[0.0000, 2.4721] ширина=2.47214
шаг  2: интервал=[0.9443, 2.4721] ширина=1.52786
шаг  3: интервал=[0.9443, 1.8885] ширина=0.94427
шаг  4: интервал=[1.3050, 1.8885] ширина=0.58359
шаг  5: интервал=[1.5279, 1.8885] ширина=0.36068
шаг 10: интервал=[1.6331, 1.6656] ширина=0.03252
шаг 15: интервал=[1.6485, 1.6514] ширина=0.00293
шаг 20: интервал=[1.6493, 1.6496] ширина=0.00026
шаг 25: интервал=[1.6494, 1.6494] ширина=0.00002
Минимум x* ≈ 1.64943
f(x*)    ≈ -0.8494

Заметьте: ширина интервала на каждом шаге множится примерно на $0.618$ — это и есть постоянная скорость золотого сечения. Найденный минимум $x^*\approx 1.649$ глубже ($f\approx-0.849$), чем грубая оценка перебора из прошлого урока ($x\approx1.6$, $f\approx-0.836$), потому что сетка была слишком редкой.

Сравнение с перебором

МетодВызовов $f$ для точности $10^{-5}$ на $[0,4]$
Равномерная сетка$\sim 4\cdot 10^5$ точек
Золотое сечение$\sim 27$ вызовов

Как работает под капотом

Скорость сходимости золотого сечения линейная: ошибка убывает как $\rho^k$ с $\rho\approx 0.618$. Это медленнее, чем у методов на основе производных (метод секущих, парабол), но зато золотое сечение надёжно работает без производных и не требует гладкости — только унимодальности. Поэтому его выбирают, когда функция «чёрный ящик»: задана кодом, шумна или негладка, а считать производные нельзя или дорого.

Частые ошибки

  • Пересчитывать обе точки каждый шаг. Весь смысл $\varphi$ — переиспользовать одну; иначе теряется половина выигрыша.
  • Применять к мультимодальной функции. Метод гарантирует минимум только при унимодальности на $[a,b]$.
  • Слишком грубый $tol$. Останавливаемся по ширине интервала, а не по значению $f$ — следите за нужной точностью аргумента.

Итоги

  • Золотое сечение сужает интервал в $\varphi\approx 1.618$ раз за шаг, делая лишь одно новое вычисление $f$.
  • Сходимость линейная ($\rho\approx 0.618$), без производных, требует унимодальности.
  • Идеален для негладких «чёрных ящиков»; на порядки экономнее перебора.
Проверьте себя
1. Почему в методе золотого сечения хватает одного нового вычисления $f$ на шаг?
AФункция линейна
BПробные точки расставлены так, что одна старая точка переиспользуется
CИспользуется производная
DИнтервал не меняется
2. Во сколько раз сужается интервал за одну итерацию?
AВ 2 раза
BВ $\varphi\approx 1.618$ раза (умножается на $\approx 0.618$)
CВ 10 раз
DНе сужается
3. Когда золотое сечение предпочтительнее методов с производными?
AКогда функция гладкая
BКогда функция — негладкий или шумный «чёрный ящик» без доступных производных
CКогда переменных много
DКогда нужна максимальная скорость