Last active
December 7, 2018 08:38
-
-
Save arneschreuder/06d5a5befcf2c4fbe97d to your computer and use it in GitHub Desktop.
Global Best Particle Swarm Optimisation (PSO) in 100 lines of Python code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# IMPORTS | |
from random import uniform | |
from copy import deepcopy | |
# TUNABLE CONSTANTS | |
swarm_size = 10 | |
w = 0.729844 | |
c1 = 1.496180 | |
c2 = 1.496180 | |
dimensions = 5 | |
domain = {"min": -30, "max": 30} | |
iterations = 1000 | |
runs = 1 | |
pso = None | |
# VARIABLES | |
class Particle: | |
position = [None]*dimensions | |
velocity = [None]*dimensions | |
fitness = float("inf") | |
pbest = [None]*dimensions | |
class Swarm: | |
particles = map(lambda particle: Particle(), [None]*swarm_size) | |
class GBestPSO: | |
swarm = Swarm() | |
gbest = None | |
def f(x): | |
# Quadratic problem | |
return sum(map(lambda x_i: x_i**2, x)) | |
def evaluate(): | |
global pso | |
for particle in pso.swarm.particles: | |
particle.fitness = f(particle.position) | |
pbestFitness = f(particle.pbest) | |
# Keep track of pbest and pbest fitness | |
particle.pbest = deepcopy(particle.position) if (particle.pbest == None) or (particle.fitness < pbestFitness) else particle.pbest | |
# Keep track of gbest and gbest fitness. | |
pso.gbest = deepcopy(particle) if (pso.gbest == None) or (particle.fitness < pso.gbest.fitness) else pso.gbest | |
def init(): | |
global pso | |
pso = GBestPSO() | |
# Place particles and evaluate on the spot | |
for particle in pso.swarm.particles: | |
particle.position = map(lambda j: uniform(domain["min"], domain["max"]), particle.position) | |
particle.velocity = map(lambda j: 0, particle.velocity) | |
particle.pbest = deepcopy(particle.position) | |
evaluate() | |
def update(): | |
global pso | |
for particle in pso.swarm.particles: | |
for j in range(dimensions): | |
r1 = uniform(0,1) | |
r2 = uniform(0,1) | |
# Velocity update rule | |
particle.velocity[j] = ( | |
w*particle.velocity[j] + # Velocity clamping via inertia weight | |
c1*r1*(particle.pbest[j] - particle.position[j]) + # Cognitive component | |
c2*r2*(pso.gbest.position[j] - particle.position[j]) # Social Component | |
) | |
# Position update rule | |
particle.position[j] = ( | |
particle.position[j] + | |
particle.velocity[j] | |
) | |
# Boundary clamping | |
particle.position[j] = max(domain["min"], particle.position[j]) | |
particle.position[j] = min(domain["max"], particle.position[j]) | |
def step(): | |
global pso | |
update() | |
evaluate() | |
def run(): | |
global pso | |
init() | |
for iteration in range(iterations): | |
step() | |
print pso.gbest.fitness | |
if __name__ == "__main__": | |
for runs in range(runs): | |
run() |
Fixed pbest not being updated correctly.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Urggh... was bored. So not the best way to combine OOP and Functional programming. But it does the job. I hope this can aid as a simple example for someone studying Artificial Intelligence paradigms such as PSO.