Python:PSO 聚集 <s> 并且代码仅在鼠标移动时有效</s>

Python: PSO clumping <s>and code working only when mouse moves</s>

我正在尝试制作一个简单的 PSO(粒子群优化)程序。

下面是我当前的代码,我一直在调整权重,结果发现 "optimization" 不起作用。

import random as ran
import math
# import threading as thr

import pygame as gm
# import pycuda as cuda
# import matplotlib.pyplot as plt

p_max = 10 # Maximum number of particles
rand_max = 100 # Maximum random vector value
# history = 10 # Number of iterations to record as history (including most current)
width = 600
height = 600

func_dict = {
            "sphere" : ( lambda x, y: ( (x-(width/2))**2 + (y-(height/2))**2 ) ),
            "booth" : ( lambda x, y: (((x-(width/2)) + 2*(y-(height/2)) - 7) ** 2) + ((2*(x-(width/2)) + (y-(height/2)) - 5) ** 2) ),
            "matyas" : ( lambda x, y: (0.26 * ((x-(width/2))**2 + (y-(height/2))**2) - 0.48*(x-(width/2))*(y-(height/2))) )
            } # (x-(width/2)) and (y-(height/2)) to shift the Zero to the display center
func = "sphere" # Choose function from func_dict

# Weights (0<w<1)
wLocal = 0.4 # Explore weight
wGlobal = 0.8 # Exploit weight
wRandom = 0.02 # Weight of random vector

global_best = [None, None, None] # Initial blank

class particle: # particles
    global global_best

    def __init__(self):
        global global_best
        global width, height
        global func_dict, func
        self.vel_x = 0
        self.vel_y = 0
        self.pos_x = ran.randint(0, width)
        self.pos_y = ran.randint(0, height)
        self.pos_z = func_dict[func](self.pos_x, self.pos_y)
        self.local_best = [self.pos_x, self.pos_y, self.pos_z]
        if (global_best[0] == None) or (global_best[1] == None) or (global_best[2] == None): # Is 1st particle
            global_best = self.local_best

    def update(self): # Update vectors
        global width, height
        global rand_max
        global wGlobal, wLocal, wRandom
        global global_best
        self.vel_x = (wGlobal * (global_best[0] - self.pos_x)) + (wLocal * (self.local_best[0] - self.pos_x)) + (wRandom * ran.randint(-rand_max, rand_max))
        self.vel_y = (wGlobal * (global_best[1] - self.pos_y)) + (wLocal * (self.local_best[1] - self.pos_y)) + (wRandom * ran.randint(-rand_max, rand_max))
        # self.pos_x = (self.pos_x + self.vel_x) % width
        # self.pos_y = (self.pos_y + self.vel_y) % height
        self.pos_x += self.vel_x
        self.pos_y += self.vel_y
        if self.pos_x < 0:
            self.pos_x = 0
        if self.pos_y < 0:
            self.pos_y = 0
        if self.pos_x > width:
            self.pos_x = width
        if self.pos_y > height:
            self.pos_y = height

        self.pos_z = func_dict[func](self.pos_x, self.pos_y)
        if self.pos_z < global_best[2]:
            global_best = [self.pos_x, self.pos_y, self.pos_z]

particles = [None for _ in range(p_max)]

def initialize():
    global_best = [None, None, None]
    for foo in range(p_max):
        particles[foo] = particle() # create new particles

# def dist(p1, p2): # distance
#     return(math.sqrt( ( (p1.pos_x - p2.pos_y)**2) + ((p1.pos_y - p2.pos_y)**2) ) )

# def update(this): # this = particle
#     this.vel_x = (wGlobal * (global_best[0] - this.pos_x)) + (wLocal * (this.local_best[0] - this.pos_x)) + (wRandom * ran.randint(0, rand_max))
#     this.vel_y = (wGlobal * (global_best[1] - this.pos_y)) + (wLocal * (this.local_best[1] - this.pos_y)) + (wRandom * ran.randint(0, rand_max))
#     # this.pos_x = (this.pos_x + this.vel_x) % width
#     # this.pos_y = (this.pos_y + this.vel_y) % height
#     this.pos_x += this.vel_x
#     this.pos_y += this.vel_y
#     if this.pos_x < 0:
#         this.pos_x = 0
#     if this.pos_y < 0:
#         this.pos_y = 0
#     if this.pos_x > width:
#         this.pos_x = width
#     if this.pos_y > height:
#         this.pos_y = height
#     # return this

# def update_multi(things): # things = list() of particles
#     these = things
#     for item in these:
#         item = update(item)
#     return these

gm.init()
main = gm.display.set_mode((width, height))
end_program = False
initialize()
main.fill((255, 255, 255))

while end_program == False:

    # main.fill((255, 255, 255)) #Comment/Uncomment to leave trace
    # plt.plot() # Plot functions

    for event in gm.event.get():
        if event.type == gm.QUIT:
            end_program = True

        for foo in range(len(particles)):
            particles[foo].update()

            gm.draw.circle(main, (0, 0, 0), (int(particles[foo].pos_x), int(particles[foo].pos_y)), 5, 0)

    gm.display.flip()

问题一:程序只在鼠标移动时运行
我不确定为什么,但该程序仅在几次迭代中运行得相当快,但似乎只是在之后停止,但在移动鼠标时继续。

问题 2:粒子似乎停留在局部
当我四处移动鼠标时,它有点跑。出现的是第二个 # main.fill((255, 255, 255)) 未注释时留下的痕迹。在没有鼠标移动的情况下程序停止之前的第一个初始痕迹似乎更加分散,我不确定这是全局变量还是随机数在起作用。

编辑:我通过取消缩进修复了程序仅在鼠标移动时运行的问题:

    for foo in range(len(particles)):
        particles[foo].update()

        gm.draw.circle(main, (0, 0, 0), (int(particles[foo].pos_x), int(particles[foo].pos_y)), 5, 0)

然而,粒子似乎仍然几乎没有离开自己的位置,在局部振荡。

感谢 Marius 解决了问题 1。我通过简单地将 update 放在 event 循环之外来修复它。

问题 2 已通过添加我忘记的本地更新得到修复。

if self.pos_z < global_best[2]: # This was not forgotten
            global_best = [self.pos_x, self.pos_y, self.pos_z]
if self.pos_z < local_best[2]: # This was forgotten
            local_best = [self.pos_x, self.pos_y, self.pos_z]