用遗传算法求解Rastrigin函数的最小值问题

遗传算法介绍并附上Matlab代码 - 知乎 (zhihu.com)icon-default.png?t=N5K3https://zhuanlan.zhihu.com/p/417444795本文基于以上博主提供的遗传算法Matlab代码进行优化和改良

一、基本原理

1、Rastrigin函数:   

 f(x_1,x_{2})=20+x_{1}^{2}+x_{2}^{2}-10(cos2\pi x_{1}+cos2\pi x_{2})

-5<x_{i}<5 \; \; \; \; \; i=1,2

        Rastrigin函数是一个用于测试优化算法性能的基准函数,是1964年由Rastrigin提出的。该函数的公式表达式为:

f(x) = A * d + ∑(x^2 - A*cos(2π * x))

        其中,x是一个d维向量,A是一个常数,通常被设为10。该函数的最优解为f(x)=0,当且仅当x的每一个元素都等于0时。 Rastrigin函数通常被用于测试各种优化算法的性能,因为它具有很强的多峰性和高维特性,能够检验算法在高维空间中的收敛速度和准确性。

2、遗传算法

        遗传算法(Genetic Algorithm,GA)是一种基于自然进化原理的优化算法,经常用于解决复杂问题的优化和搜索。遗传算法的优势在于可以解决非线性连续优化问题、多模态优化问题和高维优化问题。遗传算法可以通过不断地演化与优胜劣汰的过程,产生最适合问题的解决方案。

        在遗传算法的演化过程中,通过模拟自然界中的进化过程,不断产生下一代种群,并从中筛选出适应性更强的个体,以此不断迭代,从而找到问题的最优解或者接近最优解。在这个迭代的过程中,遗传算法首先通过随机产生的初始种群,然后通过适应度函数的评价来评价个体的适应度,按照某种规则进行繁殖、交叉、变异等操作,产生新的个体,并且按照适应度的值对个体进行筛选、选择和淘汰,得到下一代种群。这样不断地迭代下去,直到种群逐渐收敛于最优解。

GA的基本操作包括:

        1. 初始化种群:随机生成初始的种群个体,每个个体包含若干个基因,通常使用二进制码或实数编码等方式表示。

        2. 适应度评价:根据问题所需要优化的指标对每个个体进行评价,通常使用目标函数的值来衡量个体的适应度。

        3. 选择:按照适应度大小来对种群个体进化的机会进行选择,轮盘赌算法、锦标赛选择、竞争选择等是常用的选择方法。

        4. 交叉:从选择的个体中随机选取一对个体,以一定的概率对其基因进行混合和交换,形成新的个体。

        5. 变异:对新个体的某些基因进行突变,引入新的变量或改变旧的变量,以增加个体的多样性。

        6. 判断是否终止进化:当达到限定的进化代数或解已接近最优解时,进化过程应终止。

        7. 生成最优解:在所有进化中得到最优适应度的个体就是最优解。

        通过上述操作,GA能自动寻找最优解,适用于广泛领域的问题求解,例如在工程中进行参数寻优。

二、方案和结果

        参考代码所求解问题只有一个自变量,现为求解Rastrigin函数的最小值问题两个自变量),在原来的基础上增加一个种群两个大小一样的种群独自进行交叉变异(互不影响),然后根据两个种群一起算出的适应度对两个种群分别进行筛选,多次调试运行发现出现的最优解为0,如表1:

表1

三、优缺点分析

        该遗传算法的确可以计算一些比较复杂的最优问题,减少计算量,但也只能尽量接近最优,无法保证一定是最优解,而且经常会出现过早收敛,在迭代至10代左右基本就锁定了一个区间,容易陷入局部最优,经过增加迭代次数发现该问题仍然存在,运行10次有将近7次会陷入局部最优解,取其中一个图形页面展示如下:

四、改进

        为解为解决局部最优的问题,尝试将排序方法由比例法改成线性排序法,增加如下代码,如图:

        但局部最优的问题仍然没得到解决,后决定采取锦标赛选择的方法选择个体,发现结果得到改善,每次迭代基本可以正确锁定最优解区间,如表2:

表2

五、总结与体会

      在本次仿真中通过尝试不同的方法来评估遗传算法的实用性。对于遗传算法的理解和应用,需要结合实际问题和数据,综合考虑其适用性和精度。虽然遗传算法不能完全解决所有问题,但对于那些精度要求不高的问题,遗传算法提供了一种高效而且易于实现的解决方案,大大减少了计算量和成本。从这个角度看,遗传算法是机器学习领域中非常有用的工具。然而,在实际应用中,需要结合具体问题和数据,综合考虑其适用范围和效果。通过进一步了解和掌握其他优化算法的原理和应用,可以更好地改进和优化现有的遗传算法,提高其精度和实用性。

六、代码

main.m

function main()
clear;
clc;
close all;
%种群大小
popsize_x1=100;
popsize_x2=100;
%二进制编码长度
chromlength=10;
%交叉概率
pc = 0.6;
%变异概率
pm = 0.001;
%初始种群
pop_x1 = initpop(popsize_x1,chromlength);
pop_x2 = initpop(popsize_x2,chromlength);
objvalue= cal_objvalue(pop_x1,pop_x2);%计算适应度值
fitvalue = objvalue;

for i = 1:100
    %选择操作
    newpop_x1 = selection(pop_x1,fitvalue);
    newpop_x2 = selection(pop_x2,fitvalue);
    %交叉操作
    newpop_x1 = crossover(newpop_x1,pc);
    newpop_x2 = crossover(newpop_x2,pc);
    %变异操作
    newpop_x1 = mutation(newpop_x1,pm);
    newpop_x2 = mutation(newpop_x2,pm);
    %更新种群
    pop_x1 = newpop_x1;
    pop_x2 = newpop_x2;
    %计算适应度值(函数值)
    objvalue = cal_objvalue(pop_x1,pop_x2);
    fitvalue = objvalue;
    %寻找最优解
    [bestindividual_x1,bestindividual_x2,bestfit] = best(pop_x1,pop_x2,fitvalue);
    
    best_x1 = binary2decimal(bestindividual_x1);%最优解x1
    best_x2 = binary2decimal(bestindividual_x2);%最优解x2
    
    x1_x1 = binary2decimal(newpop_x1);%二进制转十进制
    x1_x2 = binary2decimal(newpop_x2);%二进制转十进制
    
       
    if mod(i,10) == 0
        figure;
        [x1,x2] = meshgrid(-5:0.01:5);
        z = 20 + x1.^2 + x2.^2 - 10*(cos(2*pi*x1)+cos(2*pi*x2)); 
        contourf(x1,x2,z,20);
        hold on;        
        plot(x1_x1,x1_x2,'r*');
        title(['iteration times n=' num2str(i)]);
        %num2str把数值转换成字符串, 转换后可以使用fprintf或disp函数进行输出。
    end
end
    
fprintf('The best x1 is --->>%5.2f\n',best_x1);
fprintf('The best x2 is --->>%5.2f\n',best_x2);
fprintf('The best Y is --->>%5.2f\n',bestfit);

best.m

%求最优适应度函数
%输入变量:pop:种群,fitvalue:种群适应度
%输出变量:bestindividual:最佳个体,bestfit:最佳适应度值
function [bestindividual_x1,bestindividual_x2,bestfit] = best(pop_x1,pop_x2,fitvalue)
[px,~] = size(pop_x1);
bestindividual_x1 = pop_x1(1,:);
bestindividual_x2 = pop_x2(1,:);
bestfit = fitvalue(1);
for i = 2:px
    if fitvalue(i)>bestfit
        bestindividual_x1 = pop_x1(i,:);
        bestindividual_x2 = pop_x2(i,:);
        bestfit = fitvalue(i);
    end
end
bestfit = 1/bestfit;

binary2decimal.m

%二进制转化成十进制函数
%输入变量:
%二进制种群
%输出变量
%十进制数值
function pop2 = binary2decimal(pop)
[~,py]=size(pop);
for i = 1:py
    pop1(:,i) = 2.^(py-i).*pop(:,i);
end
%sum(.,2)对行求和,得到列向量
temp = sum(pop1,2);
pop2 = temp*10/1023-5;

cal_objvalue.m

%计算函数目标值
%输入变量:二进制数值
%输出变量:目标函数值
function [objvalue] = cal_objvalue(pop_x1,pop_x2)
x1 = binary2decimal(pop_x1);
x2 = binary2decimal(pop_x2);
%转化二进制数为x变量的变化域范围的数值
objvalue = 20 + x1.^2 + x2.^2 - 10*(cos(2*pi*x1)+cos(2*pi*x2));
objvalue = 1./objvalue;

crossver.m

%交叉变换
%输入变量:pop:二进制的父代种群数,pc:交叉的概率
%输出变量:newpop:交叉后的种群数
function [newpop] = crossover(pop,pc)
[px,py] = size(pop);
newpop = ones(size(pop));
for i = 1:2:px-1
    if(rand<pc)
        cpoint = round(rand*py); %round取整函数
        %下面两行代码意思是:i行的1:cpoint位和i+1行的cpoint+1:py位进行交换
        newpop(i,:) = [pop(i,1:cpoint),pop(i+1,cpoint+1:py)];
        newpop(i+1,:) = [pop(i+1,1:cpoint),pop(i,cpoint+1:py)];
    else
        newpop(i,:) = pop(i,:);
        newpop(i+1,:) = pop(i+1,:);
    end
end

initpop.m

%初始化种群大小
%输入变量:
%popsize:种群大小
%chromlength:染色体长度-->>转化的二进制长度
%输出变量:
%pop:种群
function pop=initpop(popsize,chromlength)
pop = round(rand(popsize,chromlength));
%rand(3,4)生成3行4列的0-1之间的随机数
% rand(3,4)
% 
% ans =
% 
%     0.8147    0.9134    0.2785    0.9649
%     0.9058    0.6324    0.5469    0.1576
%     0.1270    0.0975    0.9575    0.9706
%round就是四舍五入
% round(rand(3,4))=
% 1 1 0 1
% 1 1 1 0
% 0 0 1 1
%所以返回的种群就是每行是一个个体,列数是染色体长度

mutation.m

%关于编译
%函数说明
%输入变量:pop:二进制种群,pm:变异概率
%输出变量:newpop变异以后的种群
function [newpop] = mutation(pop,pm)
[px,py] = size(pop);
newpop = ones(size(pop));
for i = 1:px
    if(rand<pm)
        mpoint = round(rand*py);
        if mpoint <= 0
            mpoint = 1;
        end
        newpop(i,:) = pop(i,:);%为什么要专门开辟一个newpop,直接改原来的pop不行吗
        if newpop(i,mpoint) == 0
            newpop(i,mpoint) = 1;
        elseif newpop(i,mpoint) == 1
            newpop(i,mpoint) = 0;
        end
    else
        newpop(i,:) = pop(i,:);
    end
end

selection.m

%如何选择新的个体
%输入变量:pop二进制种群,fitvalue:适应度值
%输出变量:newpop选择以后的二进制种群
function [newpop] = selection(pop,fitvalue)
%构造轮盘
[px,~] = size(pop);

%线性排序增加的代码
% fitvalue_all = zeros(px,2);
% fitvalue_all(:,2) = fitvalue;
% for i = 1:px
%     fitvalue_all(i,1) = i;
% end
% fitvalue_all = sortrows(fitvalue_all,2);
% for i = 1:px
%     fitvalue_all(i,2) = i;
% end
% fitvalue_all = sortrows(fitvalue_all,1);
% fitvalue = fitvalue_all(:,2);

% %原代码
% % totalfit = sum(fitvalue);
% % p_fitvalue = fitvalue/totalfit;
% % p_fitvalue = cumsum(p_fitvalue);%概率求和排序
% % ms = sort(rand(px,1));%从小到大排列
% % fitin = 1;
% % newin = 1;
% % 
% % while newin<=px
% %     if(ms(newin))<p_fitvalue(fitin)
% %         newpop(newin,:)=pop(fitin,:);
% %         newin = newin+1;
% %     else
% %         fitin=fitin+1;
% %     end
% % end

%采用锦标赛选择方法的代码:
for i = 1:px
    x1 = randi([1 100]);
    x2 = randi([1 100]);
    if(fitvalue(x1) < fitvalue(x2)) 
         newpop(i,:)=pop(x2,:);
    else
         newpop(i,:)=pop(x1,:);
    end
end
end

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Rastrigin函数是一个多峰函数,因此使用遗传算法可以有效地搜索其最小值。以下是求解Rastrigin函数最小值遗传算法的Python实现: ```python import random import math # 定义Rastrigin函数 def rastrigin(x): return 10 * len(x) + sum([xi**2 - 10 * math.cos(2 * math.pi * xi) for xi in x]) # 定义遗传算法参数 POPULATION_SIZE = 100 GENE_LENGTH = 10 MUTATION_RATE = 0.1 GENERATIONS = 100 # 初始化种群 def init_population(population_size, gene_length): population = [] for i in range(population_size): individual = [random.uniform(-5.12, 5.12) for j in range(gene_length)] population.append(individual) return population # 计算适应度 def fitness(individual): return 1 / (rastrigin(individual) + 1) # 选择 def selection(population): fitness_sum = sum([fitness(individual) for individual in population]) probabilities = [fitness(individual) / fitness_sum for individual in population] selected = random.choices(population, weights=probabilities, k=len(population)) return selected # 交叉 def crossover(parent1, parent2): crossover_point = random.randint(1, len(parent1) - 1) child1 = parent1[:crossover_point] + parent2[crossover_point:] child2 = parent2[:crossover_point] + parent1[crossover_point:] return child1, child2 # 变异 def mutation(individual, mutation_rate): for i in range(len(individual)): if random.random() < mutation_rate: individual[i] = random.uniform(-5.12, 5.12) return individual # 主函数 def ga(): population = init_population(POPULATION_SIZE, GENE_LENGTH) for i in range(GENERATIONS): population = selection(population) new_population = [] while len(new_population) < POPULATION_SIZE: parent1, parent2 = random.sample(population, 2) child1, child2 = crossover(parent1, parent2) child1 = mutation(child1, MUTATION_RATE) child2 = mutation(child2, MUTATION_RATE) new_population.append(child1) new_population.append(child2) population = new_population best_individual = max(population, key=fitness) best_fitness = fitness(best_individual) print('Best individual:', best_individual) print('Best fitness:', best_fitness) # 运行遗传算法 ga() ``` 在上述代码中,我们首先定义了Rastrigin函数遗传算法的参数,然后实现了初始化种群、计算适应度、选择、交叉、变异等基本操作。在主函数中,我们按照遗传算法的流程进行迭代,最终输出找到的最优个体和适应度。运行该代码,即可求解Rastrigin函数最小值

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值