遗传算法的并行实现
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
遗
传
算
法
(基于遗传算法求函数最大值)
指导老师:刘建丽
学号:S201007156
姓名:杨平
班级:研10级1班
遗传算法
一、 遗传算法的基本描述
遗传算法(Genetic Algorithm ,GA )是通过模拟自然界生物进化过程来求解优化问题的一类自组织、自适应的人工智能技术。它主要基于达尔文的自然进化论和孟德尔的遗传变异理论。多数遗传算法的应用是处理一个由许多个体组成的群体,其中每个个体表示问题的一个潜在解。对个体存在一个评估函数来评判其对环境的适应度。为反映适者生存的思想,算法中设计一个选择机制,使得:适应度好的个体有更多的机会生存。在种群的进化过程中,主要存在两种类型的遗传算子:杂交和变异。这些算子作用于个体对应的染色体,产生新的染色体,从而构成下一代种群中的个体。该过程不断进行,直到找到满足精度要求的解,或者达到设定的进化代数。显然,这样的思想适合于现实世界中的一大类问题,因而具有广泛的应用价值。遗传算法的每一次进化过程中的,各个体之间的操作大多可以并列进行,因此,一个非常自然的想法就是将遗传算法并行化,以提高计算速度。本报告中试图得到一个并行遗传算法的框架,并考察并行化之后的一些特性。为简单起见(本来应该考虑更复杂的问题,如TSP 。因时间有些紧张,做如TSP 等复杂问题怕时间不够,做不出来,请老师原谅),考虑的具有问题是:对给定的正整数n 、n 元函数f ,以及定义域D ,求函数f 在D 内的最大值。
二、 串行遗传算法
1. 染色体与适应度函数
对函数优化问题,一个潜在的解就是定义域D 中的一个点011(,,...,)n x x x -,因此,我们只需用一个长度为n 的实数数组来表示一个个体的染色体。由于问题中要求求函数f 的最大值,我们可以以个体所代表点011(,,...,)n x x x -在f 函数下的值来判断该个体的好坏。因此,我们直接用函数f 作为个体的适应度函数。
2. 选择机制
选择是遗传算法中最主要的机制,也是影响遗传算法性能最主要的因素。若选择过程中适应度好的个体生存的概率过大,会造成几个较好的可行解迅速占据种群,从而收敛于局部最优解;反之,若适应度对生存概率的影响过小,则会使算法呈现出纯粹的随机徘徊行为,算法无法收敛。下面我们介绍在实验中所使用的选择机制。
我们定义P 为当前种群内所有个体的集合,
(0)(1)(1),,...,n x x x -为P 中所有个体的一个固定排列。若x
P ∈为某一个体,()f x 表示该个体的适应度,则种群P 的适应度定义为:
1
()0()()n i i s P f x -==
∑ 对任意个体x P ∈,x 的相对适应度定义为()()/()r x f x s P =。相对适应度()r x 反映了个体()i x 的适应度在整个适应度总和中所占的比例。个体适应度越高,被选中的概率越高。累积适应度定义为:
进行选择之前,先产
生一个0到1之间的随机实数t ,若满足1()()k k r x t r x +≤<,则第k+1个个体被选中。循环以上过程,即得到生成下一代种群的母体。
具体实现见如下函数:
void pop_select(void ) { int mem, i, j, k; double sum = 0; double p; /* 计算种群适应度之和 */
for (mem = 0; mem < POPSIZE; mem++) {
/* 按照累积适应度概率选取母体种群 */ for (i = 0; i < POPSIZE; i++) { p = rand()%1000/1000.0; if (p < population[0].cfitness) newpopulation[i] = population[0]; else { for (j = 0; j < POPSIZE;j++) if (p >= population[j].cfitness && p < population[j+1].cfitness) newpopulation[i] = population[j+1]; }
} /*计算种群的总适应度*/ for (i = 0; i < POPSIZE; i++) population[i] = newpopulation[i];
} sum += (population[mem].fitness - lower_fitness); }
/* 计算相对适应度 */
for (mem = 0; mem < POPSIZE; mem++) { population[mem].rfitness = (population[mem].fitness - lower_fitness)/sum; } population[0].cfitness = population[0].rfitness;
/* 计算累积适应度 */
for (mem = 1; mem < POPSIZE; mem++) { population[mem].cfitness = population[mem-1].cfitness + population[mem].rfitness; ()()
0()()k k i i c x r x ==∑
}
3.杂交算子
杂交算子的流程一般如下:
(1)按杂交概率选择一对参与进化的个体;
(2)随机确定一个截断点;
(3)将两个个体的染色体从截断点处截断,并交换,从而得到新的染色体。
具体算法见如下函数:
void crossover(void)
{
int i, j, k, m, point;
int first = 0;
double x;
for (k = 0; k < POPSIZE; k++) {
x = rand()%1000/1000.0; //产生随机交叉概率
if(x < PXOVER) /*如果随机交叉概率小于交叉概率,则进行交叉*/
{
first++;
if (first % 2 == 0) {
if (NVARS == 2) point = 1; //得到一个交叉点
else point = (rand() % (NVARS - 1)) + 1;
for (j = 0; j < point; j++)
//交叉运算,两个个体的交叉点前的基因进行交换
swap(&population[m].gene[j], &population[k].gene[j]);
}
else m = k;
}
}
}
4.变异算子
在遗传算法中使用变异算子有两个目的:改善遗传算法的局部搜索能力。维持群体的多样性,防止出现早熟现象。变异操作的实现相当简单,只需遍历各染色体的各个单元,按某一变异概率将该单元变成一个随机的合法值。
其执行过程是:
(1)对个体的每一个基因组,依变异概率Pm指定为变异点。
(2)对每一个指定的变异点,对其基因取非或者用其他等位基因值来代替,从而产生一个新的个体。实现代码如下:
void mutate(void)
{
int i, j;
double lbound, hbound;
double p; //定义p为随机变异概率
for (i = 0; i < POPSIZE; i++)
for (j = 0; j < NVARS; j++) {
p = rand()%1000/1000.0;
if (p < PMUTATION) {
population[i].gene[j] = randval(lower[j], upper[j]);