Advertisement
VssA

GoldenSection

Jun 5th, 2024
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.95 KB | None | 0 0
  1. using System;
  2. using System.Diagnostics.Metrics;
  3. using System.Security.Cryptography;
  4.  
  5.  
  6. /// <summary>
  7. /// Находит оптимум функции одной переменной при помощи метода золотого сечения.
  8. /// </summary>
  9. public class GoldenOptimizer
  10. {
  11. /// <summary>
  12. /// Функция для исследования.
  13. /// </summary>
  14. private readonly Func<double, double> _function;
  15.  
  16. /// <summary>
  17. /// Начало поиска.
  18. /// </summary>
  19. private readonly double _start;
  20.  
  21. /// <summary>
  22. /// Шаг поиска.
  23. /// </summary>
  24. private readonly double _step;
  25.  
  26. /// <summary>
  27. /// Точность поиска. Влияет на размер области поиска.
  28. /// </summary>
  29. private readonly double _precision;
  30.  
  31. /// <summary>
  32. /// Максимальное количество операций.
  33. /// </summary>
  34. private readonly uint _operationAmount;
  35.  
  36. /// <summary>
  37. /// Смотрим ли максимум или минимум.
  38. /// </summary>
  39. private readonly bool _lookingForMax;
  40.  
  41. /// <summary>
  42. /// Счётчик операций.
  43. /// </summary>
  44. private uint counter;
  45.  
  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>
  55. public GoldenOptimizer(
  56. Func<double, double> function,
  57. double start = 0,
  58. double step = 1E-02,
  59. double precision = 1E-04,
  60. uint operationsAmount = 150,
  61. bool lookingForMax = false)
  62. {
  63. _function = function;
  64. _start = start;
  65. // разворачивает шаг в нужную сторону
  66. // учитывает max / min
  67. _step = function(start + step) > function(start - step)
  68. ? lookingForMax ? step : -step
  69. : lookingForMax ? -step : step;
  70.  
  71. _precision = precision;
  72. _operationAmount = operationsAmount;
  73. _lookingForMax = lookingForMax;
  74.  
  75. ResetCounter();
  76. }
  77.  
  78. /// <summary>
  79. /// Рассчитывает оптимальное значение функции.
  80. /// </summary>
  81. /// <returns>оптимальное значение функции</returns>
  82. public double GetOptimal()
  83. {
  84. // узнаём область поиска
  85. var triplet = GetArea();
  86. // если область поиска маленькая,
  87. // не продолжать искать
  88. while (!IsTooSmall(triplet))
  89. {
  90.  
  91. // если количество операций превысило максимальное, выкинуть ошибку
  92. if (IsCountDown())
  93. throw new ApplicationException("не удалось найти оптимального решения");
  94.  
  95. triplet = FindGood(triplet);
  96. }
  97.  
  98. // всё равно передаём центральную точку
  99. return triplet.A + (triplet.B - triplet.A) / 2;
  100. }
  101.  
  102. /// <summary>
  103. /// Рассчитывает область поиска или кидает исключение по превышении количества операций.
  104. /// <returns>область поиска оптимума</returns>
  105. public GoldenTriplet GetArea()
  106. {
  107. // записываем шаг поиска
  108. var step = _step;
  109. // создаём тройку с нуля
  110. var triplet = new GoldenTriplet
  111. {
  112. A = _start,
  113. RightCenter = _start + step
  114. };
  115. // пока не найдём удачную тройку, ищем
  116. while (!IsLucky(triplet))
  117. {
  118. // если количество операций превысило максимальное, кинуть ошибку
  119. if (IsCountDown())
  120. throw new ApplicationException("не удалось найти область поиска");
  121.  
  122. // двигаем провотиположную A сторону на количество шагов
  123. triplet.LeftCenter = triplet.B;
  124. }
  125.  
  126. ResetCounter();
  127. return triplet;
  128. }
  129.  
  130. /// <summary>
  131. /// Удачна ли тройка для этой функции.
  132. /// </summary>
  133. /// <remark>
  134. /// Учитывает настройку, какой параметр ищем: max / min.
  135. /// </remark>
  136. /// <param name="triplet">тройка</param>
  137. /// <returns>истина, если тройка удачная</returns>
  138. private bool IsLucky(GoldenTriplet triplet) =>
  139. _lookingForMax
  140. ? _function(triplet.RightCenter) >= _function(triplet.A) &&
  141. _function(triplet.RightCenter) >= _function(triplet.B)
  142. : _function(triplet.RightCenter) <= _function(triplet.A) &&
  143. _function(triplet.RightCenter) <= _function(triplet.B);
  144.  
  145. /// <summary>
  146. /// Узнаёт, не мала ли тройка.
  147. /// </summary>
  148. /// <param name="triplet">тройка</param>
  149. /// <returns>истина, если тройка меньше точности поиска</returns>
  150. private bool IsTooSmall(GoldenTriplet triplet) =>
  151. Math.Abs(triplet.B - triplet.A) <= _precision;
  152.  
  153.  
  154. /// <summary>
  155. /// Выбирает из двух частей тройки лучшую.
  156. /// </summary>
  157. /// <remark>
  158. /// Учитывает настройку, какой параметр ищем: max / min.
  159. /// </remark>
  160. /// <param name="old">тройка для рассмотрения</param>
  161. /// <returns>новая тройка, оказавшаяся лучше</returns>
  162. private GoldenTriplet FindGood(GoldenTriplet old)
  163. {
  164. if (_lookingForMax)
  165. return _function(old.LeftCenter) > _function(old.RightCenter) ?
  166. new GoldenTriplet { A = old.LeftCenter, B = old.B } : new
  167. GoldenTriplet
  168. { A = old.A, B = old.RightCenter };
  169.  
  170.  
  171. else
  172. return _function(old.LeftCenter) < _function(old.RightCenter) ?
  173. new GoldenTriplet { A = old.A, B = old.RightCenter } : new
  174. GoldenTriplet
  175. { A = old.LeftCenter, B = old.B };
  176.  
  177.  
  178. }
  179. /// <summary>
  180. /// Увеличивает счётчик на 1 и передаёт, не превысило ли количество операций максимальное.
  181. /// </summary>
  182. /// <returns>истина, если количество операций превысило максимальное </ returns >
  183. private bool IsCountDown() =>
  184.  
  185. counter++ > _operationAmount;
  186.  
  187. /// <summary>
  188. /// Сбрасывает счётчик.
  189. /// </summary>
  190. private void ResetCounter() =>
  191. counter = 0;
  192. }
  193.  
  194. /// <summary>
  195. /// Тройка с золотым сечением.
  196. /// </summary>
  197. public class GoldenTriplet
  198. {
  199. /// <summary>
  200. /// Золотое число. 1 - (\sqrt(5) - 1) / 2
  201. /// </summary>
  202. public const double SmallGolden = 0.3819660113;
  203.  
  204. /// <summary>
  205. /// Золотое число. (\sqrt(5) - 1) / 2
  206. /// </summary>
  207. public const double Golden = 0.6180339887;
  208.  
  209. /// <summary>
  210. /// Золотое число. (\sqrt(5) + 1) / 2
  211. /// </summary>
  212. public const double BigGolden = 1.6180339887;
  213.  
  214. /// <summary>
  215. /// Левая часть тройки.
  216. /// </summary>
  217. public double A { get; set; }
  218.  
  219. /// <summary>
  220. /// Правая часть тройки.
  221. /// </summary>
  222. public double B { get; set; }
  223.  
  224. /// <summary>
  225. /// Центральная часть тройки ближе к правому краю.
  226. ///
  227. /// Сеттер на самом деле устанавливает правую часть.
  228. /// </summary>
  229. /// <remark>
  230. /// Золотое сечение.
  231. /// </remark>
  232.  
  233. public double RightCenter
  234. {
  235. get => A + (B - A) * Golden; set => B = value * BigGolden - A * Golden;
  236. }
  237.  
  238. /// <summary>
  239. /// Центральная часть тройки ближе к левому краю.
  240. /// </summary>
  241. /// <remark>
  242. /// Золотое сечение.
  243. /// </remark>
  244. public double LeftCenter
  245. {
  246. get => B - (B - A) * Golden; set => B = value
  247. + BigGolden * (value - A);
  248. }
  249.  
  250. public override string ToString() =>
  251. $"{A} - {LeftCenter} - {RightCenter} - {B}";
  252. }
  253.  
  254.  
  255.  
  256. class Program
  257. {
  258. /* static public double f(List<double> x)
  259. {
  260. 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];
  261. }
  262.  
  263. static double g(double t)
  264. {
  265. List<double> vector = new List<double>() { 2 - t, 1 + 2 * t, 26 + t };
  266. return f(vector);
  267. }*/
  268. static void Main()
  269. {
  270.  
  271. /* 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;
  272. double min = GoldenSection.Minimize(func, -1.1, 0.3, 0.0001);
  273. double f = func(min);
  274. Console.WriteLine($"Минимум функции: {min}, значение функции: {f}");
  275. var min2 = GoldenSection.Minimize(g, -1, 1, 0.0001);
  276. var f2 = g(min2);
  277. Console.WriteLine($"Минимум функции: {min2}, значение функции: {f2}");*/
  278. }
  279. }
  280.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement