Поиск с помощью золотого сечения — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Алгоритм)
Строка 4: Строка 4:
 
Рассмотрим одну итерацию алгоритма [[Троичный поиск|троичного поиска]]. Попробуем подобрать такое разбиение отрезка на три части, чтобы на следующей итерации одна из точек нового разбиения совпала с одной из точек текущего разбиения. Тогда в следующий раз не придется считать функцию в двух точках, так как в одной она уже была посчитана.  
 
Рассмотрим одну итерацию алгоритма [[Троичный поиск|троичного поиска]]. Попробуем подобрать такое разбиение отрезка на три части, чтобы на следующей итерации одна из точек нового разбиения совпала с одной из точек текущего разбиения. Тогда в следующий раз не придется считать функцию в двух точках, так как в одной она уже была посчитана.  
  
[[Файл:Goldensection.gif|220px]]
+
Пусть <tex>l</tex> и <tex>r</tex> левая и правая граница исследуемого отрезка.
  
Точки <tex>x_1</tex> и <tex>x_2</tex> разбивают отрезок на три части. Потребуем, чтобы одновременно выполнялось:  
+
Точки <tex>x_1</tex> и <tex>x_2</tex> разбивают отрезок на три части, длины <tex>a, b, c</tex> соответственно. Потребуем, чтобы одновременно выполнялось:  
  
 
<tex> \frac{a + b}{c} = \frac{b + c}{a} = \varphi </tex>
 
<tex> \frac{a + b}{c} = \frac{b + c}{a} = \varphi </tex>
Строка 36: Строка 36:
 
:'''Шаг 1''':
 
:'''Шаг 1''':
 
::Определяем границы поиска <tex>lbound</tex> и <tex>rbound</tex>, затем устанавливаем текущее разбиение:
 
::Определяем границы поиска <tex>lbound</tex> и <tex>rbound</tex>, затем устанавливаем текущее разбиение:
::<tex>x_1 = lbound + \frac{rbound - lbound}{\varphi + 1}</tex>  
+
::<tex>x_1 = l + \frac{r - l}{\varphi + 1}</tex>  
::<tex>x_2 = rbound - \frac{rbound - lbound}{\varphi + 1}</tex>
+
::<tex>x_2 = r - \frac{r - l}{\varphi + 1}</tex>
 
::и вычислим функцию на них: <tex>f_1 = f(x_1), f_2 = f(x_2)</tex>
 
::и вычислим функцию на них: <tex>f_1 = f(x_1), f_2 = f(x_2)</tex>
[[Файл:Nextsection.gif|thumb|380px|Старая точка x1 уже делит отрезок в нужном отношении, поэтому нет необходимости вычислять ее заново (красным отмечены новые значения точек).]]
 
 
:'''Шаг 2''':  
 
:'''Шаг 2''':  
 
:: если <tex>f_1 < f_2</tex>, тогда
 
:: если <tex>f_1 < f_2</tex>, тогда
::: <tex>rbound = x_2</tex>
+
::: <tex>r = x_2</tex>
 
::: <tex>x_2 = x_1, f_2 = f_1</tex>
 
::: <tex>x_2 = x_1, f_2 = f_1</tex>
::: <tex>x_1 = lbound + \frac{rbound - lbound}{\varphi + 1},\; f_1 = f(x_1)</tex>  
+
::: <tex>x_1 = l + \frac{r - l}{\varphi + 1},\; f_1 = f(x_1)</tex>  
 
:: иначе:
 
:: иначе:
::: <tex>lbound = x_1</tex>
+
::: <tex>l = x_1</tex>
 
::: <tex>x_1 = x_2, f_1 = f_2</tex>
 
::: <tex>x_1 = x_2, f_1 = f_2</tex>
::: <tex>x_2 = rbound - \frac{rbound - lbound}{\varphi + 1},\; f_2 = f(x_2)</tex>
+
::: <tex>x_2 = r - \frac{r - l}{\varphi + 1},\; f_2 = f(x_2)</tex>
 
:'''Шаг 3''':
 
:'''Шаг 3''':
:: если точность <tex>|rbound - lbound| < \varepsilon</tex> нас устраивает, тогда останавливаемся, и искомая точка <tex>x = \frac{lbound + rbound}{2}</tex>, иначе назад к шагу 2
+
:: если точность <tex>|r - l| < \varepsilon</tex> нас устраивает, тогда останавливаемся, и искомая точка <tex>x = \frac{l + r}{2}</tex>, иначе назад к шагу 2
  
 
===Псевдокод===
 
===Псевдокод===
Строка 56: Строка 55:
 
  resphi = 2 - phi
 
  resphi = 2 - phi
 
   
 
   
  goldenSectionSearch(f, lbound, rbound, eps)
+
  goldenSectionSearch(f, l, r, eps)
     x1 = lbound + resphi * (rbound - lbound)
+
     x1 = l + resphi * (r - l)
     x2 = rbound - resphi * (rbound - lbound)
+
     x2 = r - resphi * (r - l)
 
     f1 = f(x1)
 
     f1 = f(x1)
 
     f2 = f(x2)
 
     f2 = f(x2)
Строка 64: Строка 63:
 
     do
 
     do
 
         if f1 < f2:
 
         if f1 < f2:
             rbound = x2
+
             r = x2
 
             x2 = x1
 
             x2 = x1
 
             f2 = f1
 
             f2 = f1
             x1 = lbound + resphi * (rbound - lbound)
+
             x1 = l + resphi * (r - l)
 
             f1 = f(x1)
 
             f1 = f(x1)
 
         else:
 
         else:
             lbound = x1
+
             l = x1
 
             x1 = x2
 
             x1 = x2
 
             f1 = f2
 
             f1 = f2
             x2 = rbound - resphi * (rbound - lbound)
+
             x2 = r - resphi * (r - l)
 
             f2 = f(x2)
 
             f2 = f(x2)
     while (abs(rbound - lbound) > eps)
+
     while (abs(r - l) > eps)
 
      
 
      
 
     return (x1 + x2) / 2
 
     return (x1 + x2) / 2
 +
 
==Время работы==
 
==Время работы==
 
Так как на каждой итерации мы считаем два значения функции и уменьшаем область поиска в полтора раза, пока <tex> r - l > \varepsilon</tex>,
 
Так как на каждой итерации мы считаем два значения функции и уменьшаем область поиска в полтора раза, пока <tex> r - l > \varepsilon</tex>,

Версия 00:43, 12 мая 2012

Поиск с помощью золотого сечения (Golden section search) - это улучшение наивной реализации троичного поиска, служащего для нахождения минимума/максимума функции. При простом троичном поиске на каждой итерации функция вычисляется в двух точках. Метод же золотого сечения требует вычисления лишь в одной точке (за исключением первой итерации). За счет этого достигается выигрыш в производительности.

Алгоритм

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

Пусть [math]l[/math] и [math]r[/math] левая и правая граница исследуемого отрезка.

Точки [math]x_1[/math] и [math]x_2[/math] разбивают отрезок на три части, длины [math]a, b, c[/math] соответственно. Потребуем, чтобы одновременно выполнялось:

[math] \frac{a + b}{c} = \frac{b + c}{a} = \varphi [/math]

[math] \frac{a}{b} = \varphi [/math]

[math] \frac{c}{b} = \varphi [/math]

Где [math] \varphi [/math] - это некоторое отношение, в котором мы делим отрезок (точки [math]x_1[/math] и [math]x_2[/math] разбивают отрезок симметрично).

Тогда:

[math] a + b = \varphi c, a = \varphi b, c = \varphi b[/math], откуда получаем [math] \varphi + 1 = \varphi^2 \Rightarrow \varphi = \frac{1 + \sqrt{5}}{2}[/math]   (тот корень уравнения, который меньше нуля, по понятным причинам отбросили).

Это число совпадает с золотым сечением. Отсюда название метода.

Для реализации алгоритма нам потребуется найти [math] a [/math] и [math] a + b [/math]. Если [math] L [/math] - длина исследуемого отрезка, тогда:

[math] (\frac{b + c}{a} = \varphi;\; b + c = L - a) \Rightarrow[/math]

[math] a = \frac{L}{\varphi + 1} [/math]

[math] a + b = L - c = L - a = L - \frac{L}{\varphi + 1}[/math]

Причем, заметим что в силу того что [math]\varphi[/math] - золотое сечение, то [math]\frac{1}{\varphi + 1} = 2 - \varphi[/math].

Формально для поиска минимума (для максимума - делается аналогично) функции [math] f [/math] делаем следующее:

Шаг 1:
Определяем границы поиска [math]lbound[/math] и [math]rbound[/math], затем устанавливаем текущее разбиение:
[math]x_1 = l + \frac{r - l}{\varphi + 1}[/math]
[math]x_2 = r - \frac{r - l}{\varphi + 1}[/math]
и вычислим функцию на них: [math]f_1 = f(x_1), f_2 = f(x_2)[/math]
Шаг 2:
если [math]f_1 \lt f_2[/math], тогда
[math]r = x_2[/math]
[math]x_2 = x_1, f_2 = f_1[/math]
[math]x_1 = l + \frac{r - l}{\varphi + 1},\; f_1 = f(x_1)[/math]
иначе:
[math]l = x_1[/math]
[math]x_1 = x_2, f_1 = f_2[/math]
[math]x_2 = r - \frac{r - l}{\varphi + 1},\; f_2 = f(x_2)[/math]
Шаг 3:
если точность [math]|r - l| \lt \varepsilon[/math] нас устраивает, тогда останавливаемся, и искомая точка [math]x = \frac{l + r}{2}[/math], иначе назад к шагу 2

Псевдокод

phi = (1 + sqrt(5)) / 2
resphi = 2 - phi

goldenSectionSearch(f, l, r, eps)
   x1 = l + resphi * (r - l)
   x2 = r - resphi * (r - l)
   f1 = f(x1)
   f2 = f(x2)
   
   do
       if f1 < f2:
           r = x2
           x2 = x1
           f2 = f1
           x1 = l + resphi * (r - l)
           f1 = f(x1)
       else:
           l = x1
           x1 = x2
           f1 = f2
           x2 = r - resphi * (r - l)
           f2 = f(x2)
   while (abs(r - l) > eps)
   
   return (x1 + x2) / 2

Время работы

Так как на каждой итерации мы считаем два значения функции и уменьшаем область поиска в полтора раза, пока [math] r - l \gt \varepsilon[/math], то время работы алгоритма составит [math]2 \log_{\frac32} \left(\frac{r - l}{\varepsilon}\right)[/math]

Так как на каждой итерации мы считаем одно значение функции и уменьшаем область поиска в [math] \varphi [/math] раз, пока [math] r - l \gt \varepsilon[/math], то время работы алгоритма составит [math] log_{\varphi}(\frac{r - l}{\varepsilon})[/math].

Если удельный вес вычисления функции [math] f [/math] достаточно большой, тогда получим ускорение работы примерно в 2,4 раз по сравнению с неулучшенным троичным поиском.

См также

Ссылки