- •Одномерная оптимизация
- •Метод дихотомии
- •Метод золотого сечения
- •Метод Ньютона
- •Многомерная оптимизация по направлению
- •Метод дихотомии
- •Метод золотого сечения
- •Метод Ньютона
- •Листинг кода метода дихотомии
- •Тест метода дихотомии
- •Листинг кода метода золотого сечения
- •Тест метода золотого сечения
- •Листинг кода метода Ньютона
- •Тест метода Ньютона
AЛистинг кода метода дихотомии
1using static System.Math;
2using System;
3
4namespace MathUtilities
5{
6
7
8
9
10
11
12
13
14
15
///<summary>
///Находит оптимум функции одной переменной при помощи метода дихотомии.
///</summary>
public class DichotomyOptimizer
{
///<summary>
///Функция для исследования.
///</summary>
private readonly Func<double, double> _function;
16
17
18
19
20
///<summary>
///Начало поиска.
///</summary>
private readonly double _start;
21
22
23
24
25
///<summary>
///Шаг поиска.
///</summary>
private readonly double _step;
26/// <summary>
27/// Точность поиска. Влияет на размер области поиска.
28/// </summary>
29private readonly double _precision;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
///<summary>
///Максимальное количество операций.
///</summary>
private readonly uint _operationAmount;
///<summary>
///Смотрим ли максимум или минимум.
///</summary>
private readonly bool _lookingForMax;
///<summary>
///Счётчик операций.
///</summary>
private uint counter;
45
11
46/// <summary>
47/// Стандартный конструктор анализатора.
48/// </summary>
49/// <param name="function">функция для исследования</param>
50/// <param name="start">точка начала поиска</param>
51/// <param name="step">шаг поиска</param>
52/// <param name="precision">точность поиска</param>
53/// <param name="operationsAmount">максимальное количество
,! операций</param>
54/// <param name="lookingForMax">смотрим ли максимум или минимум</param>
55public DichotomyOptimizer(
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Func<double, double> function, double start = 0,
double step = 1E-02, double precision = 1E-04,
uint operationsAmount = 150, bool lookingForMax = false
) {
_function = function; _start = start;
//разворачивает шаг в нужную сторону
//учитывает max / min
_step = function(start + step) > function(start - step) ? lookingForMax ? step : -step
: lookingForMax ? -step : step;
_precision = precision; _operationAmount = operationsAmount; _lookingForMax = lookingForMax;
ResetCounter();
}
78/// <summary>
79/// Рассчитывает оптимальное значение функции.
80/// </summary>
81/// <returns>оптимальное значение функции</returns>
82public double GetOptimal()
83{
84 |
// узнаём область поиска |
85 |
var triplet = GetArea(); |
86 |
// если область поиска маленькая, |
87 |
// не продолжать искать |
88 |
while (!IsTooSmall(triplet)) |
89 |
{ |
90 |
// если количество операций превысило максимальное, выкинуть |
|
,! ошибку |
12
91 |
if (IsCountDown()) |
92 |
throw new ApplicationException("не удалось найти оптимального |
|
,! решения"); |
93 |
|
94
95
96
97
98
99
// делим область на две части: левую и правую
var left = new Triplet {A = triplet.A, B = triplet.Center};
var right = new Triplet {A = triplet.Center, B = triplet.B};
// выбираем лучшую между левой и правой triplet = FindGood(left, right);
}
100 |
|
101 |
return triplet.Center; |
102 |
} |
103 |
|
104/// <summary>
105/// Рассчитывает область поиска или кидает исключение по превышении ,! количества операций.
106/// </summary>
107/// <returns>область поиска оптимума</returns>
108public Triplet GetArea()
109{
110 |
// записываем шаг |
поиска |
111 |
var step = _step; |
|
112 |
// создаём тройку |
с нуля |
113 |
var triplet = new |
Triplet {A = _start, B = _start + step * 2 }; |
114 |
// пока не найдём удачную тройку, ищем |
|
115 |
while (!IsLucky(triplet)) |
|
116 |
{ |
|
117 |
// если количество операций превысило максимальное, кинуть |
|
|
,! ошибку |
|
118
119
if (IsCountDown())
throw new ApplicationException("не удалось найти область
,! поиска");
120
121
122
123
124
125
126
// двигаем провотиположную A сторону на количество шагов
triplet.B += step;
// удваиваем шаг step *= 2;
}
127
128
129
130
131
132
133
ResetCounter(); return triplet;
}
///<summary>
///Удачна ли тройка для этой функции.
///</summary>
13
134/// <remark>
135/// Учитывает настройку, какой параметр ищем: max / min.
136/// </remark>
137/// <param name="triplet">тройка</param>
138/// <returns>истина, если тройка удачная</returns>
139private bool IsLucky(Triplet triplet) =>
140
141
142
143
144
145
_lookingForMax
? _function(triplet.Center) >= _function(triplet.A) && _function(triplet.Center) >= _function(triplet.B)
: _function(triplet.Center) <= _function(triplet.A) && _function(triplet.Center) <= _function(triplet.B);
146/// <summary>
147/// Узнаёт, не мала ли тройка.
148/// </summary>
149/// <param name="triplet">тройка</param>
150/// <returns>истина, если тройка меньше точности поиска</returns>
151private bool IsTooSmall(Triplet triplet) =>
152 |
Abs(triplet.B - triplet.A) <= _precision; |
153
154
155/// <summary>
156/// Выбирает из двух троек лучшую.
157/// </summary>
158/// <remark>
159/// Учитывает настройку, какой параметр ищем: max / min.
160/// </remark>
161/// <param name="left">одна тройка</param>
162/// <param name="right">другая тройка</param>
163/// <returns>тройка, которая оказалась лучше</returns>
164private Triplet FindGood(Triplet left, Triplet right)
165{
166 |
// либо |
оба лучшие, либо оба не лучшие |
|
167 |
if (!(IsLucky(left) ^ IsLucky(right))) |
||
168 |
return |
|
|
169 |
_lookingForMax |
||
170 |
|
? _function(left.Center) > _function(right.Center) ? left : |
|
|
|
,! |
right |
171 |
|
: _function(left.Center) < _function(right.Center) ? left : |
|
|
|
,! |
right; |
172 |
else if |
(IsLucky(left)) |
|
173 |
return left; |
||
174 |
else if |
(IsLucky(right)) |
|
175 |
return right; |
||
176 |
else |
|
|
177 |
throw new ApplicationException($"произошла неизвестная ошибка |
||
|
,! |
при выборе между {left} и {right}"); |
14
178 |
} |
179
180/// <summary>
181/// Увеличивает счётчик на 1 и передаёт, не превысило ли количество ,! операций максимальное.
182/// </summary>
183/// <returns>истина, если количество операций превысило
,! максимальное</returns>
184
185
186
private bool IsCountDown() => counter++ > _operationAmount;
187/// <summary>
188/// Сбрасывает счётчик.
189/// </summary>
190private void ResetCounter() =>
191 |
counter = 0; |
192 |
} |
193 |
|
194
195
196
197
198
199
200
201
202
203
///<summary>
///Тройка чисел.
///</summary>
public class Triplet
{
///<summary>
///Левая часть тройки.
///</summary>
public double A { get; set; }
204
205
206
207
208
///<summary>
///Правая часть тройки.
///</summary>
public double B { get; set; }
209/// <summary>
210/// Центральная часть тройки.
211/// </summary>
212public double Center { get => A + (B - A) / 2; }
213
214 public override string ToString() =>
215 |
$"{A} - {Center} - {B}"; |
216}
217}
15