Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Diagnostics.Metrics;
- using System.Security.Cryptography;
- /// <summary>
- /// Находит оптимум функции одной переменной при помощи метода золотого сечения.
- /// </summary>
- public class GoldenOptimizer
- {
- /// <summary>
- /// Функция для исследования.
- /// </summary>
- private readonly Func<double, double> _function;
- /// <summary>
- /// Начало поиска.
- /// </summary>
- private readonly double _start;
- /// <summary>
- /// Шаг поиска.
- /// </summary>
- private readonly double _step;
- /// <summary>
- /// Точность поиска. Влияет на размер области поиска.
- /// </summary>
- private readonly double _precision;
- /// <summary>
- /// Максимальное количество операций.
- /// </summary>
- private readonly uint _operationAmount;
- /// <summary>
- /// Смотрим ли максимум или минимум.
- /// </summary>
- private readonly bool _lookingForMax;
- /// <summary>
- /// Счётчик операций.
- /// </summary>
- private uint counter;
- /// <summary>
- /// Стандартный конструктор анализатора.
- /// </summary>
- /// <param name="function">функция для исследования</param>
- /// <param name="start">точка начала поиска</param>
- /// <param name="step">шаг поиска</param>
- /// <param name="precision">точность поиска</param>
- /// <param name="operationsAmount">максимальное количество операций </ param >
- /// <param name="lookingForMax">смотрим ли максимум или минимум</param>
- public GoldenOptimizer(
- 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();
- }
- /// <summary>
- /// Рассчитывает оптимальное значение функции.
- /// </summary>
- /// <returns>оптимальное значение функции</returns>
- public double GetOptimal()
- {
- // узнаём область поиска
- var triplet = GetArea();
- // если область поиска маленькая,
- // не продолжать искать
- while (!IsTooSmall(triplet))
- {
- // если количество операций превысило максимальное, выкинуть ошибку
- if (IsCountDown())
- throw new ApplicationException("не удалось найти оптимального решения");
- triplet = FindGood(triplet);
- }
- // всё равно передаём центральную точку
- return triplet.A + (triplet.B - triplet.A) / 2;
- }
- /// <summary>
- /// Рассчитывает область поиска или кидает исключение по превышении количества операций.
- /// <returns>область поиска оптимума</returns>
- public GoldenTriplet GetArea()
- {
- // записываем шаг поиска
- var step = _step;
- // создаём тройку с нуля
- var triplet = new GoldenTriplet
- {
- A = _start,
- RightCenter = _start + step
- };
- // пока не найдём удачную тройку, ищем
- while (!IsLucky(triplet))
- {
- // если количество операций превысило максимальное, кинуть ошибку
- if (IsCountDown())
- throw new ApplicationException("не удалось найти область поиска");
- // двигаем провотиположную A сторону на количество шагов
- triplet.LeftCenter = triplet.B;
- }
- ResetCounter();
- return triplet;
- }
- /// <summary>
- /// Удачна ли тройка для этой функции.
- /// </summary>
- /// <remark>
- /// Учитывает настройку, какой параметр ищем: max / min.
- /// </remark>
- /// <param name="triplet">тройка</param>
- /// <returns>истина, если тройка удачная</returns>
- private bool IsLucky(GoldenTriplet triplet) =>
- _lookingForMax
- ? _function(triplet.RightCenter) >= _function(triplet.A) &&
- _function(triplet.RightCenter) >= _function(triplet.B)
- : _function(triplet.RightCenter) <= _function(triplet.A) &&
- _function(triplet.RightCenter) <= _function(triplet.B);
- /// <summary>
- /// Узнаёт, не мала ли тройка.
- /// </summary>
- /// <param name="triplet">тройка</param>
- /// <returns>истина, если тройка меньше точности поиска</returns>
- private bool IsTooSmall(GoldenTriplet triplet) =>
- Math.Abs(triplet.B - triplet.A) <= _precision;
- /// <summary>
- /// Выбирает из двух частей тройки лучшую.
- /// </summary>
- /// <remark>
- /// Учитывает настройку, какой параметр ищем: max / min.
- /// </remark>
- /// <param name="old">тройка для рассмотрения</param>
- /// <returns>новая тройка, оказавшаяся лучше</returns>
- private GoldenTriplet FindGood(GoldenTriplet old)
- {
- if (_lookingForMax)
- return _function(old.LeftCenter) > _function(old.RightCenter) ?
- new GoldenTriplet { A = old.LeftCenter, B = old.B } : new
- GoldenTriplet
- { A = old.A, B = old.RightCenter };
- else
- return _function(old.LeftCenter) < _function(old.RightCenter) ?
- new GoldenTriplet { A = old.A, B = old.RightCenter } : new
- GoldenTriplet
- { A = old.LeftCenter, B = old.B };
- }
- /// <summary>
- /// Увеличивает счётчик на 1 и передаёт, не превысило ли количество операций максимальное.
- /// </summary>
- /// <returns>истина, если количество операций превысило максимальное </ returns >
- private bool IsCountDown() =>
- counter++ > _operationAmount;
- /// <summary>
- /// Сбрасывает счётчик.
- /// </summary>
- private void ResetCounter() =>
- counter = 0;
- }
- /// <summary>
- /// Тройка с золотым сечением.
- /// </summary>
- public class GoldenTriplet
- {
- /// <summary>
- /// Золотое число. 1 - (\sqrt(5) - 1) / 2
- /// </summary>
- public const double SmallGolden = 0.3819660113;
- /// <summary>
- /// Золотое число. (\sqrt(5) - 1) / 2
- /// </summary>
- public const double Golden = 0.6180339887;
- /// <summary>
- /// Золотое число. (\sqrt(5) + 1) / 2
- /// </summary>
- public const double BigGolden = 1.6180339887;
- /// <summary>
- /// Левая часть тройки.
- /// </summary>
- public double A { get; set; }
- /// <summary>
- /// Правая часть тройки.
- /// </summary>
- public double B { get; set; }
- /// <summary>
- /// Центральная часть тройки ближе к правому краю.
- ///
- /// Сеттер на самом деле устанавливает правую часть.
- /// </summary>
- /// <remark>
- /// Золотое сечение.
- /// </remark>
- public double RightCenter
- {
- get => A + (B - A) * Golden; set => B = value * BigGolden - A * Golden;
- }
- /// <summary>
- /// Центральная часть тройки ближе к левому краю.
- /// </summary>
- /// <remark>
- /// Золотое сечение.
- /// </remark>
- public double LeftCenter
- {
- get => B - (B - A) * Golden; set => B = value
- + BigGolden * (value - A);
- }
- public override string ToString() =>
- $"{A} - {LeftCenter} - {RightCenter} - {B}";
- }
- class Program
- {
- /* static public double f(List<double> x)
- {
- return Math.Pow(x[0], 2) + 26 * Math.Pow(x[1], 2) + Math.Pow(x[2], 2) + 3 * x[0] * x[1] - 26 * x[0] * x[2] - x[1] * x[2] + x[0] - 26 * x[1] + x[2];
- }
- static double g(double t)
- {
- List<double> vector = new List<double>() { 2 - t, 1 + 2 * t, 26 + t };
- return f(vector);
- }*/
- static void Main()
- {
- /* Func<double, double> func = x => Math.Pow(x, 6) - 26 * Math.Pow(x, 5) + 26 * Math.Pow(x, 3) - 10 * Math.Pow(x, 2) + x;
- double min = GoldenSection.Minimize(func, -1.1, 0.3, 0.0001);
- double f = func(min);
- Console.WriteLine($"Минимум функции: {min}, значение функции: {f}");
- var min2 = GoldenSection.Minimize(g, -1, 1, 0.0001);
- var f2 = g(min2);
- Console.WriteLine($"Минимум функции: {min2}, значение функции: {f2}");*/
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement