001_wz_使用遗传算法计算函数的最大值

一、目的

求解函数 f ( x ) = x + 10 s i n ( 5 x ) + 7 c o s ( 4 x ) , x ∈ [ 0 , 9 ] f(x) = x + 10sin(5x) + 7cos(4x), x∈[0,9] f(x)=x+10sin(5x)+7cos(4x),x[0,9]的最大值
这个函数大概是这个样子
在这里插入图片描述

二、遗传算法介绍

2.1 简述

遗传算法(Genetic Algorithm)遵循『适者生存』、『优胜劣汰』的原则,是一类借鉴生物界自然选择和自然遗传机制的随机化搜索算法。遗传算法模拟一个人工种群的进化过程,通过选择(Selection)、交叉(Crossover)以及变异(Mutation)等机制,在每次迭代中都保留一组候选个体,重复此过程,种群经过若干代进化后,理想情况下其适应度达到近似最优的状态。

2.2 遗传算法的组成

  • 编码 -> 创造染色体
  • 个体 -> 种群
  • 适应度函数
  • 遗传算子
  • 选择
  • 交叉
  • 变异

  • 运行参数
  • 是否选择精英操作
  • 种群大小
  • 染色体长度
  • 最大迭代次数
  • 交叉概率
  • 变异概率

2.3 编码与解码

实现遗传算法的第一步就是明确对求解问题的编码和解码方式。对于函数优化问题,一般有两种编码方式,各具优缺点实数编码:

  • 直接用实数表示基因,容易理解且不需要解码过程,但容易过早收敛,从而陷入局部最优
  • 二进制编码:稳定性高,种群多样性大,但需要的存储空间大,需要解码且难以理解对于求解函数最大值问题
    下面编程选择二进制编码
    在这里插入图片描述

以我们的目标函数 f ( x ) = x + 10 s i n ( 5 x ) + 7 c o s ( 4 x ) , x ∈ [ 0 , 9 ] f(x) = x + 10sin(5x) + 7cos(4x), x∈[0,9] f(x)=x+10sin(5x)+7cos(4x),x[0,9] 为例。假如设定求解的精度为小数点后4位,可以将x的解空间划分为 (9-0)×(1e+4)=90000个等分。 2 16 < 90000 < 2 17 2^{16}<90000<2^{17} 216<90000<217,需要17位二进制数来表示这些解。

换句话说,一个解的编码就是一个17位的二进制串。一开始,这些二进制串是随机生成的,一个这样的二进制串代表一条染色体串,这里染色体串的长度为17。对于任何一条这样的染色体chromosome,如何将它复原(解码)到[0,9]这个区间中的数值呢?对于本问题,我们可以采用以下公式来解码:

x = 0 + decimal(chromosome)*(9-0)/(2^17-1)
  • decimal( ): 将二进制数转化为十进制数
    一般化解码公式:
f(x), x∈[lower_bound, upper_bound]
x = lower_bound + decimal(chromosome)*(upper_bound-lower_bound)/(2^chromosome_size-1)
  • lower_bound: 函数定义域的下限
  • upper_bound: 函数定义域的上限
  • chromosome_size: 染色体的长度

通过上述公式,我们就可以成功地将二进制染色体串解码成[0,9]区间中的十进制实数解。

2.4 个体与种群

『染色体』表达了某种特征,这种特征的载体,称为『个体』。

对于本次实验所要解决的一元函数最大值求解问题,个体可以用上一节构造的染色体表示,一个个体里有一条染色体。许多这样的个体组成了一个种群,其含义是一个一维点集(x轴上[0,9]的线段)。

2.5 适应度函数

遗传算法中,一个个体(解)的好坏用适应度函数值来评价,在本问题中,f(x)就是适应度函数,适应度函数值越大,解的质量越高。

适应度函数是遗传算法进化的驱动力,也是进行自然选择的唯一标准,它的设计应结合求解问题本身的要求而定。

2.6 遗传算子

我们希望有这样一个种群,它所包含的个体所对应的函数值都很接近于f(x)在[0,9]上的最大值,但是这个种群一开始可能不那么优秀,因为个体的染色体串是随机生成的。

如何让种群变得优秀呢?不断的进化。

每一次进化都尽可能保留种群中的优秀个体,淘汰掉不理想的个体,并且在优秀个体之间进行染色体交叉,有些个体还可能出现变异。种群的每一次进化,都会产生一个最优个体。种群所有世代的最优个体,可能就是函数f(x)最大值对应的定义域中的点。如果种群无休止地进化,那总能找到最好的解。

但实际上,我们的时间有限,通常在得到一个看上去不错的解时,便终止了进化。对于给定的种群,如何赋予它进化的能力呢?

首先是选择(selection):

  • 选择操作是从前代种群中选择多对较优个体,一对较优个体称之为一对父母,让父母们将它们的基因传递到下一代,直到下一代个体数量达到种群数量上限
  • 在选择操作前,将种群中个体按照适应度从小到大进行排列
  • 采用轮盘赌选择方法(当然还有很多别的选择方法),各个个体被选中的概率与其适应度函数值大小成正比
  • 轮盘赌选择方法具有随机性,在选择的过程中可能会丢掉较好的个体,所以可以使用精英机制,将前代最优个体直接选择

其次是交叉(crossover):

  • 两个待交叉的不同的染色体(父母)根据交叉概率(cross_rate)按某种方式交换其部分基因
  • 采用单点交叉法,也可以使用其他交叉方法

最后是变异(mutation):

  • 染色体按照变异概率(mutate_rate)进行染色体的变异
  • 采用单点变异法,也可以使用其他变异方法

一般来说,交叉概率(cross_rate)比较大,变异概率(mutate_rate)极低。

像求解函数最大值这类问题,设置的交叉概率(cross_rate)是0.6,变异概率(mutate_rate)是0.01。因为遗传算法相信2条优秀的父母染色体交叉更有可能产生优秀的后代,而变异的话产生优秀后代的可能性极低,不过也有存在可能一下就变异出非常优秀的后代,这也是符合自然界生物进化的特征的。

2.7 遗传算法流程

在这里插入图片描述

三、编程实现

3.1 初始化种群

%初始化种群
%population_size:种群大小
%chromosome:染色体长度

function init(population_size, chromosome_size)
global population;
for i=1:population_size
    for j=1:chromosome_size
        %给population的i行j列赋值
        %rand产生0-1之间的随机数,round()是四舍五入函数
        population(i,j) = round(rand);
    end
end

clear i;
clear j;
end

3.2 计算个体适应度

%计算种群个体适应度,对不同的优化目标,修改下面的函数
%population_size:种群大小
%chromosome_size:染色体长度

function fitness(population_size,chromosome_size)
global fitness_value;
global population;

upper_bound=9;%自变量的区间上限
lower_bound=0;%自变量的区间下限

%将所有种群个体适应度初始化为0
for i=1:population_size
    fitness_value(i)=0.;
end
%f(x)=-x-10*sin(5*x)-7*cos(4*x)
for i=1:population_size
    for j=1:chromosome_size
        if population(i,j)==1
            fitness_value(i) = fitness_value(i)+2^(j-1);%population[i]染色体串和实际的自变量xi二进制串顺序是相反的
        end
    end
    fitness_value(i)=lower_bound+fitness_value(i)*(upper_bound-lower_bound)/(2^chromosome_size-1);%自变量xi二进制转十进制
    fitness_value(i)=fitness_value(i)+10*sin(5*fitness_value(i))+7*cos(4*fitness_value(i)   );%计算自变量xi适应度函数值
end

clear i;
clear k;
end

3.3 按照个体适应度大小排序

%对个体适应度进行排序,并保留最佳个体、
%population_size:种群大小
%chromosome_size:染色体长度

function rank(population_size,chromosome_size)
global fitness_value;%种群适应度
global fitness_sum;%种群累计适应度
global fitness_average;
global best_fitness;
global best_individual;
global best_generation;
global population;
global G;

for i=1:population
    fitness_sum(i)=0;
end

min_index=1;
temp=1;
temp_chromosome(chromosome_size)=0;

%遍历种群
%冒泡排序
%最后population(i)的适应度随i递增而递增,population(1)最小,population(population_size)最大
for i=1:population_size
    min_index=i;
    for j=i+1:chromosome_size
        if fitness_value(j)<fitness_value(min_index)
            min_index=j;
        end
    end
    
    if min_index~=i
        %交换个体适应度
        temp = fitness_value(i);
        fitness_value(i)=fitness_value(min_index);
        fitness_value(min_index)=temp;
        
        %交换染色体串
        for k=1:chromosome_size
            temp_chromosome(k) = population(i,k);
            population(i,k)=population(min_index,k);
            population(min_index,k)=temp_chromosome(k);
        end
    end
end

%计算前i个个体的适应度之和
for i=1:population_size
    if i==1
        fitness_sum(i)=fitness_sum(i)+fitness_value(i);
    else
        fitness_sum(i)=fitness_sum(i-1)+fitness_value(i);
    end
end

%计算第G次迭代个体的平均适应度
fitness_average(G)=fitness_sum(population_size)/population_size;

%更新最大适应度和对应的迭代次数,保留最佳个体
if fitness_value(population_size)>best_fitness
    best_fitness=fitness_value(population_size);
    best_generation=G;
    for j=1:chromosome_size
        best_individual(j)=population(population_size,j);
    end
end
clear i;
clear j;
clear k;
clear min_index;
clear temp;
end

3.4 选择操作

%轮盘赌选择操作
%population_size:种群大小
%chromosome_size:染色体长度
%elitism:是否精英选择

function selection(population_size,chromosome_size,elitism)
global population;%前代种群
global new_population;%新一代种群
global fitness_sum;%种群累计适应度

for i=1:population_size
    r=rand*fitness_sum(population_size);
    first=1;
    last=population_size;
    mid=round((first+last)/2);
    idx=-1;
    
    %排中法选择个体
    while(first<last)&&(idx==-1)
        if r>fitness_sum(mid)
            first=mid;
        elseif r<fitness_sum(mid)
            last=mid;
        else
            idx=mid;
            break;
        end
        mid=round((first+last)/2);
        if(last-first)==1
            idx=last;
            break;
        end
    end
    
    %产生新一代个体
    for j=1:chromosome_size
        new_population(i,j)=population(idx,j);
    end
end

%是否精英选择
if elitism
    p = population_size-1;
else
    p = population_size;
end

for i=1:p
   for j=1:chromosome_size
       %如果精英选择,将population中前population_size-1个个体更新,最后一个最优个体保留
       population(i,j) = new_population(i,j);
   end
end
clear i;
clear j;
clear new_population;
clear first;
clear last;
clear idx;
clear mid;
end

3.5 交叉操作

%单点交叉操作
%population_size:种群大小
%chromosome_size:染色体长度
%cross_rate:交叉概率

function crossover(population_size,chromeosome_size,cross_rate)
global population;

%步长为2,遍历种群
for i=1:2:population_size
    if rand<cross_rate
        cross_position=round(rand*chromeosome_size);
        if cross_position==0||cross_position==1
            continue;
        end
        
        %对cross_popsition之后的二进制进行交换
        for j=cross_position:chromeosome_size
            temp=population(i,j);
            population(i,j)=population(i+1,j);
            population(i+1,j)=temp;
        end
    end
end
clear i;
clear j;
clear temp;
clear cross_position;
end

3.6 变异操作

%单点变异操作
%population_size:种群大小
%chromosome_size:染色体长度
%mutate_rate:变异概率

function mutation(population_size,chromosome_size,mutate_rate)
global population;

for i=1:population_size
    if rand<mutate_rate
        mutate_position=round(rand*chromosome_size);
        if mutate_position==0
            continue;
        end
        population(i,mutate_position)=1-population(i,mutate_position);
    end
end
clear i;
clear j;
clear mutate_position;
end

3.7 绘图

%打印算法迭代过程
%generation_size:迭代次数

function plotGA(generation_size)
global fitness_average;

x = 1:1:generation_size;
y = fitness_average;
plot(x,y)
end

3.8 遗传算法流程控制

%求函数最大值的遗产算法
%f(x) = x+10*sin(5*x)+7*cos(4*x), x∈[0,9]
%population_size:输入种群大小
%chromosome_size:输入染色体长度
%generation_size:输入迭代次数
%cross_rate:输入交叉概率
%mutate_rate:输入变异概率
%elitism:输入是否精英选择
%m:输出最佳个体
%n:输出最佳适应度
%p:输出最佳个体出现迭代次数
%q:输出最佳个体自变量值

function[m,n,p,q]=genetic_algorithm(population_size,chromosome_size,generation_size,cross_rate,mutate_rate,elitism)
global G ;              %当前迭代次数
global fitness_value;   %当前代适应度矩阵
global best_fitness;    %历代最佳适应值
global fitness_average; %历代平均适应值矩阵
global best_individual; %历代最佳个体
global best_generation; %最佳个体出现代
upper_bound = 9;        %自变量的区间上限
lower_bound = 0;        %自变量的区间下限

fitness_average=zeros(generation_size,1);
disp [genetic algorithm]
fitness_value=0.;
best_fitness=0.;
best_generation=0.;

%种群初始化
init(population_size,chromosome_size)

for G=1:generation_size
    %计算适应度
    fitness(population_size,chromosome_size);
    %对个体按照适应度大小排序
    rank(population_size,chromosome_size);
    %选择
    selection(population_size,chromosome_size,elitism);
    %交叉
    crossover(population_size,chromosome_size,cross_rate);
    %变异
    mutation(population_size,chromosome_size,mutate_rate);
end

%打印算法迭代过程
plotGA(generation_size);

m = best_individual;    %获得最佳个体
n = best_fitness;       %获得最佳适应度
p = best_generation;    %获得最佳个体出现时的迭代次数

%获得最佳个体变量值,对不同的优化目标,这里需要修改
q = 0.;
for j=1:chromosome_size
    if best_individual(j) == 1
            q = q+2^(j-1);  % 最佳个体变量二进制转十进制
    end 
end
q = lower_bound + q*(upper_bound-lower_bound)/(2^chromosome_size-1); % 解码

clear i;
clear j; 
end

3.9 主控程序

%设置遗传算法的参数,测试效果
%设定求解精度为小数点后4位

function main()
elitism = true;             % 选择精英操作
population_size = 100;      % 种群大小
chromosome_size = 17;       % 染色体长度
generation_size = 200;      % 最大迭代次数
cross_rate = 0.6;           % 交叉概率
mutate_rate = 0.01;         % 变异概率

[best_individual,best_fitness,iterations,x] = genetic_algorithm(population_size, chromosome_size, generation_size, cross_rate, mutate_rate,elitism);

disp 最优个体:
best_individual
disp 最优适应度:
best_fitness
disp 最优个体对应自变量值:
x
disp 达到最优结果的迭代次数:
iterations

clear;
end

3.10 结果

>> main()
[genetic algorithm]
最优个体:
best_individual =
     1     0     1     0     1     1     0     1     0     0     0     0     0     0     1     1     1
最优适应度:
best_fitness =
   24.6847
最优个体对应自变量值:
x =
    7.8875
达到最优结果的迭代次数:
iterations =
   129

在这里插入图片描述

四、参考文章

如何通俗易懂地解释遗传算法?有什么例子?

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值