Advertisement
slik1977

Gradient

Apr 29th, 2022
1,406
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.74 KB | None | 0 0
  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. import math as math
  4.  
  5.  
  6. class Vec2:
  7.     x = 0
  8.     y = 0
  9.  
  10.     def __init__(self, x, y):
  11.         self.x = x
  12.         self.y = y
  13.  
  14.     def __add__(self, other):
  15.         return Vec2(self.x + other.x, self.y + other.y)
  16.  
  17.     def __sub__(self, other):
  18.         return Vec2(self.x - other.x, self.y - other.y)
  19.  
  20.     def __mul__(self, other):
  21.         return Vec2(self.x * other, self.y * other)
  22.  
  23.     def __truediv__(self, other):
  24.         return Vec2(self.x / other, self.y / other)
  25.  
  26.     def __iadd__(self, other):
  27.         self.x += other.x
  28.         self.y += other.y
  29.         return self
  30.  
  31.     def __isub__(self, other):
  32.         self.x -= other.x
  33.         self.y -= other.y
  34.         return self
  35.  
  36.     def __imul__(self, other):
  37.         self.x *= other
  38.         self.y *= other
  39.         return self
  40.  
  41.     def __repr__(self):
  42.         return "{} {}".format(self.x, self.y)
  43.  
  44.     def SquaredLength(self):
  45.         return self.x * self.x + self.y * self.y
  46.  
  47.     def Length(self):
  48.         return math.sqrt(self.SquaredLength())
  49.  
  50.     def __getitem__(self, key):
  51.         if key == 0:
  52.             return self.x;
  53.         return self.y;
  54.  
  55.  
  56. # Отобразить линии уровня функции двух переменных и траекторию работы алгоритма
  57. def plot_3d_with_trajectory(
  58.         f, trajectory, x_left, x_right, y_left, y_right, resol=10, title="F(X, Y)"
  59. ):
  60.     # f - отрисовываемая функция
  61.     # trajectory - последовательность точек траектории
  62.     # x_left - левая граница оси X
  63.     # x_right - правая граница оси X
  64.     # y_left - левая граница оси Y
  65.     # y_right - правая граница оси Y
  66.     # resol - разрешение, число отрисовываемых точек на единицу длины
  67.     # title - заголовок графика
  68.  
  69.     fig = plt.figure()
  70.     ax = fig.add_subplot(111, projection="3d")
  71.  
  72.     ax.set_xlabel("X")
  73.     ax.set_ylabel("Y")
  74.     ax.set_title(title)
  75.  
  76.     x = np.linspace(x_left, x_right, int((x_right - x_left) * resol))
  77.     y = np.linspace(y_left, y_right, int((y_right - y_left) * resol))
  78.     x, y = np.meshgrid(x, y)
  79.     z = f(x, y)
  80.  
  81.     ax.contour3D(x, y, z)
  82.  
  83.     points_x = [point.x for point in trajectory]
  84.     points_y = [point.y for point in trajectory]
  85.     points_z = [f(point.x, point.y) for point in trajectory]
  86.  
  87.     ax.scatter(points_x, points_y, points_z, c="red")
  88.  
  89.     plt.show()
  90.  
  91.  
  92. def derivative(func, point, h=0.001):
  93.     res = func(point.x, point.y)
  94.     return Vec2(func(point.x + h, point.y) - res, func(point.x, point.y + h) - res) / h;
  95.  
  96.  
  97. def gradient(func, startPoint, method, eps=0.00001):
  98.     newPoint = startPoint
  99.     result = []
  100.     while True:
  101.         lastPoint = newPoint
  102.         newPoint = lastPoint - derivative(func, lastPoint) * method(lastPoint, func)
  103.         result.append(lastPoint)
  104.         if np.absolute(func(newPoint.x, newPoint.y) - func(lastPoint.x, lastPoint.y)) < eps:
  105.             return result
  106.     return result
  107.  
  108.  
  109. class constantMethod():
  110.     value = 0.01
  111.  
  112.     def __init__(self, value=0.01):
  113.         self.value = value
  114.  
  115.     def __call__(self, point, func):
  116.         return self.value
  117.  
  118.  
  119. class splitMethod():
  120.     value = 0.01
  121.     eps = 1
  122.     delta = 0.5
  123.  
  124.     def __init__(self, value=0.01, eps=1, delta=0.5):
  125.         self.value = value
  126.         self.eps = eps
  127.         self.delta = delta
  128.  
  129.     def __call__(self, point, func):
  130.         div = derivative(func, point)
  131.         fval = func(point.x, point.y)
  132.         while func(point.x - self.value * div.x, point.y - self.value * div.y) > (
  133.                 fval - self.eps * self.value * div.SquaredLength()):
  134.             self.value *= self.delta
  135.         return self.value
  136.  
  137.  
  138. class goldMethod():
  139.     a = 0.0001
  140.     b = 1
  141.     eps = 0.00001
  142.  
  143.     def __init__(self, a=0.0001, b=1, eps=0.00001):
  144.         self.a = a
  145.         self.b = b
  146.         self.eps = eps
  147.         if a > b:
  148.             self.a, self.b = self.b, self.a
  149.  
  150.     def __call__(self, point, func):
  151.         fi = 1.6180339887
  152.         grad = derivative(func, point)
  153.         x1 = self.b - (self.b - self.a) / fi
  154.         x2 = self.a + (self.b - self.a) / fi
  155.         resa = self.a
  156.         resb = self.b
  157.         y1 = func(point.x - grad.x * x1, point.y - grad.y * x1)
  158.         y2 = func(point.x - grad.x * x2, point.y - grad.y * x2)
  159.         while np.absolute(resa - resb) > self.eps:
  160.             if y1 <= y2:
  161.                 resb = x2
  162.                 x2 = x1
  163.                 x1 = resb - (resb - resa) / fi
  164.                 y2 = y1
  165.                 y1 = func(point.x - grad.x * x2, point.y - grad.y * x2)
  166.             else:
  167.                 resa = x1
  168.                 x1 = x2
  169.                 x2 = resa + (resb - resa) / fi
  170.                 y1 = y2
  171.                 y1 = func(point.x - grad.x * x1, point.y - grad.y * x1)
  172.         return (resb + resa) * 0.5
  173.  
  174.  
  175. class fibonacciMethod():
  176.     a = 0.0001
  177.     b = 1
  178.     n = 50
  179.  
  180.     def __init__(self, a=0.0001, b=1, n=50):
  181.         self.a = a
  182.         self.b = b
  183.         self.n = n
  184.         if a > b:
  185.             self.a, self.b = self.b, self.a
  186.  
  187.     def fib(self, n):
  188.         if n == 0 or n == 1:
  189.             return 1
  190.         a = 1
  191.         b = 1
  192.         res = 0
  193.         for i in range(1, n):
  194.             res = a + b
  195.             a = b
  196.             b = res
  197.         return res
  198.  
  199.     def __call__(self, point, func):
  200.         grad = derivative(func, point)
  201.         resa = self.a
  202.         resb = self.b
  203.         for k in range(self.n):
  204.             fibo = self.fib(self.n - k + 1)
  205.             lambd = resa + self.fib(self.n - k - 1) / fibo * (resb - resa)
  206.             mu = resa + self.fib(self.n - k) / fibo * (resb - resa)
  207.             if func(point.x - grad.x * lambd, point.y - grad.y * lambd) > func(point.x - grad.x * mu,
  208.                                                                                point.y - grad.y * mu):
  209.                 resa = lambd
  210.             else:
  211.                 resb = mu
  212.         return (resb + resa) * 0.5
  213.  
  214.  
  215. def dixotomMin(func, point, grad, eps=0.001, delta=0.001, a=-100, b=100):
  216.     t = Vec2(0, 0)
  217.     x1 = (a + b - delta) * 0.5
  218.     x2 = (a + b + delta) * 0.5
  219.     total = 0
  220.     while b - a > eps * 2:
  221.         total += 1
  222.         if total > 1000:
  223.             break
  224.         t = point + grad * x1
  225.         y1 = func(t.x, t.y)
  226.         t = point + grad * x2
  227.         y2 = func(t.x, t.y)
  228.         if y1 > y2:
  229.             a = x1
  230.         else:
  231.             b = x2
  232.         x1 = (a + b - delta) * 0.5
  233.         x2 = (a + b + delta) * 0.5
  234.     return (a + b) * 0.5
  235.  
  236.  
  237. def gradientFletcherReeves(func, startPoint, eps=0.00001):
  238.     newPoint = startPoint
  239.     result = []
  240.     beta = 0
  241.     k = 0
  242.     m = 100
  243.     bFin = False
  244.     while k <= m:
  245.         lastPoint = newPoint
  246.         grad = derivative(func, lastPoint)
  247.         result.append(lastPoint)
  248.         gradLen2 = grad.SquaredLength()
  249.         if gradLen2 < eps * eps:
  250.             return result
  251.         if (k == 0):
  252.             grad *= -1
  253.         else:
  254.             beta = gradLen2 / prevGradLen2
  255.             grad *= beta - 1
  256.         prevGradLen2 = gradLen2
  257.         minn = dixotomMin(func, lastPoint, grad)
  258.         newPoint = lastPoint + grad * minn
  259.         norm = (newPoint - lastPoint).Length()
  260.         if np.absolute(func(newPoint.x, newPoint.y) - func(lastPoint.x, lastPoint.y)) < eps and norm < eps:
  261.             if bFin == False:
  262.                 bFin = True
  263.             else:
  264.                 return result
  265.         k += 1
  266.     return result
  267.  
  268.  
  269. # def function(x, y):
  270. # return 10 * x * x + y * y
  271. def function(x, y):
  272.     return x * x + y * y + 2 * x * y
  273.  
  274.  
  275. trajectory = gradient(function, Vec2(1, 5), constantMethod(0.001))
  276. print(trajectory[len(trajectory) - 1])
  277. print(len(trajectory))
  278. plot_3d_with_trajectory(function, trajectory, -20, 20, -20, 20, 10, "Constant (X, Y)")
  279.  
  280. trajectory = gradient(function, Vec2(1, 5), splitMethod(0.1, 0.1, 0.1))
  281. print(trajectory[len(trajectory) - 1])
  282. print(len(trajectory))
  283. plot_3d_with_trajectory(function, trajectory, -20, 20, -20, 20, 10, "Split (X, Y)")
  284.  
  285. trajectory = gradient(function, Vec2(1, 5), goldMethod())
  286. print(trajectory[len(trajectory) - 1])
  287. print(len(trajectory))
  288. plot_3d_with_trajectory(function, trajectory, -20, 20, -20, 20, 10, "Gold (X, Y)")
  289.  
  290. trajectory = gradient(function,Vec2(1, 5), fibonacciMethod())
  291. print(trajectory[len(trajectory) - 1])
  292. print(len(trajectory))
  293. plot_3d_with_trajectory(function, trajectory, -20, 20, -20, 20, 10, "Fibonacci (X, Y)")
  294.  
  295. trajectory = gradientFletcherReeves(function, Vec2(1, 5))
  296. print(trajectory[len(trajectory) - 1])
  297. print(len(trajectory))
  298. plot_3d_with_trajectory(function, trajectory, -20, 20, -20, 20, 10, "FletcherReeves (X, Y)")
  299.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement