## Differential Evolution Solver Class ## Based on algorithms developed by Dr. Rainer Storn & Kenneth Price ## Written By: Lester E. Godwin ## PushCorp, Inc. ## Dallas, Texas ## 972-840-0208 x102 ## godwin@pushcorp.com ## Created: 6/8/98 ## Last Modified: 6/8/98 ## Revision: 1.0 ## ## Ported To Python From C++ July 2002 ## Ported To Python By: James R. Phillips ## Birmingham, Alabama USA ## zunzun@zunzun.com import psyco psyco.full() true = 1 false = 0 stBest1Exp = 0 stRand1Exp = 1 stRandToBest1Exp = 2 stBest2Exp = 3 stRand2Exp = 4 stBest1Bin = 5 stRand1Bin = 6 stRandToBest1Bin = 7 stBest2Bin = 8 stRand2Bin = 9 #/*------Constants for self.RandomUniform()---------------------------------------*/ SEED = 3 IM1 = 2147483563 IM2 = 2147483399 AM = (1.0/IM1) IMM1 = (IM1-1) IA1 = 40014 IA2 = 40692 IQ1 = 53668 IQ2 = 52774 IR1 = 12211 IR2 = 3791 NTAB = 32 NDIV = (1+IMM1/NTAB) EPS = 1.2e-7 RNMX = (1.0-EPS) class DESolver: def __init__(self, dim, popSize): self.nDim = dim self.nPop = popSize self.generations = 0 self.strategy = stRand1Exp self.scale = 0.7 self.probability = 0.5 self.bestEnergy = 0.0 self.trialSolution = [0.0] * self.nDim self.bestSolution = [0.0] * self.nDim self.popEnergy = [0.0] * self.nPop self.population = [0.0] * (self.nPop * self.nDim) self.iv = [0] * NTAB self.idum = 0 self.idum2 = 123456789 self.iy = 0 self.randCount = 0 def Dimension(self): return self.nDim def Population(self): return self.nPop def Energy(self): return self.bestEnergy def Solution(self): return self.bestSolution def Generations(self): return self.generations def Setup(self, min, max, deStrategy, diffScale, crossoverProb): self.strategy = deStrategy self.scale = diffScale self.probability = crossoverProb for i in range(self.nPop): for j in range(self.nDim): self.population[i*self.nDim+j] = self.RandomUniform(min[j],max[j]) self.popEnergy[i] = 1.0E20 for i in range(self.nDim): self.bestSolution[i] = 0.0 if self.strategy == stBest1Exp: self.calcTrialSolution = self.Best1Exp elif self.strategy == stRand1Exp: self.calcTrialSolution = self.Rand1Exp elif self.strategy == stRandToBest1Exp: self.calcTrialSolution = self.RandToBest1Exp elif self.strategy == stBest2Exp: self.calcTrialSolution = self.Best2Exp elif self.strategy == stRand2Exp: self.calcTrialSolution = self.Rand2Exp elif self.strategy == stBest1Bin: self.calcTrialSolution = self.Best1Bin elif self.strategy == stRand1Bin: self.calcTrialSolution = self.Rand1Bin elif self.strategy == stRandToBest1Bin: self.calcTrialSolution = self.RandToBest1Bin elif self.strategy == stBest2Bin: self.calcTrialSolution = self.Best2Bin else: #self.strategy == stRand2Bin: self.calcTrialSolution = self.Rand2Bin def Solve(self, maxGenerations): self.bestEnergy = 1.0E20 bAtSolution = false for generation in range(maxGenerations): if bAtSolution == true: break for candidate in range(self.nPop): self.calcTrialSolution(candidate) trialEnergy, bAtSolution = self.EnergyFunction(self.trialSolution, bAtSolution) if trialEnergy < self.popEnergy[candidate]: # New low for this candidate self.popEnergy[candidate] = trialEnergy for copyCount in range(self.nDim): self.population[candidate*self.nDim + copyCount] = self.trialSolution[copyCount] # Check if all-time low if trialEnergy < self.bestEnergy: self.bestEnergy = trialEnergy for z in range(self.nDim): self.bestSolution[z] = self.trialSolution[z] self.generations = generation return bAtSolution def Best1Exp(self, candidate): ##print "Best1Exp" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,0,0,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.bestSolution[n] \ + self.scale * (self.population[r1*self.nDim+n] - self.population[r2*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def Rand1Exp(self, candidate): ##print "Rand1Exp" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,1,0,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.population[r1*self.nDim+n] + self.scale * (self.population[r2*self.nDim+n] - self.population[r3*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def RandToBest1Exp(self, candidate): ##print "RandToBest1Exp" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,0,0,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] += self.scale * (self.bestSolution[n] - self.trialSolution[n]) \ + self.scale * (self.population[r1*self.nDim+n] - self.population[r2*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def Best2Exp(self, candidate): ##print "Best2Exp" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,1,1,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.bestSolution[n] + \ self.scale * (self.population[r1*self.nDim+n] + \ self.population[r2*self.nDim+n] - \ self.population[r3*self.nDim+n] - \ self.population[r4*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def Rand2Exp(self, candidate): ##print "Rand2Exp" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,1,1,1) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.population[r1*self.nDim+n] + \ self.scale * (self.population[r2*self.nDim+n] + \ self.population[r3*self.nDim+n] - \ self.population[r4*self.nDim+n] - \ self.population[r5*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def Best1Bin(self, candidate): ##print "Best1Bin" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,0,0,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.bestSolution[n] + \ self.scale * (self.population[r1*self.nDim+n] - \ self.population[r2*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def Rand1Bin(self, candidate): ##print "Rand1Bin" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,1,0,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.population[r1*self.nDim+n] + \ self.scale * (self.population[r2*self.nDim+n] -\ self.population[r3*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def RandToBest1Bin(self, candidate): ##print "RandToBest1Bin" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,0,0,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] += self.scale * (self.bestSolution[n] - self.trialSolution[n]) + \ self.scale * (self.population[r1*self.nDim+n] - \ self.population[r2*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def Best2Bin(self, candidate): ##print "Best2Bin" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,1,1,0) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.bestSolution[n] + \ self.scale * (self.population[r1*self.nDim+n] + \ self.population[r2*self.nDim+n] - \ self.population[r3*self.nDim+n] - \ self.population[r4*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def Rand2Bin(self, candidate): ##print "Rand2Bin" r1,r2,r3,r4,r5 = self.SelectSamples(candidate, 1,1,1,1,1) n = int(self.RandomUniform(0.0,float(self.nDim))) for copyCount in range(self.nDim): self.trialSolution[copyCount] = self.population[candidate*self.nDim+copyCount] i = 0 while(1): if self.RandomUniform(0.0, 1.0) >= self.probability or i == self.nDim: break self.trialSolution[n] = self.population[r1*self.nDim+n] + \ self.scale * (self.population[r2*self.nDim+n] + \ self.population[r3*self.nDim+n] - \ self.population[r4*self.nDim+n] - \ self.population[r5*self.nDim+n]) n = (n + 1) % self.nDim i += 1 def SelectSamples(self, candidate, r1, r2, r3, r4, r5): if r1: while(1): r1 = int(self.RandomUniform(0.0, float(self.nPop))) if r1 != candidate: break if r2: while(1): r2 = int(self.RandomUniform(0.0, float(self.nPop))) if r2 != candidate and r2 != r1: break if r3: while(1): r3 = int(self.RandomUniform(0.0, float(self.nPop))) if r3 != candidate and r3 != r1 and r3 != r2: break if r4: while(1): r4 = int(self.RandomUniform(0.0, float(self.nPop))) if r4 != candidate and r4 != r1 and r4 != r2 and r4 != r3: break if r5: while(1): r5 = int(self.RandomUniform(0.0, float(self.nPop))) if r5 != candidate and r5 != r1 and r5 != r2 and r5 != r3 and r5 != r4: break return r1, r2, r3, r4, r5 def RandomUniform(self, minValue, maxValue): if self.iy == 0: self.idum = SEED if self.idum <= 0: if -self.idum < 1: self.idum = 1 else: self.idum = -self.idum self.idum2 = self.idum for j in range(NTAB+7, -1, -1): k = self.idum / IQ1 self.idum = IA1 * (self.idum - k*IQ1) - k*IR1 if self.idum < 0: self.idum += IM1 if j < NTAB: self.iv[j] = self.idum self.iy = self.iv[0] k = self.idum / IQ1 self.idum = IA1 * (self.idum - k*IQ1) - k*IR1 if self.idum < 0: self.idum += IM1 k = self.idum2 / IQ2 self.idum2 = IA2 * (self.idum2 - k*IQ2) - k*IR2 if self.idum2 < 0: self.idum2 += IM2 j = self.iy / NDIV self.iy = self.iv[j] - self.idum2 self.iv[j] = self.idum if self.iy < 1: self.iy += IMM1 result = AM * self.iy if result > RNMX: result = RNMX else: result = minValue + result * (maxValue - minValue) self.randCount += 1 return result