& }9 z4 q4 _& ]& g/ F; y% Q9 Fimport random. O! Z2 e s( K
import math 4 h3 Z/ `7 }1 Q( \- _, Nfrom operator import itemgetter1 E8 ]3 Q/ v; c! m
' T, B% c! W/ P' ^2 f' Y( K
class Gene:. N" X. X6 s$ w6 F" [7 g" }
''' / x# b4 ~4 O* ]/ j This is a class to represent individual(Gene) in GA algorithom 2 w/ m* p+ \/ X/ m5 |1 |' a each object of this class have two attribute: data, size3 o5 `2 f) w* \, Z
'''- g+ s3 ~$ t3 X! x6 P- A) B
def __init__(self,**data):! n$ n, x( A5 s6 i+ Z
self.__dict__.update(data) % T* H% o+ a8 h$ S self.size = len(data['data'])#length of gene$ H) t0 U m; g
" b* M: h; a& n) v. I, P 0 O9 B) G/ W0 y1 z: H8 qclass GA:7 D' t2 M4 {3 ]1 Y- ]+ t n
''' + e. j! c* i% Z- g- g This is a class of GA algorithm. % ^. U$ C o0 }9 q. A1 q' d ''': }% c* ]9 K# o, R [
def __init__(self,parameter):9 O- {% Z6 V {6 [! {
''' " o# [8 o& r/ T5 c) D Initialize the pop of GA algorithom and evaluate the pop by computing its' fitness value . 8 G' `$ p' P- Z [+ N3 b, ?4 w The data structure of pop is composed of several individuals which has the form like that: 0 e7 j4 H- t+ J; X' {. J" H6 v2 R- y3 G8 d# c* x. y( j/ L
{'Gene':a object of class Gene, 'fitness': 1.02(for example)}+ K8 A4 \, Q/ p; X
Representation of Gene is a list: [b s0 u0 sita0 s1 u1 sita1 s2 u2 sita2]4 \3 J/ k( ]% R: y7 |1 I- q
/ F/ d3 R2 ]6 w '''9 }6 C, A. T) U) V+ h" @
#parameter = [CXPB, MUTPB, NGEN, popsize, low, up] 3 z9 V$ [% z6 O- U- U1 W x self.parameter = parameter ) W& B. s/ C8 X9 V: S, E$ N8 Z; y" h2 j2 ?; m, j: X& @" a; x' ~
low = self.parameter[4]/ \3 Z1 A! D; q9 ~8 x
up = self.parameter[5]2 u% n y. a4 S
( p" m' G8 \# a& V self.bound = []( z( r* u8 m" P* W2 {
self.bound.append(low)# N( c: B, z1 Q
self.bound.append(up) & W3 [: H# N8 H ( W1 I& K6 x* t+ F/ @6 e pop = [] - X) k% c) l) u, D for i in range(self.parameter[3]):2 I. n9 b3 e- b
geneinfo = [] ' v! {9 |; |# [' [ \! a for pos in range(len(low)): + A1 T, P( h) ]3 G0 a$ K geneinfo.append(random.uniform(self.bound[0][pos], self.bound[1][pos]))#initialise popluation & q% a( r/ R0 }. c8 @6 g3 N% V/ W: L( M0 h) i( D
fitness = evaluate(geneinfo)#evaluate each chromosome- Z* M8 z1 G) |2 H$ k% V2 g5 U
pop.append({'Gene':Gene(data = geneinfo), 'fitness':fitness})#store the chromosome and its fitness9 g0 C9 B$ I8 u* Q( r# K
{/ V$ m6 w( k+ y& x self.pop = pop6 [. y4 F) k# \2 y6 c
self.bestindividual = self.selectBest(self.pop)#store the best chromosome in the population ! g5 L% h n/ ^7 ], G2 a- T' w0 M# T$ Q6 f+ n" O2 ^. Q/ o% A
def selectBest(self, pop):) `% G4 h/ n) K4 s
''' 9 s) M# g& | Q select the best individual from pop 1 e: A3 A9 M% g9 s2 B- C '''0 e, q% i) F+ G
s_inds = sorted(pop, key = itemgetter("fitness"), reverse = False)1 N7 o& @1 x! p% E4 q
return s_inds[0] : A& X2 ` a8 }$ t 2 B2 ?. d0 H8 H" y6 i5 c1 \: J& A def selection(self, individuals, k): " h" Q- c' @/ w+ X" Z '''% F5 R2 I. U# q& d, Y w( e0 |( ?
select two individuals from pop ! s& O1 z* p3 t( q3 v; F ''' 9 j, V5 r7 x+ D" ? s_inds = sorted(individuals, key = itemgetter("fitness"), reverse=True)#sort the pop by the reference of 1/fitness " ~) N: ~! Q+ ]$ M" {8 V sum_fits = sum(1/ind['fitness'] for ind in individuals) #sum up the 1/fitness of the whole pop % S1 r, J* Z! O/ g" k: | f2 Y * H+ L/ C1 I5 B% e- g" Y7 w chosen = [] % K* |. n2 q: E# H for i in xrange(k): 4 S6 F4 Z. d) \0 c/ ]9 }) e u = random.random() * sum_fits#randomly produce a num in the range of [0, sum_fits]3 R4 F2 ?: D/ P7 m& e! o9 s
sum_ = 0: i: A( Y9 d5 C T1 [ m1 u {4 Y
for ind in s_inds:! O& f$ L8 I+ g" F& K7 [1 D- K. d e
sum_ += 1/ind['fitness']#sum up the 1/fitness 1 r: f" A- n6 E/ Q$ ~7 Y if sum_ > u: ! U5 M$ j7 i# u8 ]$ W #when the sum of 1/fitness is bigger than u, choose the one, which means u is in the range of [sum(1,2,...,n-1),sum(1,2,...,n)] and is time to choose the one ,namely n-th individual in the pop. }0 W$ e6 ]. y* }! w9 `) ~
chosen.append(ind) ; R% C2 v8 k4 x& O- J6 _ break ) N3 _; [# ? O$ N+ ?6 Q3 g' U8 E/ _* L0 x% Y
return chosen / |; ], O+ o: z( g
9 o1 z; ]7 F) a* @
" v* G4 j; ]3 m6 i: g) l
def crossoperate(self, offspring):: r, {4 N" k5 m3 P' P9 ?2 W+ L
''' 2 v8 S2 _5 o% w/ H, T cross operation 5 D& z# L# ^* l '''& B2 u8 c4 f& ^- \, q8 B2 r
dim = len(offspring[0]['Gene'].data) + a( q4 z, p l5 ~/ n6 Z 8 e& a% {9 y, Q- D, x geninfo1 = offspring[0]['Gene'].data#Gene's data of first offspring chosen from the selected pop ( h4 v5 Z' c! G( u geninfo2 = offspring[1]['Gene'].data#Gene's data of second offspring chosen from the selected pop' X0 A4 ]" R- ~1 c! o" o$ t- n0 e
) P; F; t0 X a4 W
pos1 = random.randrange(1,dim)#select a position in the range from 0 to dim-1, & |; i; |6 X0 @6 z8 X pos2 = random.randrange(1,dim)7 d! k" u3 f. ]. a& T7 x
4 S. A3 ^8 a; X3 r+ c( X- Z newoff = Gene(data = [])#offspring produced by cross operation6 Q& d# c3 U% g% w
temp = []' P3 t8 m: g& f/ d, S! Z+ f, e$ n
for i in range(dim):. p+ \1 w2 ? C
if (i >= min(pos1,pos2) and i <= max(pos1,pos2)):* P2 g# `7 e# v; `+ ]3 R" j! w- l4 S
temp.append(geninfo2) 4 L: l1 }! n3 y #the gene data of offspring produced by cross operation is from the second offspring in the range [min(pos1,pos2),max(pos1,pos2)] 7 Q* l& c( {2 b' t else:. o( a5 B( E t- ^1 `
temp.append(geninfo1) % Y8 i7 e+ N% x; }9 b #the gene data of offspring produced by cross operation is from the frist offspring in the range [min(pos1,pos2),max(pos1,pos2)]% [- X) Y" C6 I% j( h8 v$ F! H
newoff.data = temp' M- @ @4 I* R, Q6 R, v/ p; V
" }) ?+ w; d& K; @0 P0 G9 o1 S
return newoff' w4 w6 \! H* q7 [6 X
6 D5 Z# B: ^3 }4 u; w0 L8 D, K, K- R' B( G0 X8 J
def mutation(self, crossoff, bound): ) m+ Y4 e; _+ r5 _3 X ''' * \) w- u/ \3 K# I3 h3 A$ Y mutation operation . D+ l6 }/ v8 c J. L5 U4 O ''' + D" Y( n w, q2 D) N4 n- x! s+ [: J1 l" R0 R' q S
dim = len(crossoff.data)- m9 n# _) X C3 G! P5 r- y E0 Z9 h+ K
8 ^1 s" U, i1 ?2 i0 @# D( Z- C pos = random.randrange(1,dim)#chose a position in crossoff to perform mutation.$ Q! ?/ P% [9 i, d5 Q+ J/ I
$ q, n5 T7 \& p% D' m8 K0 m crossoff.data[pos] = random.uniform(bound[0][pos],bound[1][pos]) 2 U3 `6 p# B# }2 u- [ return crossoff % i, r' s# q; e0 @# L- U) g2 ^- R1 q3 e, A
def GA_main(self):! y. Q; t% t, x: I' B) |
'''5 J9 }* \& _- m0 t# ]$ O
main frame work of GA 0 ?$ c' {7 E. Z- t ''' 8 U! K+ C. {, [$ [! F" Q" Y * g3 D% G# K' w- V& ^' |8 P popsize = self.parameter[3] 1 J+ t& _+ l2 A' Q- L$ O" h' v* ~2 T+ [5 d- _' B( u! @( V
print("Start of evolution") 2 I8 z# w6 E, U; d5 V% L8 q . f: O8 E: y2 k # Begin the evolution% c# m9 f3 Q* H% D
for g in range(NGEN): ' v8 U) X( n0 E& E+ b 5 ~- u2 X" l* R8 f+ b- ~6 }1 Y5 l print("-- Generation %i --" % g) , J" W1 l+ _/ j. [* F. ~3 D / r, f* x; [# y# @5 X2 ~ #Apply selection based on their converted fitness% P# _9 U3 w& y% a' n9 u
selectpop = self.selection(self.pop, popsize) # t7 g6 I! z( c6 O J/ V |: d% g1 Y3 b4 a) Z3 H# J
nextoff = [] : J4 t Y/ S$ q* F# J
while len(nextoff) != popsize: % d3 O+ \3 j3 S! L
# Apply crossover and mutation on the offspring $ V8 k: `! p, @3 b( D0 w+ ~* J- Y+ \ 5 _1 f" o$ @6 e # Select two individuals; p- U+ E& W' t3 @1 y K
offspring = [random.choice(selectpop) for i in xrange(2)] / z& x4 M: j; V, v2 P( v: m3 j6 { p6 a
if random.random() < CXPB: # cross two individuals with probability CXPB 6 H* a! ~, r& A$ S5 j* g crossoff = self.crossoperate(offspring). a4 P" Y/ z( j+ p- J; n
fit_crossoff = evaluate(self.xydata, crossoff.data)# Evaluate the individuals 5 e2 w- G2 K% z * e- v/ H' K! } if random.random() < MUTPB: # mutate an individual with probability MUTPB 4 @7 }1 m# e2 q1 a; }; u- B muteoff = self.mutation(crossoff,self.bound) 7 @4 w4 A. \% B/ y! s( w! a fit_muteoff = evaluate(self.xydata, muteoff.data)# Evaluate the individuals& e y, M/ c9 D' z( Q) U
nextoff.append({'Gene':muteoff,'fitness':fit_muteoff}) + c: a" o- K' Q 3 s' L3 Q/ |+ \! D$ X/ @* a # The population is entirely replaced by the offspring 3 V) a/ c. H" K self.pop = nextoff0 R2 ~# M! |! n9 {; z$ o# u
1 E, b/ _5 A* F$ U- D* G # Gather all the fitnesses in one list and print the stats ; D* Z, c' g9 O- |' `6 Y0 p fits = [ind['fitness'] for ind in self.pop], u: A/ V0 B$ H' T4 | p
4 ^- ` `% t6 e, R
length = len(self.pop) / }8 ~. d7 e) ~ mean = sum(fits) / length % E; H8 L4 J! I; y* [ sum2 = sum(x*x for x in fits) 1 ~( E8 {3 r; z1 s* s$ { std = abs(sum2 / length - mean**2)**0.5 7 p3 `1 a4 @0 r) X7 U$ | e best_ind = self.selectBest(self.pop) " y$ x# F$ `( B I! Z" H8 [( u. M7 I1 o, K, W
if best_ind['fitness'] < self.bestindividual['fitness']:7 M& t1 \$ ]% H, X1 X+ \; e9 _
self.bestindividual = best_ind 4 V/ ~8 T5 b$ {+ m; J' [& \; c / K7 e: [! V6 U. ~/ z3 ^4 K3 S print("Best individual found is %s, %s" % (self.bestindividual['Gene'].data,self.bestindividual['fitness'])) 5 U, G M, X3 B print(" Min fitness of current pop: %s" % min(fits)), J# s$ {0 _+ w8 J5 F
print(" Max fitness of current pop: %s" % max(fits))" [6 U5 p A% _5 }1 U4 Y
print(" Avg fitness of current pop: %s" % mean)& y# N1 r% ?2 T. [4 z
print(" Std of currrent pop: %s" % std)5 J6 |/ L5 z+ a
" b% j2 [& J; ]- F print("-- End of (successful) evolution --") 9 L8 t9 |7 [2 W # P( l' D: u- M) j1 [( [" Hif __name__ == "__main__":" T" G# k( }# m
( J* I( E" I) ]' g
CXPB, MUTPB, NGEN, popsize = 0.8, 0.3, 50, 100#control parameters & ^ n. c; o: a: i9 |3 J) d# R! y& s3 u
up = [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]#upper range for variables9 Y/ C) U; I* V+ s' O
low = [-64, -64, -64, -64, -64, -64, -64, -64, -64, -64]#lower range for variables & }* C- z1 V# F) L' x4 _+ e4 } parameter = [CXPB, MUTPB, NGEN, popsize, low, up] z0 Z' |3 K: j2 t