$ Z8 l0 F$ o2 E7 i
7 K k; d5 C6 y3 a% E9 I2 X- E' v7 W
遗传算法 * n h7 w Q) f. C0 T9 q9 s遗传算法(Genetic Algorithm, GA)是近几年发展起来的一种崭新的全局优化算法。1962年霍兰德(Holland)教授首次提出了GA算法的思想,它借用了仿真生物遗传学和自然选择机理,通过自然选择、遗传、变异等作用机制,实现各个个体的适应性的提高。从某种程度上说遗传算法是对生物进化过程进行的数学方式仿真。 - |: S9 m( D) W n# k这一点体现了自然界中"物竞天择、适者生存"进化过程。与自然界相似,遗传算法对求解问题的本身一无所知,它所需要的仅是对算法所产生的每个染色体进行评价,把问题的解表示成染色体,并基于适应值来选择染色体,使适应性好的染色体有更多的繁殖机会。在算法中也即是以二进制编码的串。并且,在执行遗传算法之前,给出一群染色体,也即是假设解。然后,把这些假设解置于问题的“环境”中,也即一个适应度函数中来评价。并按适者生存的原则,从中选择出较适应环境的染色体进行复制, 淘汰低适应度的个体,再通过交叉,变异过程产生更适应环境的新一代染色体群。对这个新种群进行下一轮进化,至到最适合环境的值。 & s. k* ~2 ?( H; z/ n遗传算法已用于求解带有应用前景的一些问题,例如遗传程序设计、函数优化、排序问题、人工神经网络、分类系统、计算机图像处理和机器人运动规划等。 9 p' d$ a2 Y1 l+ M术语说明 $ L0 |3 r% L* t8 U1 N由于遗传算法是由进化论和遗传学机理而产生的搜索算法,所以在这个算法中会用到很多生物遗传学知识,下面是我们将会用来的一些术语说明:, j; p! @; R+ _. S6 J. j0 } 一、染色体(Chronmosome)+ J8 g+ g4 K* l! _6 j
染色体又可以叫做基因型个体(individuals),一定数量的个体组成了群体(population),群体中个体的数量叫做群体大小。 " y ]& ]* f9 |/ ?* v) N4 {" b1 C二、基因(Gene): B: q4 M1 s( t! H' S( e$ @
基因是串中的元素,基因用于表示个体的特征。例如有一个串S=1011,则其中的1,0,1,1这4个元素分别称为基因。它们的值称为等位基因(Alletes)。2 K# B; N- M% v% j+ [& `, R 三、基因地点(Locus) : K+ U: G& M+ q+ M基因地点在算法中表示一个基因在串中的位置称为基因位置(Gene Position),有时也简称基因位。基因位置由串的左向右计算,例如在串 S=1101 中,0的基因位置是3。0 z4 m4 D; _: T1 Z 四、基因特征值(Gene Feature) ! r! D& t- [- s0 R/ f在用串表示整数时,基因的特征值与二进制数的权一致;例如在串 S=1011 中,基因位置3中的1,它的基因特征值为2;基因位置1中的1,它的基因特征值为8。 ) p; ^" W* S3 f& A S5 Y五、适应度(Fitness)) E- ^- s! q4 T6 Q6 h
各个个体对环境的适应程度叫做适应度(fitness)。为了体现染色体的适应能力,引入了对问题中的每一个染色体都能进行度量的函数,叫适应度函数. 这个函数是计算个体在群体中被使用的概率。! J! I: q/ U0 q" j8 C" o$ M 操作算法 , r4 _ C. l. [2 D, z- S& s7 V霍兰德(Holland)教授最初提出的算法也叫简单遗传算法,简单遗传算法的遗传操作主要有三种:选择(selection)、交叉(crossover)、变异(mutation)这也是遗传算法中最常用的三种算法: $ Y3 F7 o7 V5 s" I2 H1.选择(selection)& [1 V& ]5 s) m
选择操作也叫复制操作,从群体中按个体的适应度函数值选择出较适应环境的个体。一般地说,选择将使适应度高的个体繁殖下一代的数目较多,而适应度较小的个体,繁殖下一代的数目较少,甚至被淘汰。最通常的实现方法是轮盘赌(roulette wheel)模型。令Σfi表示群体的适应度值之总和,fi表示种群中第i个染色体的适应度值,它被选择的概率正好为其适应度值所占份额fi/Σfi。如下图表中的数据适应值总和Σfi=6650,适应度为2200变选择的可能为fi/Σfi=2200/6650=0.394." O [7 M1 {. t9 Z% G5 q$ N! r; C
1 ~. y9 e9 q9 M+ i[url=]图1. 轮盘赌模型[/url], P) O6 N' A# q# ?# @& S 9 k; m8 Y- K9 d0 a
Fitness 值:
2200
1800
1200
950
400
100
选择概率:
3331
0.271
0.18
0.143
0.06
0.015
2.交叉(Crossover) # L' Y o1 G# o5 K9 G/ `交叉算子将被选中的两个个体的基因链按一定概率pc进行交叉,从而生成两个新的个体,交叉位置pc是随机的。其中Pc是一个系统参数。根据问题的不同,交叉又为了单点交叉算子(Single Point Crossover)、双点交叉算子(Two Point Crossover)、均匀交叉算子 (Uniform Crossover),在此我们只讨论单点交叉的情况。 5 _% j/ i. o. O" S) t单点交叉操作的简单方式是将被选择出的两个个体S1和S2作为父母个体,将两者的部分基因码值进行交换。假设如下两个8位的个体:; k+ ]+ |, i! s- f F1 B
S1 1000 1111 S2 1110 1100
5 k" n- }1 o& k$ ~0 A7 m1 S. O
产生一个在1到7之间的随机数c,假如现在产生的是2,将S1和S2的低二位交换:S1的高六位与S2的低六位组成数串10001100,这就是S1和S2 的一个后代P1个体;S2的高六位与S1的低二位组成数串11101111,这就是S1和S2的一个后代P2个体。其交换过程如下图所示: 3 s1 f9 n" u' c: R
choose an intial population$ u$ X4 r) i8 ^7 M- Q
For each h in population,compute Fitness(h)& m$ A# `/ W/ q$ Y. n, s
While(max Fitness(h) < Fitnessthreshold) ( V8 Z+ N0 o6 W8 q( J) Mdo selection & W1 z. N. D5 l/ D$ N do crossover% ], _2 r4 R! b4 a0 `4 S
do mutation 1 D& a ~2 N- `& s update population ! ^' |3 a: a% d$ {% M$ G. J' ^For each h in population,compute Fitness(h) , u6 X, I7 M/ zReturn best Fitness 0 i- i# M# ], v* ], R1 Z: p8 @
double forceX = 0;. e8 l! B) [# T, {0 \- m
double forceY = 0; % @! G3 g* B& x+ I" x for (int i=0; i
+ v6 p$ o% {# } d) I: D6 r这里我们用遗传算法来控制机器人移动位置。这些策略是基于下面几点:机器人人自己的位置、速度和方位;对手的位置(x,y坐标)、速度、方位以及相对角;所有机器人和子弹位置,方位及速度;场地大小等参数。 4 d2 R: k- j) q% X1 ^+ H1 `当上面的信息在下一回移动中使用时,出输出一对坐标值,根据这对坐标在Robocode就能得到距离和角度。要想让移动实现遗传必须要让它实现在线学习:所以我们的代码必须做下面几件事:要有一个函数收集适应度值,在Robocode运行过程中要运用到遗传操作,遗传后代要在Robocode运行中产生,而不是事后由手写入代码。- \, p& T. l' @, R' j8 k* o$ v 遗传操作4 |. N2 ^$ {8 M! j6 {9 G7 `
本例中遗传算法为实现移动用到两个类GA和MovePattern。此处的GA比较简单主要完成数据和群体的定义,以及这些定义的读写文件操作。基中包括如下参数:群体大小、交叉概率、变异概率、精英概率(既告诉从当前群体到下一代中有多少移动不需要改变)、方程式中使用的加权系数大小,它通过一个主循环完成MovePattern的封装。MovePattern类中实现交叉、变异方法等方法,完成移动模式操作。而所有的输出保存在一个vector函数当中。Vector函数拥有一对实数数组,一个用于计算x坐标,另一个用于计算y坐标。通过对x,y坐标的计算,从而得到距离、角度等值,并产生相就在移动策略。如下,MovePattern包含三个参数,grad表示vector函数排列顺序,input即表示算法给出的输入编号,rang是加权的范围。5 c' G" T8 `/ K
public class MovePatteren implements Comparable { 8 G/ O2 l: R" u7 r- m' |1 i" G- `6 r/ o private int grad, input; , q- j- n8 [9 g# B" ~% H$ u private double range; ' N Q* _0 j3 Q8 h- t1 k protected double fitness=0; ; k; K4 f4 \* w- a4 p p6 Y8 X protected double[] weightsX, weightsY; 1 r7 z/ ], B+ h" u" B… } ' L r5 p6 i6 ^+ u
0 l B/ \+ k, m& U0 U8 d# B
交叉操作:每一个交叉操作执行如下步骤,先在交叉操作中产生一个特征码。这个特征码是个0到1之间的变量数组。有关交叉的基本原理可参考上面部分。最后通过遍历vector函数,把相应的加权值进行交叉操作。/ B8 ?1 n" h1 M: C. d
protected MovePatteren crossOver(MovePatteren mate, boolean[] maskx, boolean[] masky) {: @: C- w2 m" [
double[] wx= new double[weightsX.length]; {+ k# F7 ]! m1 I5 Y
double[] wy= new double[weightsX.length]; ) ], m% V& p/ E1 ~/ A for(int mask=0; mask <="" pre="" mask++)="" for(int="" g="0;" g
% B, E$ f2 Y7 [9 S, s) ~这里的变异操作比较简单。把加权范围内的随机数值去代替0到数组长之间的随机数并保存到移动模式中。则完成整个数组的变异过程: [2 H. s* Y/ }) M8 z
protected void mutate() {3 N9 c# M; \, M9 |* B
weightsX[(int)(Math.random()*weightsX.length)]=Math.random()*range*2-range;8 V, c1 ~- p6 [+ j7 w& U. ^
weightsY[(int)(Math.random()*weightsX.length)]=Math.random()*range*2-range; 6 [! U6 o3 w& J3 A' ^} 4 @. R+ @: S6 r( F+ Q4 {. `) \% H
}7 p+ M5 o, O; Y* g
从上面的例子我们知道了遗传算法的大概实现,但并没有告诉我们这些组件是如何一起工作的。当Robocode开始时,如果文件中没有数据,所以系统会依照输入的策略随机生成一个移动模式,如果文件中有数据,则加载这些数据。每一个移动模式在开始都会给出了一个适应度值。当所有的移动模式都接收到适应度值,并完成各自的编号后,下面的操作将开始执行: # f& k5 ^. l/ o; i
对所有的移动模式依据它们的适应度值进行分级处理
执行精英操作
执行交叉操作
应用变异操作
保存加权
算法重新开始6 J6 \. ^8 U# @$ C: w* T3 {
适应度值在进行运算过程中由机器人程序不断调整,以找到最优适应度。0 I3 p, x" E \8 C; g& Z4 o, p) y
限于篇副其他的一些策略本文不与详细说明,上面所有提到的策略和行为程序都可在网上或IBM的开发杂志上找到成熟的讲解和例子机器人。有兴趣的朋友可以把这些策略都加入到自己的遗传算法中来。我们取群体大小为50,选择概率为0.7,交叉概率为0.6,变异概率为0.3,与Robocode部分例子机器人测试,经过150代后你会发现系统产生了很多有趣的策略。比如撞击策略,这些策略都不在我们定义的策略之中。6 C# [+ r& n0 [: Z
( }2 E/ u: i, ?: v! i3 d
# I8 i0 }! }; M; C9 f
- W7 }% |. ], L$ ?" N; ^8 A$ g6 a
S7 |- E! @. e" F, W
0 b/ e. u- ?" U* ?- s0 }' C
. f# J: c/ r7 h9 v! A
中间解释程序进化机器人 ( [8 z- T X' K2 }遗传算法可被看做任意基因组字符串。但是你必须决定这些字符所代表的意义,也就是说如何解释每一个基因组。最简单的方法是把每一个基因组视为java代码,编译并运行它们。但是这些程序编译都很困难,所以也就有可能不能工作。Jacob Eisenstein设计了一种机器翻译语言TableRex来解决这个问题。在java中,TableRex被用于进化和解释动行时的Robocode 机器人。通过测试,只要我把TableRex解释程序作为文件放入Robocode控制器目录中,这些控制器就会读取文件并开始战斗。TableRex是一些最适合遗传算法的二进制编程。只要符合TableRex程序文法,每个程序都能被解释。 $ G6 w) @! L- Z0 e* z) g编码 8 G U0 ~5 Q% K* c下表中显示了TableRex编码结构,它由一个行动作函数,二个输入和一个输出组成。如行6的值 ,这是个布尔型的表达式“值 line4 小于 90”,这个结果会在最后一行输出布尔为1的值。0 c2 g$ x% q0 g0 s* M