diff --git a/PSO.py b/PSO.py new file mode 100644 index 0000000..937c35a --- /dev/null +++ b/PSO.py @@ -0,0 +1,96 @@ +import random +import Problem +import numpy as np + +# This class contains the code of the Particles in the swarm +class Particle: + def __init__(self,problem,c1,c2,w): + self.problem = problem + self.c1 = c1 + self.c2 = c2 + self.w = w + self.position = problem.generate_random_ponit() + self.velocity = np.random.uniform(0,1,problem.n) + self.personal_best = self.position.copy() + self.personal_best_value = 0 + + def update_positions(self): + #Update the position: + #position = position + velocity + self.position = self.position + self.velocity + return + + def update_velocities(self, golbal_best): + #Update the velocity: + #velocity = w * velocity + c1 * r1 * (golbal_best - position) + # + c2 * r2 * (personal_best - position). + for i in range(self.problem.n): + r1 = np.random.rand() + r2 = np.random.rand() + + #social part + social = self.c1 * r1 * (golbal_best[i] - self.position[i]) + + #recognition part + cognitive = self.c2 * r2 * (self.personal_best[i] - self.position[i]) + + self.velocity[i] = (self.w * self.velocity[i]) + social + cognitive + return + + +# This class contains the particle swarm optimization algorithm +class ParticleSwarmOptimizer: + def __init__(self,problem,swarmSize,iterations,c1,c2,w): + self.problem = problem + self.swarmSize = swarmSize + self.iterations = iterations + self.swarm = [] + self.generate_init_swarms(c1,c2,w) + + def generate_init_swarms(self,c1,c2,w): + for i in range(self.swarmSize): + #Initialize particle + particle = Particle(self.problem,c1,c2,w) + particle.personal_best_value = self.fitness_function(particle.personal_best) + self.swarm.append(particle) + self.update_global_best() + + + #update the global best particle + def update_global_best(self): + self.global_best = self.swarm[0].position + self.global_best_value = self.swarm[0].personal_best_value + for j in range(self.swarmSize): + + #If the personal best value value is better than the global best + # value Set current personal best value as the new global best + personal_best_value = self.swarm[j].personal_best_value + if personal_best_value < self.global_best_value: + self.global_best = self.swarm[j].personal_best + self.global_best_value = personal_best_value + + #Update the personal best positions + def update_personal_best(self): + for l in range(self.swarmSize): + + #If the fitness value is better than the personal best fitness + # value Set current value as the personal best + personal_best_value = self.swarm[l].personal_best_value + current_value = self.fitness_function(self.swarm[l].position) + if current_value < personal_best_value: + self.swarm[l].personal_best = self.swarm[l].position + self.swarm[l].personal_best_value = current_value + + def fitness_function(self,position): + return self.problem.get_value(position) + + def optimize(self): + for i in range(self.iterations ): + for k in range(self.swarmSize): + #Update velocitie of each paricle + self.swarm[k].update_velocities(self.global_best) + #Update position of each paricle + self.swarm[k].update_positions() + self.update_personal_best() + self.update_global_best() + return self.global_best \ No newline at end of file diff --git a/Problem.py b/Problem.py new file mode 100644 index 0000000..c9ec320 --- /dev/null +++ b/Problem.py @@ -0,0 +1,122 @@ +from abc import ABC,abstractmethod +from enum import Enum +import numpy as np +import math +#Problem interface for all test functions +class IProblem(ABC): + n = 0 + lbound = 0 + ubound = 0 + + def generate_random_ponit(self): + return np.random.uniform(self.lbound,self.ubound,size=(self.n)) + + def generate_random_ponits(self,count): + return np.random.uniform(self.lbound,self.ubound,size=(count,self.n)) + + @abstractmethod + def get_value(self, swarm): + pass + +#an enum for test functions +class ProblemType(Enum): + Ackley = 1, + PowellSum = 2, + Booth = 3, + DropWave = 4, + SumSquares = 5, + Griewank = 6 + +#a factory class for generate test function class +class ProblemFactory: + @staticmethod + def generateProblem(type: ProblemType,n,lbound,ubound): + if type == ProblemType.Ackley: + return Ackley(n,lbound,ubound) + elif type == ProblemType.Booth: + return Booth(n,lbound,ubound) + elif type == ProblemType.PowellSum: + return PowellSum(n,lbound,ubound) + elif type == ProblemType.DropWave: + return DropWave(n,lbound,ubound) + elif type == ProblemType.SumSquares: + return SumSquares(n,lbound,ubound) + elif type == ProblemType.Griewank: + return Griewank(n,lbound,ubound) +class PowellSum(IProblem): + + def __init__(self,n,lbound,ubound): + self.n = n + self.lbound = lbound + self.ubound = ubound + + #get value for custom state + def get_value(self, swarm): + value = 0 + for i in range(self.n): + value = value + abs(swarm[i])**(i+2) + return value + +class Booth(IProblem): + def __init__(self,n,lbound,ubound): + self.n = n + self.lbound = lbound + self.ubound = ubound + + def get_value(self,swarm): + value = (swarm[0] + (2 * swarm[1]) - 7)**2 + ( (2 * swarm[0]) + swarm[1] - 5)**2 + return value + +class DropWave(IProblem): + def __init__(self,n,lbound,ubound): + self.n = n + self.lbound = lbound + self.ubound = ubound + + def get_value(self, swarm): + part1 = -1 * math.cos(12 * (math.sqrt((swarm[0]**2) + (swarm[1]**2)))) + part2 = (0.5 * (swarm[0]**2) + (swarm[1]**2)) + 2 + value = part1 / part2 + return value + +class Ackley(IProblem): + C1=20 + C2=.2 + C3=2*np.pi + def __init__(self,n,lbound,ubound): + self.n = n + self.lbound = lbound + self.ubound = ubound + def get_value(self, swarm): + part1 = -1. * self.C1 * np.exp( + -1. * self.C2 * np.sqrt((1./self.n) * sum(map(lambda nb: nb**2, swarm))) + ) + part2 = -1. * np.exp( + (1./self.n) * \ + sum(map(lambda nb: np.cos(self.C3 * nb), swarm)) + ) + return part1 + part2 + self.C1 + np.exp(1) + +class SumSquares(IProblem): + def __init__(self,n,lbound,ubound): + self.n = n + self.lbound = lbound + self.ubound = ubound + def get_value(self, swarm): + return np.sum(np.arange(1,self.n+1) * (swarm**2)) + +class Griewank(IProblem): + def __init__(self,n,lbound,ubound): + self.n = n + self.lbound = lbound + self.ubound = ubound + def get_value(self, swarm): + part1 = 0 + for i in range(len(swarm)): + part1 += swarm[i]**2 + part2 = 1 + for i in range(len(swarm)): + part2 *= math.cos(float(swarm[i]) / math.sqrt(i+1)) + return 1 + (float(part1)/4000.0) - float(part2) + + diff --git a/README.md b/README.md index c411466..ac1df71 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# PSO \ No newline at end of file +#Particle Swarm Optimization (PSO) with Python \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..5124963 --- /dev/null +++ b/main.py @@ -0,0 +1,17 @@ +import PSO +import Problem +import numpy as np + + +problem = Problem.ProblemFactory.generateProblem( + Problem.ProblemType.Ackley, 5, -32, 32) + +iterations = 100 +swarmSize = 50 +c1 = 2 #social constant +c2 = 2 #cognative constant +w = 0.2 #constant inertia weight +pso = PSO.ParticleSwarmOptimizer(problem, swarmSize, iterations, c1, c2, w) +solution = pso.optimize() +print('global best position : {0} - global best value : {1}'.format(solution,problem.get_value(solution))) + \ No newline at end of file