参考:
http://www.360doc.com/content/15/0309/15/13726687_453806200.shtml
http://www.cnblogs.com/liyuwang/p/5988358.html
最近在自学《演化计算》(潘正君著),了解了演化算法的基本基本步骤。在丽丽的帮助下找到了一个SGA的入门小程序,结合程序,理解演化算法中简单遗传算法的基本步骤。
一、问题描述
f(x1, x2) = x1 * x1 + x2 * x2,求解 f 的最大值(x1、x2为 0 ~ 7之间的正整数)。
二、算法实现
1、基本模块(具体遗传算法的基本步骤可以查书)
a、初始化种群(二进制编码)
b、评价种群(计算目标值、适应值、更新当前最坏个体)
c、产生下一代种群(选择——轮盘式选择、交叉——单点交叉、变异)
d、输出结果
2、具体思想
a、初始化种群(二进制编码)
x1、x2分别用3位二进制数来表示,将它们连在一起组成一个6位二进制数。用字符串来保存。
例:基因型 X = 101110,表现型 x1 = 5,x2 = 6。
种群使用一个结构体来表示,包括
b、评价种群(计算目标值、适应值)
本例中,目标值和适应值相同就采用一个整型变量来存储,fitness。
c、评价种群(更新当前最坏个体)
例中,额外定义一个历史最好个体和当前最坏个体。每次调用评价种群函数更新历史最好个体,并找到当前最坏个体,用历史最好个体更新当前最坏个体。
e、产生下一代种群(选择——轮盘式选择)
计算种群中所有个体的适应值之和sfitness。
计算每个个体相对适应值的大小 cfitness[i] += fitness / sfitness – cfitness[i – 1]。
随机生成 0 ~ 1 之间的数,来确定每个个体被选中的次数。
f、产生下一代种群(交叉——单点交叉)
打乱种群中个体的下标,重新排列种群中的个体。
循环,每次两个个体。
判断随机概率是否低于交叉概率。
是,则随机生成一个单点的下标。
将两个个体从单点下标开始到个体末端的基因位进行交换。
g、产生下一代种群(变异)
对每个个体的每一位随机生成概率。
若概率低于变异概率,则将这一位取反。
3、注意问题
a、随机数生成
由于rand()直接产生的是伪随机,所以在前面添上:
inclue <time.h>
rand((int)time(0));
b、种群中个体的个数、交叉概率和变异概率都会对算法产生影响,慎重选取
这里个体个数为:10
交叉概率为:0.6
变异概率为:0.001
#include <iostream>
#include <time.h>
#include <stdio.h>
using namespace std;
#define Popsize 10 //population size
#define ChromLength 6 //length of chromosome
typedef struct
{
char chrom[ChromLength + 1];//a chromosome of individual
int fitness; //取fitness(适应值) = value(目标值)
}Individual;
int gen; //current generation no.
int maxgen = 100; //maximum generation
int bestidx; //最好个体下标
int sfitness; //适应值总和
double pc = 0.6; //交叉概率
double pm = 0.001; //变异概率
Individual pop[Popsize + 1]; //old population
Individual hisbestind; //历史最佳个体
Individual curworsind; //当前最差个体
void initpop(void); //初始化种群
void evaluatepop(void); //评估种群并优化
void calfitness(void); //计算目标值(适应值)
int decchrom(char *chrom, int l, int r); //二进制转十进制
void findbestandworsind(void); ////更新历史最好和当前最坏个体,并用历史最好替换当前最坏
void gennexpop(void); //产生下一代种群
void selectpop(void); //选择算子,轮盘式选择
void crosspop(void); //交叉算子,单点交叉
void mutatepop(void); //变异算子,对每个个体每一位进行概率变异
void output(void); //输出
//初始化种群
void initpop(void)
{
int i, j;
srand((int)time(0));
for(i = 0; i < Popsize; i++)
{
for(j = 0; j < ChromLength; j++)
{
if(rand() % 2 == 0)
pop[i].chrom[j] = '0';
else
pop[i].chrom[j] = '1';
}
pop[i].chrom[j] = '\0';
}
bestidx = 0;
}
//评估种群并优化
void evaluatepop(void)
{
calfitness();
findbestandworsind();
}
//计算目标值(适应值)
//目标函数为f(x) = x1 * x1 + x2 * x2;
void calfitness(void)
{
int i, x1, x2;
for(i = 0; i < Popsize; i++)
{
x1 = decchrom(pop[i].chrom, 0, 2);
x2 = decchrom(pop[i].chrom, 3, 5);
pop[i].fitness = x1 * x1 + x2 * x2;
}
//求适应值总和
sfitness = 0;
for(i = 0; i < Popsize; i++)
sfitness += pop[i].fitness;
}
//二进制转十进制
int decchrom(char *chrom, int l, int r)
{
int i, tmp = 1, dec = 0;
for(i = r; i >= l; i--)
{
dec += tmp * (chrom[i] - '0');
tmp *= 2;
}
return dec;
}
//更新历史最好和当前最坏个体,并用历史最好替换当前最坏
void findbestandworsind(void)
{
int i, j = 0;
if(gen == 0)
hisbestind = pop[0];
curworsind = pop[0];
for(i = 0; i < Popsize; i++)
{
if(hisbestind.fitness < pop[i].fitness)
hisbestind = pop[i];
else if(curworsind.fitness > pop[i].fitness)
{
curworsind = pop[i];
j = i;
}
}
pop[j] = hisbestind;
}
//产生下一代种群
void gennexpop(void)
{
selectpop();
crosspop();
mutatepop();
}
//选择算子,轮盘式选择
void selectpop(void)
{
int i, j;
double cfitness[Popsize + 1], p;
Individual newpop[Popsize + 1];
//计算轮盘分布
cfitness[0] = (double)pop[0].fitness / sfitness;
for(i = 1; i < Popsize; i++)
cfitness[i] = (double)pop[i].fitness / sfitness + cfitness[i - 1];
//用轮盘进行随机选取,产生新的种群
for(i = 0; i < Popsize; i++)
{
p = rand() % 1000 / 1000.0;
j = 0;
while(p > cfitness[j]) j++;
newpop[i] = pop[j];
}
//更新种群
for(i = 0; i < Popsize; i++)
pop[i] = newpop[i];
}
//交叉算子,单点交叉
void crosspop(void)
{
int i, j, tmp, poi, idx[Popsize + 1];
double p;
char c;
//打乱种群下标,重新排列
for(i = 0; i < Popsize; i++)
idx[i] = 1;
for(i = 0; i < Popsize; i++)
{
poi = rand() % (Popsize - i);
tmp = idx[poi];
idx[poi] = idx[i];
idx[i] = tmp;
}
//随机选取交叉点,进行交叉
for(i = 0; i < Popsize; i += 2)
{
p = rand() % 1000 /1000.0;
if(p < pc)
{
poi = rand() % ChromLength;
for(j = poi; j < ChromLength; j++)
{
c = pop[i].chrom[j];
pop[i].chrom[j] = pop[i + 1].chrom[j];
pop[i + 1].chrom[j] = c;
}
}
}
}
//变异算子,对每个个体每一位进行概率变异
void mutatepop(void)
{
int i, j;
double p;
for(i = 0; i < Popsize; i++)
{
for(j = 0; j < ChromLength; j++)
{
p = rand() % 1000 / 1000.0;
if(p < pm)
{
if(pop[i].chrom[j] == '0')
pop[i].chrom[j] = '1';
else
pop[i].chrom[j] = '0';
}
}
}
}
//输出
void output(void)
{
double avg = (double)sfitness / Popsize;
cout << "gen = " << gen << ", avg = " << avg << ", best = " << hisbestind.fitness << ", chrom = " << hisbestind.chrom << endl;
}
int main()
{
gen = 0;
initpop();
evaluatepop();
while(gen < maxgen)
{
gen++;
gennexpop();
evaluatepop();
output();
}
return 0;
}