遗传算法入门简单实例

来源:互联网 发布:怎么快速成为淘宝达人 编辑:程序博客网 时间:2024/05/17 00:08

参考:

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 chromosometypedef struct{char chrom[ChromLength + 1];//a chromosome of individualint fitness; //取fitness(适应值) = value(目标值)}Individual;int gen; //current generation no.int maxgen = 100; //maximum generationint bestidx; //最好个体下标int sfitness; //适应值总和double pc = 0.6; //交叉概率double pm = 0.001; //变异概率Individual pop[Popsize + 1]; //old populationIndividual 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';elsepop[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';elsepop[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;}

0 0
原创粉丝点击