2023 華樹杯モデリングのアイデア - ケース: 粒子群の最適化

# 0 コンテストのアイデア

(コンテストの質問が出たらすぐに CSDN で共有します)

https://blog.csdn.net/dc_sinor?type=blog

1 粒子群アルゴリズムとは何ですか?

Particle Swarm Optimization (PSO) は、鳥や魚の採餌行動を模倣して開発された進化的アルゴリズムです。そのコンセプトはシンプルで、プログラムと実現が容易で、操作効率が高く、パラメータが比較的少ないため、広く使用されています。粒子群最適化アルゴリズムは1995年に提案され、24年(2019年)の歴史があります。
  
  PSO アルゴリズムにおける各粒子の位置は、求められる問題に対する解決策の候補を表します。空間内の各粒子の位置の質は、求める問題における粒子の位置の適合値によって決まります。次の世代における各粒子の位置は、この世代における位置とそれ自体の速度ベクトルによって決定され、その速度によって粒子の各飛行の方向と距離が決まります。飛行中、粒子はそれが行った最適な位置 P を記録し、グループはまた、グループが行った最適な位置 G を更新します。粒子の飛行速度は、粒子の現在位置、粒子自体が行った最適な位置、グループが行った最適な位置、およびこのときの粒子の速度によって決まります。

ここに画像の説明を挿入

2 例を挙げてみましょう

ここに画像の説明を挿入
湖の中に 2 人の人間がいて、互いに通信でき、自分たちの位置の最低点を検出できます。初期位置は上図の通りですが、右側は比較的深いので左側の人がボートを右に動かします。

ここに画像の説明を挿入

左側が暗くなったので、右側の人がボートを左側に動かします

このプロセスを最後まで繰り返し、最終的に 2 つのボートが合流します。

ここに画像の説明を挿入
局所的な最適解が得られ
ここに画像の説明を挿入、各個人は粒子として表現されます。ある瞬間における各個体の位置をx(t)、方向をv(t)で表す。

ここに画像の説明を挿入

p(t) は時刻 t における個体 x の最適解、g(t) は時刻 t におけるすべての個体の最適解、v(t) は時刻 t における個体の方向、x(t) は時間 t における個々の位置

ここに画像の説明を挿入

上の図に示すように、次の位置は x、p、g によって決定されます。

ここに画像の説明を挿入

集団内の粒子は、自身と集団の履歴情報から継続的に学習することで、問題に対する最適な解決策を見つけることができます。

3はまだ一例です

粒子群最適化は、鳥の採餌行動から派生したアルゴリズムです。さて、私たちの主人公は鳥の群れに置き換えられます。
ここに画像の説明を挿入

小鳥たちの目的はシンプルで、この地域で一番餌が豊富な場所を見つけて、落ち着いて回復することです。この場所での彼らの捜索戦略は次のとおりです。
  1. 各鳥はランダムに場所を見つけ、その場所にある餌の量を評価します。
  2. 鳥たちは一斉に会議を開き、餌が最も多い場所を定住候補地点Gとして選択する。
  3. 各鳥は自分たちの旅を振り返り、最も餌が豊富な場所 P を覚えています。
  4. より多くの餌のある場所を見つけるために、それぞれの鳥はGに向かって飛んでいきます。しかし、それが選択の難しさによるものなのか、Pへの懐かしさによるものなのか、それともGへの不信感によるものなのかはわかりません。実際にはPに向かって飛んでいます。 、G に向かって飛んでいるのか、P に向かって飛んでいるのかはわかりません。
  5. 再び会議の時間です。鳥が探すのをやめると決めた場合は、現在の G を選択して落ち着きます。そうでない場合は、2->3->4->5 を続けて生息地を見つけます。

ここに画像の説明を挿入

上図で説明した戦略 4 の場合、鳥は A 点におり、G 点は鳥が最も多くの餌を見つけた場所、P 点は鳥が最も多くの餌を訪れた場所です。V は現在の飛行速度 (速度はベクトルであり、方向と大きさを表します) で、今度は P と G に向かって飛ぶことを決定します。ただし、これは仏教の鳥であり、どの程度飛ぶかは状況によって異なります。速度 V がなければ点 B に飛行するはずです。速度 V の影響を受けて、その合成速度により最終的に次の目的地である点 C に飛行します。C が P より優れている場合は C が次の P となり、C が G より優れている場合は次の G になります。

アルゴリズム処理

ここに画像の説明を挿入

アルゴリズムの実装

ここでは、上級生が Python を使用して粒子群ソリューション関数の最適解をデモンストレーションします。

ここに画像の説明を挿入

import numpy as np
import matplotlib.pyplot as plt
import random


# 定义“粒子”类
class parti(object):
    def __init__(self, v, x):
        self.v = v                    # 粒子当前速度
        self.x = x                    # 粒子当前位置
        self.pbest = x                # 粒子历史最优位置

class PSO(object):
    def __init__(self, interval, tab='min', partisNum=10, iterMax=1000, w=1, c1=2, c2=2):
        self.interval = interval                                            # 给定状态空间 - 即待求解空间
        self.tab = tab.strip()                                              # 求解最大值还是最小值的标签: 'min' - 最小值;'max' - 最大值
        self.iterMax = iterMax                                              # 迭代求解次数
        self.w = w                                                          # 惯性因子
        self.c1, self.c2 = c1, c2                                           # 学习因子
        self.v_max = (interval[1] - interval[0]) * 0.1                      # 设置最大迁移速度
        #####################################################################
        self.partis_list, self.gbest = self.initPartis(partisNum)                 # 完成粒子群的初始化,并提取群体历史最优位置
        self.x_seeds = np.array(list(parti_.x for parti_ in self.partis_list))    # 提取粒子群的种子状态 ###
        self.solve()                                                              # 完成主体的求解过程
        self.display()                                                            # 数据可视化展示

    def initPartis(self, partisNum):
        partis_list = list()
        for i in range(partisNum):
            v_seed = random.uniform(-self.v_max, self.v_max)
            x_seed = random.uniform(*self.interval)
            partis_list.append(parti(v_seed, x_seed))
        temp = 'find_' + self.tab
        if hasattr(self, temp):                                             # 采用反射方法提取对应的函数
            gbest = getattr(self, temp)(partis_list)
        else:
            exit('>>>tab标签传参有误:"min"|"max"<<<')
        return partis_list, gbest

    def solve(self):
        for i in range(self.iterMax):
            for parti_c in self.partis_list:
                f1 = self.func(parti_c.x)
                # 更新粒子速度,并限制在最大迁移速度之内
                parti_c.v = self.w * parti_c.v + self.c1 * random.random() * (parti_c.pbest - parti_c.x) + self.c2 * random.random() * (self.gbest - parti_c.x)
                if parti_c.v > self.v_max: parti_c.v = self.v_max
                elif parti_c.v < -self.v_max: parti_c.v = -self.v_max
                # 更新粒子位置,并限制在待解空间之内
                if self.interval[0] <= parti_c.x + parti_c.v <=self.interval[1]:
                    parti_c.x = parti_c.x + parti_c.v
                else:
                    parti_c.x = parti_c.x - parti_c.v
                f2 = self.func(parti_c.x)
                getattr(self, 'deal_'+self.tab)(f1, f2, parti_c)             # 更新粒子历史最优位置与群体历史最优位置

    def func(self, x):                                                       # 状态产生函数 - 即待求解函数
        value = np.sin(x**2) * (x**2 - 5*x)
        return value

    def find_min(self, partis_list):                                         # 按状态函数最小值找到粒子群初始化的历史最优位置
        parti = min(partis_list, key=lambda parti: self.func(parti.pbest))
        return parti.pbest

    def find_max(self, partis_list):
        parti = max(partis_list, key=lambda parti: self.func(parti.pbest))   # 按状态函数最大值找到粒子群初始化的历史最优位置
        return parti.pbest

    def deal_min(self, f1, f2, parti_):
        if f2 < f1:                          # 更新粒子历史最优位置
            parti_.pbest = parti_.x
        if f2 < self.func(self.gbest):
            self.gbest = parti_.x            # 更新群体历史最优位置

    def deal_max(self, f1, f2, parti_):
        if f2 > f1:                          # 更新粒子历史最优位置
            parti_.pbest = parti_.x
        if f2 > self.func(self.gbest):
            self.gbest = parti_.x            # 更新群体历史最优位置

    def display(self):
        print('solution: {}'.format(self.gbest))
        plt.figure(figsize=(8, 4))
        x = np.linspace(self.interval[0], self.interval[1], 300)
        y = self.func(x)
        plt.plot(x, y, 'g-', label='function')
        plt.plot(self.x_seeds, self.func(self.x_seeds), 'b.', label='seeds')
        plt.plot(self.gbest, self.func(self.gbest), 'r*', label='solution')
        plt.xlabel('x')
        plt.ylabel('f(x)')
        plt.title('solution = {}'.format(self.gbest))
        plt.legend()
        plt.savefig('PSO.png', dpi=500)
        plt.show()
        plt.close()


if __name__ == '__main__':
    PSO([-9, 5], 'max')

効果
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/math_assistant/article/details/132047920