|
| 1 | +# !usr/bin/env python |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | +# Time : 2022/10/19 20:32 |
| 4 | +# @Author : LucXiong |
| 5 | +# @Project : Model |
| 6 | +# @File : GSA.py |
| 7 | + |
| 8 | +''' |
| 9 | +Ref:https://github.com/ravexina/GSA/blob/master/GSA.py |
| 10 | +Ref:Rashedi E., Nezamabadi-Pour H., Saryazdi S. GSA: A Gravitational Search Algorithm[J]. Information Sciences, 2009, 179(13): 2232-48. |
| 11 | +''' |
| 12 | + |
| 13 | +import numpy as np |
| 14 | +import matplotlib.pyplot as plt |
| 15 | +import math |
| 16 | +import test_function |
| 17 | + |
| 18 | +class GSA(): |
| 19 | + def __init__(self, func, n_dim=None, pop=40, max_iter=150, lb=-1e5, ub=1e5, alpha=0.1, G=0.9): |
| 20 | + self.func = func |
| 21 | + self.alpha = alpha |
| 22 | + self.G = G |
| 23 | + self.pop = pop # number of particles |
| 24 | + self.n_dim = n_dim # dimension of particles, which is the number of variables of func |
| 25 | + self.max_iter = max_iter # max iter |
| 26 | + |
| 27 | + self.lb, self.ub = np.array(lb) * np.ones(self.n_dim), np.array(ub) * np.ones(self.n_dim) |
| 28 | + assert self.n_dim == len(self.lb) == len(self.ub), 'dim == len(lb) == len(ub) is not True' |
| 29 | + assert np.all(self.ub > self.lb), 'upper-bound must be greater than lower-bound' |
| 30 | + |
| 31 | + self.X = np.random.uniform(low=self.lb, high=self.ub, size=(self.pop, self.n_dim)) |
| 32 | + v_high = (self.ub - self.lb) # 速度设置为区间长度的一半 |
| 33 | + self.V = np.random.uniform(low=-v_high, high=v_high, size=(self.pop, self.n_dim)) # speed of particles |
| 34 | + self.Y = [self.func(self.X[i]) for i in range(self.pop)] # y = f(x) for all particles |
| 35 | + self.q = [1 for i in range(self.pop)] |
| 36 | + self.M = [1 for i in range(self.pop)] |
| 37 | + self.f = [[0 for j in range(self.n_dim)] for i in range(self.pop)] |
| 38 | + self.a = [[0 for j in range(self.n_dim)] for i in range(self.pop)] |
| 39 | + |
| 40 | + |
| 41 | + self.pbest_x = self.X.copy() # personal best location of every particle in history |
| 42 | + self.pbest_y = [np.inf for i in range(self.pop)] # best image of every particle in history |
| 43 | + self.gbest_x = self.pbest_x.mean(axis=0).reshape(1, -1) # global best location for all particles |
| 44 | + self.gbest_y = np.inf # global best y for all particles |
| 45 | + self.gbest_y_hist = [] # gbest_y of every iteration |
| 46 | + self.update_gbest() |
| 47 | + |
| 48 | + def cal_q_M(self): |
| 49 | + best = np.min(self.Y) |
| 50 | + worst = np.max(self.Y) |
| 51 | + self.q = (self.Y - worst) / best - worst |
| 52 | + self.M = self.q / sum(self.q) |
| 53 | + |
| 54 | + def cal_f(self): |
| 55 | + for i in range(self.pop): |
| 56 | + f = None |
| 57 | + for j in range(self.pop): |
| 58 | + if j != i: |
| 59 | + dividend = float(self.M[i] * self.M[j]) |
| 60 | + temp = self.X[i] - self.X[j] |
| 61 | + sum_temp = [k**2 for k in temp] |
| 62 | + divisor = math.sqrt(sum(sum_temp)) + np.finfo('float').eps |
| 63 | + if f is None: |
| 64 | + f = self.G * (dividend / divisor) * (self.X[j] - self.X[i]) |
| 65 | + else: |
| 66 | + f = f + self.G * (dividend / divisor) * (self.X[j] - self.X[i]) |
| 67 | + |
| 68 | + self.f[i] = np.random.uniform(0, 1) * f |
| 69 | + |
| 70 | + def update_gbest(self): |
| 71 | + idx_min = self.Y.index(min(self.Y)) |
| 72 | + if self.gbest_y > self.Y[idx_min]: |
| 73 | + self.gbest_x = self.X[idx_min, :].copy() |
| 74 | + self.gbest_y = self.Y[idx_min] |
| 75 | + |
| 76 | + def run(self): |
| 77 | + for iteration in range(self.max_iter): |
| 78 | + |
| 79 | + self.Y = [self.func(self.X[i]) for i in range(self.pop)] |
| 80 | + self.cal_q_M() |
| 81 | + self.G = self.G * np.e ** (- self.alpha * (iteration / self.max_iter)) |
| 82 | + self.cal_f() |
| 83 | + self.a = [self.f[i]/self.M[i] for i in range(self.pop)] |
| 84 | + self.V = (np.random.uniform(0, 1) * self.V) + self.a |
| 85 | + self.update_gbest() |
| 86 | + self.X = self.X + self.V |
| 87 | + self.gbest_y_hist.append(self.gbest_y) |
| 88 | + # print(iteration, self.gbest_x, self.gbest_y) |
| 89 | + self.best_x, self.best_y = self.gbest_x, self.gbest_y |
| 90 | + return self.best_x, self.best_y |
| 91 | + |
| 92 | + |
| 93 | +def demo_func(args): |
| 94 | + |
| 95 | + x, y = args[0], args[1] |
| 96 | + a = 1 |
| 97 | + b = 100 |
| 98 | + return (a - x) ** 2 + b * (y - x ** 2) ** 2 |
| 99 | + |
| 100 | + |
| 101 | +if __name__ == '__main__': |
| 102 | + n_dim = 2 |
| 103 | + lb = [0 for i in range(n_dim)] |
| 104 | + ub = [1 for i in range(n_dim)] |
| 105 | + # demo_func = test_function.fu2 |
| 106 | + pop_size = 20 |
| 107 | + max_iter = 100 |
| 108 | + res = [] |
| 109 | + for i in range(100): |
| 110 | + pso = GSA(func=demo_func, n_dim=n_dim, pop=pop_size, max_iter=max_iter, lb=lb, ub=ub) |
| 111 | + best_x, bext_y = pso.run() |
| 112 | + print(f'{i}: {demo_func(pso.gbest_x)}\t{pso.gbest_x}') |
| 113 | + res.append(bext_y) |
| 114 | + print(sum(res)/len(res)) |
| 115 | + print(np.std(res)) |
| 116 | + # plt.plot(pso.gbest_y_hist) |
| 117 | + # |
| 118 | + # plt.show() |
0 commit comments