6 W! \3 V$ Q f* v! T& m% L
遗传算法(GA)是最早由美国Holland教授提出的一种基于自然界的“适者生存,优胜劣汰”基本法则的智能搜索算法。该法则很好地诠释了生物进化的自然选择过程。遗传算法也是借鉴该基本法则,通过基于种群的思想,将问题的解通过编码的方式转化为种群中的个体,并让这些个体不断地通过选择、交叉和变异算子模拟生物的进化过程,然后利用“优胜劣汰”法则选择种群中适应性较强的个体构成子种群,然后让子种群重复类似的进化过程,直到找到问题的最优解或者到达一定的进化(运算)时间。 5 s. P J* f i8 k% W ; E. R6 s/ o) z& F' cGa算法中的几个重要名词概念。) |4 j4 B4 m- n3 @8 a5 N
4 I9 Z. a: F1 t; B7 }
个体(染色体):自然界中一个个体(染色体)代表一个生物,在GA算法中,个体(染色体)代表了具体问题的一个解。 , F' q( Q, x* C( N
% p( n8 g0 D/ ?: g( z: C' simport random: O7 Q, _6 Z& R% y& I e
import math! O, E6 Z/ i/ \: ]$ ?8 |# D/ ~
from operator import itemgetter * z' C, g& A' h3 V1 H 3 `+ j3 z2 @4 p' ~6 ?) O1 ~) ]; |class Gene: ' g5 D( [+ V0 i( C( S '''. i; V% u6 P* _: w
This is a class to represent individual(Gene) in GA algorithom! w3 s1 S, Y0 J9 R: }6 j& A0 [, R
each object of this class have two attribute: data, size , `4 J: C i" z z ''' & ?3 p9 v. w* z7 c& G5 t& x8 B def __init__(self,**data):( Y' I8 \% [& m- V& W
self.__dict__.update(data) % ?; a3 @& k( V. H9 f
self.size = len(data['data'])#length of gene 6 ^3 w* c2 O! V6 O3 i0 A. S0 j( J4 j6 I: {6 c$ q. T& A3 \
/ K0 F' L# @% M1 L {0 |5 d5 Kclass GA: 8 d/ V0 s* M% g '''; c% m+ |0 P$ {% q" q3 p9 U
This is a class of GA algorithm. & E6 F" J7 G r& w ''' % z8 V# c6 D* u' S' U def __init__(self,parameter): 1 i0 M' `7 h7 ?5 p '''6 D) y, |) ~3 a$ @' w
Initialize the pop of GA algorithom and evaluate the pop by computing its' fitness value . 8 l( C6 T1 U) Y- u: b. b The data structure of pop is composed of several individuals which has the form like that:7 V* M- D6 B J
2 o( D. ]+ J5 l3 \$ K
{'Gene':a object of class Gene, 'fitness': 1.02(for example)}- C5 q" d7 S; ^/ d7 Y* `
Representation of Gene is a list: [b s0 u0 sita0 s1 u1 sita1 s2 u2 sita2] # s1 d s# M! b* I0 ]4 v7 C; {9 R8 D1 S/ w# _" Q, h2 }, [
'''1 |' |; ]* Q& M+ Y( {/ F& A( h
#parameter = [CXPB, MUTPB, NGEN, popsize, low, up] . Z- w$ W, M# {: _1 A4 d self.parameter = parameter / k# k& z' q& t $ i D2 ^7 w `% |6 m+ n, k low = self.parameter[4] : {7 R& n+ I+ f0 Y8 `7 N V up = self.parameter[5]) O6 z# \& F2 Y( |
+ i+ q' Y, N; _6 Y# G1 d pop = []7 _; j; G8 a; I$ v' ^2 V
for i in range(self.parameter[3]): : i5 E. f( p% i6 E$ H/ I geneinfo = [] 0 _6 G0 u0 b9 ^- ^ for pos in range(len(low)):' g6 C9 d9 B5 r* k+ M/ V" D0 @
geneinfo.append(random.uniform(self.bound[0][pos], self.bound[1][pos]))#initialise popluation, C9 T: I z6 c9 `: G! q1 h9 `" N6 n
# p$ \% [) k9 @% z$ N
fitness = evaluate(geneinfo)#evaluate each chromosome 0 N# M+ g; V( X' I pop.append({'Gene':Gene(data = geneinfo), 'fitness':fitness})#store the chromosome and its fitness' S1 Q& C- h5 Q/ t" Q
0 }1 E2 a6 ~1 @: s7 M5 O self.pop = pop) M `; q9 f Q. i- x& P1 r
self.bestindividual = self.selectBest(self.pop)#store the best chromosome in the population ! ?! q+ O3 X [2 ~/ ^4 ^3 _# G5 ]3 \) ^( I
def selectBest(self, pop):5 `9 R" H* {' N" ^! d
''' : U/ o0 ?! z$ r select the best individual from pop% C3 |: A! ~# P4 c7 d3 e* f
''' ) K9 C& U' q& W" l' n5 R0 H s_inds = sorted(pop, key = itemgetter("fitness"), reverse = False) 2 N. H$ g$ `! s# d) E return s_inds[0] / B+ W$ w9 o$ G7 ^ b0 S& I ~9 k/ ?, L) H% r( n& v* k" P$ E. v
def selection(self, individuals, k): , P+ y s& c8 F; f) } '''6 k1 T( l+ e% _: m" v( y& u) ]* a
select two individuals from pop. {+ `5 w' t+ u! \ w4 y+ V7 I
''' 5 k0 P$ d$ B& k/ t0 [/ G- U s_inds = sorted(individuals, key = itemgetter("fitness"), reverse=True)#sort the pop by the reference of 1/fitness ! Q. B8 j/ C. Q) N9 R sum_fits = sum(1/ind['fitness'] for ind in individuals) #sum up the 1/fitness of the whole pop $ S. L8 \1 m9 O: t- T# \5 J* b4 a! P2 o- ~+ [) o" E4 R
chosen = [] - a3 I2 w7 r0 @5 d for i in xrange(k): . |; Y, {0 Y( Q6 \ u = random.random() * sum_fits#randomly produce a num in the range of [0, sum_fits]# ^2 z7 p, o8 O8 o; v
sum_ = 0 ) ^" v4 s! z7 e for ind in s_inds: 6 L- P* P6 G6 _8 Q5 v' ]2 i sum_ += 1/ind['fitness']#sum up the 1/fitness ( J1 V6 g+ Q3 Q9 H2 p4 O if sum_ > u:& _- e$ |3 r# R8 E; T1 V
#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 7 \3 Y* G2 B- @ chosen.append(ind) 4 D( K; t+ I( @ J# |* A m+ B break8 ^9 _. I1 [) V/ j
6 [0 H; ^5 j; A" O/ Y; M4 j
return chosen # B: l7 \* ~( j: f& {$ l% e9 j# ]/ U' y' I
: r! O7 c& o0 A/ S. p4 @: D def crossoperate(self, offspring): : }- ~6 p% B& ?4 e9 k: G2 V' _9 ] ''' 8 U4 A. \% F; z9 q8 g cross operation U+ j9 p' v) N
''' ; p0 h+ y+ x$ q( g) q, H2 O dim = len(offspring[0]['Gene'].data)9 M y' L, [7 ]9 x( [4 [
1 Y/ B9 u9 f# C# b geninfo1 = offspring[0]['Gene'].data#Gene's data of first offspring chosen from the selected pop $ j6 p/ j! r: j+ _6 d: [ geninfo2 = offspring[1]['Gene'].data#Gene's data of second offspring chosen from the selected pop ) N, w; Y, _" e' u. A 0 h- a) N# Q) Z: Z$ s# Q' k0 t pos1 = random.randrange(1,dim)#select a position in the range from 0 to dim-1, G- c( l' H1 q6 C* I2 ]
pos2 = random.randrange(1,dim) ; \4 {: r; j$ I7 Z/ | N0 m# V $ ?8 T/ N4 G" V0 T newoff = Gene(data = [])#offspring produced by cross operation5 E1 x: ^7 K$ @2 d/ u5 O
temp = [] 0 Z: a1 Y" [% E8 j& H for i in range(dim): ( r1 J$ k0 }6 f: W9 m% ? if (i >= min(pos1,pos2) and i <= max(pos1,pos2)): + _! G/ y6 f q+ r/ u- ]* n, W temp.append(geninfo2). o3 b- B, R# l3 J5 f$ p
#the gene data of offspring produced by cross operation is from the second offspring in the range [min(pos1,pos2),max(pos1,pos2)]* i+ C" Y3 O9 f& x' m
else: t- y8 A; F; D; R4 `- N. x1 x$ b temp.append(geninfo1), g* Y7 V j5 P
#the gene data of offspring produced by cross operation is from the frist offspring in the range [min(pos1,pos2),max(pos1,pos2)] 8 x7 s! ?7 G( V; @ newoff.data = temp; K3 B1 t M0 v+ v2 l- m
* e3 R. N* L# r2 i6 k0 g$ b; E return newoff 7 I; j( i& B* l+ P4 \. f ! @2 D- W& a: B+ M8 y 1 K" n) H2 V- o+ g$ D def mutation(self, crossoff, bound):0 i9 w- [2 I& e* y% \
'''- d3 M2 _$ I8 z2 r- c
mutation operation5 ~) ^0 V# a/ x6 j
'''# ]6 S( o/ T l( c
, B4 v5 \9 x6 K- q- E; a
dim = len(crossoff.data) 6 c" R5 a, `6 _ 0 W- M5 ]' z$ ^4 Q1 Q: b [% ]0 E. o pos = random.randrange(1,dim)#chose a position in crossoff to perform mutation./ |- D5 c; q* F5 q5 U6 o
5 i6 J; C* ^9 c# r/ j" ~( `% \
crossoff.data[pos] = random.uniform(bound[0][pos],bound[1][pos])( ?4 B% o y. C/ J
return crossoff/ y# y5 t R( A$ l y
0 o6 E: g# s" ^
def GA_main(self): 7 _1 k, D0 c) \6 Z8 C ''' 9 C9 ~ [% S0 T4 l0 `8 s main frame work of GA 2 d4 f7 A2 s( ~" F& E# | '''" _( q! T# z) i- P
6 ?0 i2 X* _+ e
popsize = self.parameter[3] 0 K% j1 C# C, N5 ~' H' ]6 e# q. K1 I+ R i# \/ [0 Q/ }" c1 D- y
print("Start of evolution") , u1 K* Y7 ~" |7 R" C+ E 5 V3 \* f7 I7 C3 O: M) o+ b # Begin the evolution1 i+ Y% k, l. r( j
for g in range(NGEN): 3 M& l; y& ]) u+ r! } @' f& S- r+ o+ h) ~$ ~7 C" V
print("-- Generation %i --" % g) ! o: c' {. D0 L4 s% K& e 6 ]: G, q" [* t6 E( ^ #Apply selection based on their converted fitness 6 [4 ~! L7 \' L @& k# O, d" k selectpop = self.selection(self.pop, popsize) 6 L: N3 y: P6 T" k. f3 T, |
5 o) c m. {3 {% K/ U nextoff = [] - X8 `* P7 v9 `# ~ while len(nextoff) != popsize: ; n+ m& y/ N7 T6 [( q8 j
# Apply crossover and mutation on the offspring 2 |2 k- I i( ~8 _# i; \( K
5 R6 v& X; L2 O. @2 R# f4 o # Select two individuals w$ r$ z4 K0 F2 c offspring = [random.choice(selectpop) for i in xrange(2)]) | e3 v% a4 y
5 I3 W% z* @& q# }% b3 n if random.random() < CXPB: # cross two individuals with probability CXPB( a* p& W7 {, M2 y. o, w( z
crossoff = self.crossoperate(offspring). \2 A0 i" n5 J! g
fit_crossoff = evaluate(self.xydata, crossoff.data)# Evaluate the individuals 1 p* b+ Q+ N6 M1 }2 |
8 ], m4 P$ C9 h1 _ _* }, t
if random.random() < MUTPB: # mutate an individual with probability MUTPB . o2 R- d2 f2 h# [4 z muteoff = self.mutation(crossoff,self.bound) ) |; b; B, w0 y9 ?/ T7 n fit_muteoff = evaluate(self.xydata, muteoff.data)# Evaluate the individuals* h! n: X/ M% e5 x* ~
nextoff.append({'Gene':muteoff,'fitness':fit_muteoff}) 0 P }/ b" A3 P" \5 K! ] % U" Y- y1 c8 O+ K # The population is entirely replaced by the offspring 6 u4 d2 O3 V( i- `1 l5 \5 v self.pop = nextoff9 k- F& t. R0 T* |: h# a, h# |5 q
+ |' e. R$ n; U k8 @9 q: X% Q
# Gather all the fitnesses in one list and print the stats % B! O U* y; ?7 _3 l* O fits = [ind['fitness'] for ind in self.pop]! y- ~6 U9 A- r
9 s3 A7 x; B& D- _ length = len(self.pop) ! E; _% g! s( H6 b: B! n mean = sum(fits) / length l8 k7 W6 o% H: i8 C
sum2 = sum(x*x for x in fits)1 O) B5 i" X- I4 M& ?
std = abs(sum2 / length - mean**2)**0.5 M: w* @9 f) M% \+ N3 @ best_ind = self.selectBest(self.pop)3 h% ?1 I, K7 y* G+ Q
9 } I* O# d1 _6 g- I" C
if best_ind['fitness'] < self.bestindividual['fitness']:8 e$ {" M( K3 K9 K1 w: ~) t& z
self.bestindividual = best_ind% S2 [* n- N3 r* W/ C% `/ B
+ I3 ]' \# B4 l. J$ U" v& p6 T2 \
print("Best individual found is %s, %s" % (self.bestindividual['Gene'].data,self.bestindividual['fitness'])) 4 B) Z" Y0 T+ H, ]$ I% h5 ]# n% A print(" Min fitness of current pop: %s" % min(fits)) ( b" y- l* G: | print(" Max fitness of current pop: %s" % max(fits)) ' A0 D$ j0 r5 h, r1 f print(" Avg fitness of current pop: %s" % mean) ; w! Q, ?/ ?; _- s5 e print(" Std of currrent pop: %s" % std) : ^; }5 e& v1 c- o' a" [9 c5 ]- @/ I6 K1 W4 j! g1 ^$ G1 Y
print("-- End of (successful) evolution --") 2 ~3 ~. M0 o3 E/ ^5 [0 K8 d7 `
3 C1 |5 ^) l3 x9 Z6 ^* c, V( g: s
if __name__ == "__main__": , n/ t) }+ @3 D8 a% B$ ^. |+ ?' l3 s% l9 D
CXPB, MUTPB, NGEN, popsize = 0.8, 0.3, 50, 100#control parameters; I/ Y: J+ ?( ?